Allow assigning factions to states.

This commit is contained in:
Adarnof 2021-10-26 09:16:28 +00:00 committed by Ariel Rin
parent 2da78f7793
commit 23849b9f42
19 changed files with 629 additions and 67 deletions

View File

@ -17,7 +17,7 @@ from allianceauth.authentication.models import State, get_guest_state,\
CharacterOwnership, UserProfile, OwnershipRecord
from allianceauth.hooks import get_hooks
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo,\
EveAllianceInfo
EveAllianceInfo, EveFactionInfo
from allianceauth.eveonline.tasks import update_character
from .app_settings import AUTHENTICATION_ADMIN_USERS_MAX_GROUPS, \
AUTHENTICATION_ADMIN_USERS_MAX_CHARS
@ -159,18 +159,14 @@ def user_main_organization(obj):
"""
user_obj = obj.user if hasattr(obj, 'user') else obj
if not user_obj.profile.main_character:
result = None
result = ''
else:
corporation = user_obj.profile.main_character.corporation_name
result = user_obj.profile.main_character.corporation_name
if user_obj.profile.main_character.alliance_id:
result = format_html(
'{}<br>{}',
corporation,
user_obj.profile.main_character.alliance_name
)
else:
result = corporation
return result
result += f'<br>{user_obj.profile.main_character.alliance_name}'
elif user_obj.profile.main_character.faction_name:
result += f'<br>{user_obj.profile.main_character.faction_name}'
return format_html(result)
user_main_organization.short_description = 'Corporation / Alliance (Main)'
@ -243,6 +239,38 @@ class MainAllianceFilter(admin.SimpleListFilter):
)
class MainFactionFilter(admin.SimpleListFilter):
"""Custom filter to filter on factions from mains only
works for both User objects and objects with `user` as FK to User
To be used for all user based admin lists
"""
title = 'faction'
parameter_name = 'main_faction_id__exact'
def lookups(self, request, model_admin):
qs = EveCharacter.objects\
.exclude(faction_id=None)\
.exclude(userprofile=None)\
.values('faction_id', 'faction_name')\
.distinct()\
.order_by(Lower('faction_name'))
return tuple(
(x['faction_id'], x['faction_name']) for x in qs
)
def queryset(self, request, qs):
if self.value() is None:
return qs.all()
else:
if qs.model == User:
return qs.filter(profile__main_character__faction_id=self.value())
else:
return qs.filter(
user__profile__main_character__faction_id=self.value()
)
def update_main_character_model(modeladmin, request, queryset):
tasks_count = 0
for obj in queryset:
@ -342,6 +370,7 @@ class UserAdmin(BaseUserAdmin):
'groups',
MainCorporationsFilter,
MainAllianceFilter,
MainFactionFilter,
'is_active',
'date_joined',
'is_staff',
@ -426,7 +455,8 @@ class StateAdmin(admin.ModelAdmin):
'public',
'member_characters',
'member_corporations',
'member_alliances'
'member_alliances',
'member_factions'
),
})
)
@ -434,6 +464,7 @@ class StateAdmin(admin.ModelAdmin):
'member_characters',
'member_corporations',
'member_alliances',
'member_factions',
'permissions'
]
@ -448,6 +479,9 @@ class StateAdmin(admin.ModelAdmin):
elif db_field.name == "member_alliances":
kwargs["queryset"] = EveAllianceInfo.objects.all()\
.order_by(Lower('alliance_name'))
elif db_field.name == "member_factions":
kwargs["queryset"] = EveFactionInfo.objects.all()\
.order_by(Lower('faction_name'))
elif db_field.name == "permissions":
kwargs["queryset"] = Permission.objects.select_related("content_type").all()
return super().formfield_for_manytomany(db_field, request, **kwargs)
@ -485,7 +519,8 @@ class BaseOwnershipAdmin(admin.ModelAdmin):
'user__username',
'character__character_name',
'character__corporation_name',
'character__alliance_name'
'character__alliance_name',
'character__faction_name'
)
list_filter = (
MainCorporationsFilter,

View File

@ -16,6 +16,8 @@ def available_states_query(character):
query |= Q(member_corporations__corporation_id=character.corporation_id)
if character.alliance_id:
query |= Q(member_alliances__alliance_id=character.alliance_id)
if character.faction_id:
query |= Q(member_factions__faction_id=character.faction_id)
return query

View File

@ -0,0 +1,19 @@
# Generated by Django 3.1.13 on 2021-10-12 20:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('eveonline', '0015_factions'),
('authentication', '0017_remove_fleetup_permission'),
]
operations = [
migrations.AddField(
model_name='state',
name='member_factions',
field=models.ManyToManyField(blank=True, help_text='Factions to whose members this state is available.', to='eveonline.EveFactionInfo'),
),
]

View File

@ -3,7 +3,7 @@ import logging
from django.contrib.auth.models import User, Permission
from django.db import models, transaction
from django.utils.translation import ugettext_lazy as _
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo, EveAllianceInfo
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo, EveAllianceInfo, EveFactionInfo
from allianceauth.notifications import notify
from .managers import CharacterOwnershipManager, StateManager
@ -16,9 +16,14 @@ class State(models.Model):
permissions = models.ManyToManyField(Permission, blank=True)
priority = models.IntegerField(unique=True, help_text="Users get assigned the state with the highest priority available to them.")
member_characters = models.ManyToManyField(EveCharacter, blank=True, help_text="Characters to which this state is available.")
member_corporations = models.ManyToManyField(EveCorporationInfo, blank=True, help_text="Corporations to whose members this state is available.")
member_alliances = models.ManyToManyField(EveAllianceInfo, blank=True, help_text="Alliances to whose members this state is available.")
member_characters = models.ManyToManyField(EveCharacter, blank=True,
help_text="Characters to which this state is available.")
member_corporations = models.ManyToManyField(EveCorporationInfo, blank=True,
help_text="Corporations to whose members this state is available.")
member_alliances = models.ManyToManyField(EveAllianceInfo, blank=True,
help_text="Alliances to whose members this state is available.")
member_factions = models.ManyToManyField(EveFactionInfo, blank=True,
help_text="Factions to whose members this state is available.")
public = models.BooleanField(default=False, help_text="Make this state available to any character.")
objects = StateManager()

View File

@ -46,6 +46,11 @@ def state_member_alliances_changed(sender, instance, action, *args, **kwargs):
logger.debug(f'State {instance} member alliances changed. Re-evaluating membership.')
trigger_state_check(instance)
@receiver(m2m_changed, sender=State.member_factions.through)
def state_member_factions_changed(sender, instance, action, *args, **kwargs):
if action.startswith('post_'):
logger.debug(f'State {instance} member factions changed. Re-evaluating membership.')
trigger_state_check(instance)
@receiver(post_save, sender=State)
def state_saved(sender, instance, *args, **kwargs):

View File

@ -60,6 +60,17 @@
<td class="text-center">{{ main.alliance_name }}</td>
<tr>
</table>
{% elif main.faction_id %}
<table class="table">
<tr>
<td class="text-center">
<img class="ra-avatar"src="{{ main.faction_logo_url_128 }}">
</td>
</tr>
<tr>
<td class="text-center">{{ main.faction_name }}</td>
<tr>
</table>
{% endif %}
</div>
</div>
@ -67,12 +78,22 @@
<p>
<img class="ra-avatar" src="{{ main.portrait_url_64 }}">
<img class="ra-avatar" src="{{ main.corporation_logo_url_64 }}">
<img class="ra-avatar" src="{{ main.alliance_logo_url_64 }}">
{% if main.alliance_id %}
<img class="ra-avatar" src="{{ main.alliance_logo_url_64 }}">
{% endif %}
{% if main.faction_id %}
<img class="ra-avatar" src="{{ main.faction_logo_url_64 }}">
{% endif %}
</p>
<p>
<strong>{{ main.character_name }}</strong><br>
{{ main.corporation_name }}<br>
{{ main.alliance_name }}
{% if main.alliance_id %}
{{ main.alliance_name }}<br>
{% endif %}
{% if main.faction_id %}
{{ main.faction_name }}
{% endif %}
</p>
</div>
{% endwith %}

View File

@ -9,7 +9,7 @@ from allianceauth.authentication.models import (
CharacterOwnership, State, OwnershipRecord
)
from allianceauth.eveonline.models import (
EveCharacter, EveCorporationInfo, EveAllianceInfo
EveCharacter, EveCorporationInfo, EveAllianceInfo, EveFactionInfo
)
from allianceauth.services.hooks import ServicesHook
from allianceauth.tests.auth_utils import AuthUtils
@ -20,6 +20,7 @@ from ..admin import (
StateAdmin,
MainCorporationsFilter,
MainAllianceFilter,
MainFactionFilter,
OwnershipRecordAdmin,
User,
UserAdmin,
@ -180,6 +181,30 @@ class TestCaseWithTestData(TestCase):
cls.user_3.is_superuser = True
cls.user_3.save()
# user 4 - corp and faction, no alliance
cls.character_4 = EveCharacter.objects.create(
character_id=4321,
character_name='Professor X',
corporation_id=5432,
corporation_name="Xavier's School for Gifted Youngsters",
corporation_ticker='MUTNT',
alliance_id = None,
faction_id=999,
faction_name='The X-Men',
)
cls.user_4 = User.objects.create_user(
cls.character_4.character_name.replace(' ', '_'),
'abc@example.com',
'password'
)
CharacterOwnership.objects.create(
character=cls.character_4,
owner_hash='x1' + cls.character_4.character_name,
user=cls.user_4
)
cls.user_4.profile.main_character = cls.character_4
cls.user_4.profile.save()
EveFactionInfo.objects.create(faction_id=999, faction_name='The X-Men')
def make_generic_search_request(ModelClass: type, search_term: str):
User.objects.create_superuser(
@ -315,9 +340,13 @@ class TestUserAdmin(TestCaseWithTestData):
self.assertEqual(user_main_organization(self.user_2), expected)
def test_user_main_organization_u3(self):
expected = None
expected = ''
self.assertEqual(user_main_organization(self.user_3), expected)
def test_user_main_organization_u4(self):
expected="Xavier's School for Gifted Youngsters<br>The X-Men"
self.assertEqual(user_main_organization(self.user_4), expected)
def test_characters_u1(self):
expected = 'Batman, Bruce Wayne'
result = self.modeladmin._characters(self.user_1)
@ -420,6 +449,7 @@ class TestUserAdmin(TestCaseWithTestData):
expected = [
(2002, 'Daily Planet'),
(2001, 'Wayne Technologies'),
(5432, "Xavier's School for Gifted Youngsters"),
]
self.assertEqual(filterspec.lookup_choices, expected)
@ -463,6 +493,34 @@ class TestUserAdmin(TestCaseWithTestData):
expected = [self.user_1]
self.assertSetEqual(set(queryset), set(expected))
def test_filter_main_factions(self):
class UserAdminTest(BaseUserAdmin):
list_filter = (MainFactionFilter,)
my_modeladmin = UserAdminTest(User, AdminSite())
# Make sure the lookups are correct
request = self.factory.get('/')
request.user = self.user_4
changelist = my_modeladmin.get_changelist_instance(request)
filters = changelist.get_filters(request)
filterspec = filters[0][0]
expected = [
(999, 'The X-Men'),
]
self.assertEqual(filterspec.lookup_choices, expected)
# Make sure the correct queryset is returned
request = self.factory.get(
'/',
{'main_faction_id__exact': self.character_4.faction_id}
)
request.user = self.user_4
changelist = my_modeladmin.get_changelist_instance(request)
queryset = changelist.get_queryset(request)
expected = [self.user_4]
self.assertSetEqual(set(queryset), set(expected))
def test_change_view_loads_normally(self):
User.objects.create_superuser(
username='superuser', password='secret', email='admin@example.com'

View File

@ -4,7 +4,7 @@ from django.contrib.auth.models import User
from django.test import TestCase
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo,\
EveAllianceInfo
EveAllianceInfo, EveFactionInfo
from allianceauth.tests.auth_utils import AuthUtils
from esi.errors import IncompleteResponseError
from esi.models import Token
@ -80,13 +80,15 @@ class StateTestCase(TestCase):
def setUpTestData(cls):
cls.user = AuthUtils.create_user('test_user', disconnect_signals=True)
AuthUtils.add_main_character(cls.user, 'Test Character', '1', corp_id='1', alliance_id='1',
corp_name='Test Corp', alliance_name='Test Alliance')
corp_name='Test Corp', alliance_name='Test Alliance', faction_id=1337,
faction_name='Permabanned')
cls.guest_state = get_guest_state()
cls.test_character = EveCharacter.objects.get(character_id='1')
cls.test_corporation = EveCorporationInfo.objects.create(corporation_id='1', corporation_name='Test Corp',
corporation_ticker='TEST', member_count=1)
cls.test_alliance = EveAllianceInfo.objects.create(alliance_id='1', alliance_name='Test Alliance',
alliance_ticker='TEST', executor_corp_id='1')
cls.test_faction = EveFactionInfo.objects.create(faction_id=1337, faction_name='Permabanned')
cls.member_state = State.objects.create(
name='Test Member',
priority=150,
@ -122,6 +124,15 @@ class StateTestCase(TestCase):
self._refresh_user()
self.assertEqual(self.user.profile.state, self.guest_state)
def test_state_assignment_on_faction_change(self):
self.member_state.member_factions.add(self.test_faction)
self._refresh_user()
self.assertEqual(self.user.profile.state, self.member_state)
self.member_state.member_factions.remove(self.test_faction)
self._refresh_user()
self.assertEqual(self.user.profile.state, self.guest_state)
def test_state_assignment_on_higher_priority_state_creation(self):
self.member_state.member_characters.add(self.test_character)
higher_state = State.objects.create(

View File

@ -6,6 +6,7 @@ from .providers import ObjectNotFound
from .models import EveAllianceInfo
from .models import EveCharacter
from .models import EveCorporationInfo
from .models import EveFactionInfo
class EveEntityExistsError(forms.ValidationError):
@ -34,6 +35,38 @@ class EveEntityForm(forms.ModelForm):
pass
def get_faction_choices():
# use a method to avoid making an ESI call when the app loads
# restrict to only those factions a player can join for faction warfare
player_factions = [x for x in EveFactionInfo.provider.get_all_factions() if x['militia_corporation_id']]
return [(x['faction_id'], x['name']) for x in player_factions]
class EveFactionForm(EveEntityForm):
id = forms.ChoiceField(
choices=get_faction_choices,
label="Name"
)
def clean_id(self):
try:
assert self.Meta.model.provider.get_faction(self.cleaned_data['id'])
except (AssertionError, ObjectNotFound):
raise EveEntityNotFoundError('faction', self.cleaned_data['id'])
if self.Meta.model.objects.filter(faction_id=self.cleaned_data['id']).exists():
raise EveEntityExistsError('faction', self.cleaned_data['id'])
return self.cleaned_data['id']
def save(self, commit=True):
faction = self.Meta.model.provider.get_faction(self.cleaned_data['id'])
return self.Meta.model.objects.create(faction_id=faction.id, faction_name=faction.name)
class Meta:
fields = ['id']
model = EveFactionInfo
class EveCharacterForm(EveEntityForm):
entity_type_name = 'character'
@ -94,6 +127,21 @@ class EveAllianceForm(EveEntityForm):
model = EveAllianceInfo
@admin.register(EveFactionInfo)
class EveFactionInfoAdmin(admin.ModelAdmin):
search_fields = ['faction_name']
list_display = ('faction_name',)
ordering = ('faction_name',)
def has_change_permission(self, request, obj=None):
return False
def get_form(self, request, obj=None, **kwargs):
if not obj or not obj.pk:
return EveFactionForm
return super().get_form(request, obj=obj, **kwargs)
@admin.register(EveCorporationInfo)
class EveCorporationInfoAdmin(admin.ModelAdmin):
search_fields = ['corporation_name']
@ -135,7 +183,7 @@ class EveCharacterAdmin(admin.ModelAdmin):
'character_ownership__user__username'
]
list_display = (
'character_name', 'corporation_name', 'alliance_name', 'user', 'main_character'
'character_name', 'corporation_name', 'alliance_name', 'faction_name', 'user', 'main_character'
)
list_select_related = (
'character_ownership', 'character_ownership__user__profile__main_character'
@ -143,6 +191,7 @@ class EveCharacterAdmin(admin.ModelAdmin):
list_filter = (
'corporation_name',
'alliance_name',
'faction_name',
(
'character_ownership__user__profile__main_character',
admin.RelatedOnlyFieldListFilter

View File

@ -27,6 +27,8 @@ class EveCharacterManager(models.Manager):
alliance_id=character.alliance.id,
alliance_name=character.alliance.name,
alliance_ticker=getattr(character.alliance, 'ticker', None),
faction_id=character.faction.id,
faction_name=character.faction.name
)
def update_character(self, character_id):

View File

@ -0,0 +1,35 @@
# Generated by Django 3.1.13 on 2021-10-12 01:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('eveonline', '0014_auto_20210105_1413'),
]
operations = [
migrations.CreateModel(
name='EveFactionInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('faction_id', models.PositiveIntegerField(db_index=True, unique=True)),
('faction_name', models.CharField(max_length=254, unique=True)),
],
),
migrations.AddField(
model_name='evecharacter',
name='faction_id',
field=models.PositiveIntegerField(blank=True, default=None, null=True),
),
migrations.AddField(
model_name='evecharacter',
name='faction_name',
field=models.CharField(blank=True, default='', max_length=254, null=True),
),
migrations.AddIndex(
model_name='evecharacter',
index=models.Index(fields=['faction_id'], name='eveonline_e_faction_d5274e_idx'),
),
]

View File

@ -10,6 +10,47 @@ from .evelinks import eveimageserver
_DEFAULT_IMAGE_SIZE = 32
class EveFactionInfo(models.Model):
faction_id = models.PositiveIntegerField(unique=True, db_index=True)
faction_name = models.CharField(max_length=254, unique=True)
provider = providers.provider
def __str__(self):
return self.faction_name
@staticmethod
def generic_logo_url(
faction_id: int, size: int = _DEFAULT_IMAGE_SIZE
) -> str:
"""image URL for the given faction ID"""
return eveimageserver.corporation_logo_url(faction_id, size)
def logo_url(self, size: int = _DEFAULT_IMAGE_SIZE) -> str:
"""image URL of this faction"""
return self.generic_logo_url(self.faction_id, size)
@property
def logo_url_32(self) -> str:
"""image URL for this faction"""
return self.logo_url(32)
@property
def logo_url_64(self) -> str:
"""image URL for this faction"""
return self.logo_url(64)
@property
def logo_url_128(self) -> str:
"""image URL for this faction"""
return self.logo_url(128)
@property
def logo_url_256(self) -> str:
"""image URL for this faction"""
return self.logo_url(256)
class EveAllianceInfo(models.Model):
alliance_id = models.PositiveIntegerField(unique=True)
alliance_name = models.CharField(max_length=254, unique=True)
@ -149,17 +190,20 @@ class EveCharacter(models.Model):
alliance_id = models.PositiveIntegerField(blank=True, null=True, default=None)
alliance_name = models.CharField(max_length=254, blank=True, null=True, default='')
alliance_ticker = models.CharField(max_length=5, blank=True, null=True, default='')
faction_id = models.PositiveIntegerField(blank=True, null=True, default=None)
faction_name = models.CharField(max_length=254, blank=True, null=True, default='')
objects = EveCharacterManager()
provider = EveCharacterProviderManager()
class Meta:
indexes = [
models.Index(fields=['corporation_id',]),
models.Index(fields=['alliance_id',]),
models.Index(fields=['corporation_name',]),
models.Index(fields=['alliance_name',]),
]
models.Index(fields=['corporation_id',]),
models.Index(fields=['alliance_id',]),
models.Index(fields=['corporation_name',]),
models.Index(fields=['alliance_name',]),
models.Index(fields=['faction_id',]),
]
@property
def alliance(self) -> Union[EveAllianceInfo, None]:
@ -181,6 +225,17 @@ class EveCharacter(models.Model):
"""
return EveCorporationInfo.objects.get(corporation_id=self.corporation_id)
@property
def faction(self) -> Union[EveFactionInfo, None]:
"""
Pseudo foreign key from faction_id to EveFactionInfo
:raises: EveFactionInfo.DoesNotExist
:return: EveFactionInfo
"""
if self.faction_id is None:
return None
return EveFactionInfo.objects.get(faction_id=self.faction_id)
def update_character(self, character: providers.Character = None):
if character is None:
character = self.provider.get_character(self.character_id)
@ -191,6 +246,8 @@ class EveCharacter(models.Model):
self.alliance_id = character.alliance.id
self.alliance_name = character.alliance.name
self.alliance_ticker = getattr(character.alliance, 'ticker', None)
self.faction_id = character.faction.id
self.faction_name = character.faction.name
self.save()
return self
@ -278,3 +335,31 @@ class EveCharacter(models.Model):
def alliance_logo_url_256(self) -> str:
"""image URL for alliance of this character or empty string"""
return self.alliance_logo_url(256)
def faction_logo_url(self, size=_DEFAULT_IMAGE_SIZE) -> str:
"""image URL for alliance of this character or empty string"""
if self.faction_id:
return EveFactionInfo.generic_logo_url(self.faction_id, size)
else:
return ''
@property
def faction_logo_url_32(self) -> str:
"""image URL for alliance of this character or empty string"""
return self.faction_logo_url(32)
@property
def faction_logo_url_64(self) -> str:
"""image URL for alliance of this character or empty string"""
return self.faction_logo_url(64)
@property
def faction_logo_url_128(self) -> str:
"""image URL for alliance of this character or empty string"""
return self.faction_logo_url(128)
@property
def faction_logo_url_256(self) -> str:
"""image URL for alliance of this character or empty string"""
return self.faction_logo_url(256)

View File

@ -22,6 +22,7 @@ get_corporations_corporation_id
get_characters_character_id
get_universe_types_type_id
post_character_affiliation
get_universe_factions
"""
@ -38,7 +39,8 @@ class ObjectNotFound(Exception):
class Entity:
def __init__(self, id=None, name=None):
def __init__(self, id=None, name=None, **kwargs):
super().__init__(**kwargs)
self.id = id
self.name = name
@ -55,15 +57,11 @@ class Entity:
return self.id == other.id
class Corporation(Entity):
def __init__(self, ticker=None, ceo_id=None, members=None, alliance_id=None, **kwargs):
class AllianceMixin:
def __init__(self, alliance_id=None, **kwargs):
super().__init__(**kwargs)
self.ticker = ticker
self.ceo_id = ceo_id
self.members = members
self.alliance_id = alliance_id
self._alliance = None
self._ceo = None
@property
def alliance(self):
@ -73,6 +71,30 @@ class Corporation(Entity):
return self._alliance
return Entity(None, None)
class FactionMixin:
def __init__(self, faction_id=None, **kwargs):
super().__init__(**kwargs)
self.faction_id = faction_id
self._faction = None
@property
def faction(self):
if self.faction_id:
if not self._faction:
self._faction = provider.get_faction(self.faction_id)
return self._faction
return Entity(None, None)
class Corporation(Entity, AllianceMixin, FactionMixin):
def __init__(self, ticker=None, ceo_id=None, members=None, **kwargs):
super().__init__(**kwargs)
self.ticker = ticker
self.ceo_id = ceo_id
self.members = members
self._ceo = None
@property
def ceo(self):
if not self._ceo:
@ -80,7 +102,7 @@ class Corporation(Entity):
return self._ceo
class Alliance(Entity):
class Alliance(Entity, FactionMixin):
def __init__(self, ticker=None, corp_ids=None, executor_corp_id=None, **kwargs):
super().__init__(**kwargs)
self.ticker = ticker
@ -106,13 +128,11 @@ class Alliance(Entity):
return Entity(None, None)
class Character(Entity):
def __init__(self, corp_id=None, alliance_id=None, **kwargs):
class Character(Entity, AllianceMixin, FactionMixin):
def __init__(self, corp_id=None, **kwargs):
super().__init__(**kwargs)
self.corp_id = corp_id
self.alliance_id = alliance_id
self._corp = None
self._alliance = None
@property
def corp(self):
@ -120,12 +140,6 @@ class Character(Entity):
self._corp = provider.get_corp(self.corp_id)
return self._corp
@property
def alliance(self):
if self.alliance_id:
return self.corp.alliance
return Entity(None, None)
class ItemType(Entity):
def __init__(self, **kwargs):
@ -179,6 +193,7 @@ class EveSwaggerProvider(EveProvider):
self._token = token
self.adapter = adapter or self
self._faction_list = None # what are the odds this will change? could cache forever!
@property
def client(self):
@ -201,6 +216,7 @@ class EveSwaggerProvider(EveProvider):
ticker=data['ticker'],
corp_ids=corps,
executor_corp_id=data['executor_corporation_id'] if 'executor_corporation_id' in data else None,
faction_id=data['faction_id'] if 'faction_id' in data else None,
)
return model
except HTTPNotFound:
@ -216,6 +232,7 @@ class EveSwaggerProvider(EveProvider):
ceo_id=data['ceo_id'],
members=data['member_count'],
alliance_id=data['alliance_id'] if 'alliance_id' in data else None,
faction_id=data['faction_id'] if 'faction_id' in data else None,
)
return model
except HTTPNotFound:
@ -231,11 +248,30 @@ class EveSwaggerProvider(EveProvider):
name=data['name'],
corp_id=affiliation['corporation_id'],
alliance_id=affiliation['alliance_id'] if 'alliance_id' in affiliation else None,
faction_id=affiliation['faction_id'] if 'faction_id' in affiliation else None,
)
return model
except (HTTPNotFound, HTTPUnprocessableEntity):
raise ObjectNotFound(character_id, 'character')
def get_all_factions(self):
if not self._faction_list:
self._faction_list = self.client.Universe.get_universe_factions().result()
return self._faction_list
def get_faction(self, faction_id):
faction_id=int(faction_id)
try:
if not self._faction_list:
_ = self.get_all_factions()
for f in self._faction_list:
if f['faction_id'] == faction_id:
return Entity(id=f['faction_id'], name=f['name'])
else:
raise KeyError()
except (HTTPNotFound, HTTPUnprocessableEntity, KeyError):
raise ObjectNotFound(faction_id, 'faction')
def get_itemtype(self, type_id):
try:
data = self.client.Universe.get_universe_types_type_id(type_id=type_id).result()

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@ from unittest.mock import Mock, patch
from django.test import TestCase
from ..models import (
EveCharacter, EveCorporationInfo, EveAllianceInfo
EveCharacter, EveCorporationInfo, EveAllianceInfo, EveFactionInfo
)
from ..providers import Alliance, Corporation, Character
from ..evelinks import eveimageserver
@ -126,6 +126,66 @@ class EveCharacterTestCase(TestCase):
self.assertIsNone(character.alliance)
def test_faction_prop(self):
"""
Test that the correct faction is returned by the alliance property
"""
character = EveCharacter.objects.create(
character_id=1234,
character_name='character.name',
corporation_id=2345,
corporation_name='character.corp.name',
corporation_ticker='cc1',
alliance_id=3456,
alliance_name='character.alliance.name',
faction_id=1337,
faction_name='character.faction.name'
)
expected = EveFactionInfo.objects.create(faction_id=1337, faction_name='faction.name')
incorrect = EveFactionInfo.objects.create(faction_id=8008, faction_name='faction.badname')
self.assertEqual(character.faction, expected)
self.assertNotEqual(character.faction, incorrect)
def test_faction_prop_exception(self):
"""
Check that an exception is raised when the expected
object is not in the database
"""
character = EveCharacter.objects.create(
character_id=1234,
character_name='character.name',
corporation_id=2345,
corporation_name='character.corp.name',
corporation_ticker='cc1',
alliance_id=3456,
alliance_name='character.alliance.name',
faction_id=1337,
faction_name='character.faction.name'
)
with self.assertRaises(EveFactionInfo.DoesNotExist):
character.faction
def test_faction_prop_none(self):
"""
Check that None is returned when the character has no alliance
"""
character = EveCharacter.objects.create(
character_id=1234,
character_name='character.name',
corporation_id=2345,
corporation_name='character.corp.name',
corporation_ticker='cc1',
alliance_id=None,
alliance_name=None,
faction_id=None,
faction_name=None,
)
self.assertIsNone(character.faction)
@patch('allianceauth.eveonline.providers.provider')
def test_update_character(self, mock_provider):
mock_provider.get_corp.return_value = Corporation(
@ -144,13 +204,17 @@ class EveCharacterTestCase(TestCase):
corporation_ticker='DC1',
alliance_id=3001,
alliance_name='Dummy Alliance 1',
faction_id=1337,
faction_name='Dummy Faction 1',
)
my_updated_character = Character(
name='Bruce X. Wayne',
corp_id=2002
corp_id=2002,
faction_id=None,
)
my_character.update_character(my_updated_character)
self.assertEqual(my_character.character_name, 'Bruce X. Wayne')
self.assertFalse(my_character.faction_id)
# todo: add test cases not yet covered, e.g. with alliance

View File

@ -10,6 +10,8 @@ from . import set_logger
from ..providers import (
ObjectNotFound,
Entity,
AllianceMixin,
FactionMixin,
Character,
Corporation,
Alliance,
@ -18,7 +20,6 @@ from ..providers import (
EveSwaggerProvider
)
MODULE_PATH = 'allianceauth.eveonline.providers'
SWAGGER_OLD_SPEC_PATH = os.path.join(os.path.dirname(
os.path.abspath(__file__)), 'swagger_old.json'
@ -80,6 +81,72 @@ class TestEntity(TestCase):
# bug: missing _neq_ in Equity to compliment _eq_
class TestAllianceMixin(TestCase):
@patch(MODULE_PATH + '.EveSwaggerProvider.get_alliance')
def test_alliance_defined(self, mock_provider_get_alliance):
my_alliance = Alliance(
id=3001,
name='Dummy Alliance',
ticker='Dummy',
corp_ids=[2001, 2002, 2003],
executor_corp_id=2001
)
mock_provider_get_alliance.return_value = my_alliance
x = AllianceMixin(alliance_id=3001)
self.assertEqual(
x.alliance,
my_alliance
)
self.assertEqual(
x.alliance,
my_alliance
)
# should fetch alliance once only
self.assertEqual(mock_provider_get_alliance.call_count, 1)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_alliance')
def test_alliance_not_defined(self, mock_provider_get_alliance):
mock_provider_get_alliance.return_value = None
x = AllianceMixin()
self.assertEqual(
x.alliance,
Entity(None, None)
)
self.assertEqual(mock_provider_get_alliance.call_count, 0)
class TestFactionMixin(TestCase):
@patch(MODULE_PATH + '.EveSwaggerProvider.get_faction')
def test_faction_defined(self, mock_provider_get_faction):
my_faction = Entity(id=1337, name='Permabanned')
mock_provider_get_faction.return_value = my_faction
x = FactionMixin(faction_id=3001)
self.assertEqual(
x.faction,
my_faction
)
self.assertEqual(
x.faction,
my_faction
)
# should fetch alliance once only
self.assertEqual(mock_provider_get_faction.call_count, 1)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_alliance')
def test_faction_not_defined(self, mock_provider_get_faction):
mock_provider_get_faction.return_value = None
x = FactionMixin()
self.assertEqual(
x.faction,
Entity(None, None)
)
self.assertEqual(mock_provider_get_faction.call_count, 0)
class TestCorporation(TestCase):
@patch(MODULE_PATH + '.EveSwaggerProvider.get_alliance')
@ -114,6 +181,7 @@ class TestCorporation(TestCase):
x.alliance,
Entity(None, None)
)
self.assertEqual(mock_provider_get_alliance.call_count, 0)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_character')
def test_ceo(self, mock_provider_get_character):
@ -142,6 +210,26 @@ class TestCorporation(TestCase):
# bug in ceo(): will try to fetch character even if ceo_id is None
@patch(MODULE_PATH + '.EveSwaggerProvider.get_faction')
def test_faction_defined(self, mock_provider_get_faction):
my_faction = Entity(id=1337, name='Permabanned')
mock_provider_get_faction.return_value = my_faction
# fetch from provider if not defined
x = Corporation(faction_id=1337)
self.assertEqual(x.faction, my_faction)
# return existing if defined
mock_provider_get_faction.return_value = None
self.assertEqual(x.faction, my_faction)
self.assertEqual(mock_provider_get_faction.call_count, 1)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_faction')
def test_faction_undefined(self, mock_provider_get_faction):
x = Corporation()
self.assertEqual(x.faction, Entity())
self.assertEqual(mock_provider_get_faction.call_count, 0)
class TestAlliance(TestCase):
@ -151,7 +239,8 @@ class TestAlliance(TestCase):
name='Dummy Alliance',
ticker='Dummy',
corp_ids=[2001, 2002, 2003],
executor_corp_id=2001
executor_corp_id=2001,
faction_id=1337
)
@staticmethod
@ -232,6 +321,25 @@ class TestAlliance(TestCase):
Entity(None, None),
)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_faction')
def test_faction_defined(self, mock_provider_get_faction):
my_faction = Entity(id=1337, name='Permabanned')
mock_provider_get_faction.return_value = my_faction
# fetch from provider if not defined
self.assertEqual(self.my_alliance.faction, my_faction)
# return existing if defined
mock_provider_get_faction.return_value = None
self.assertEqual(self.my_alliance.faction, my_faction)
self.assertEqual(mock_provider_get_faction.call_count, 1)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_faction')
def test_faction_undefined(self, mock_provider_get_faction):
self.my_alliance.faction_id = None
self.assertEqual(self.my_alliance.faction, Entity())
self.assertEqual(mock_provider_get_faction.call_count, 0)
class TestCharacter(TestCase):
@ -240,7 +348,8 @@ class TestCharacter(TestCase):
id=1001,
name='Bruce Wayne',
corp_id=2001,
alliance_id=3001
alliance_id=3001,
faction_id=1337,
)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_corp')
@ -282,12 +391,32 @@ class TestCharacter(TestCase):
self.assertEqual(self.my_character.alliance, my_alliance)
# should call the provider one time only
self.assertEqual(mock_provider_get_corp.call_count, 1)
self.assertEqual(mock_provider_get_alliance.call_count, 1)
def test_alliance_has_none(self):
@patch(MODULE_PATH + '.EveSwaggerProvider.get_alliance')
def test_alliance_has_none(self, mock_provider_get_alliance):
self.my_character.alliance_id = None
self.assertEqual(self.my_character.alliance, Entity(None, None))
self.assertEqual(mock_provider_get_alliance.call_count, 0)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_faction')
def test_faction_defined(self, mock_provider_get_faction):
my_faction = Entity(id=1337, name='Permabanned')
mock_provider_get_faction.return_value = my_faction
# fetch from provider if not defined
self.assertEqual(self.my_character.faction, my_faction)
# return existing if defined
mock_provider_get_faction.return_value = None
self.assertEqual(self.my_character.faction, my_faction)
self.assertEqual(mock_provider_get_faction.call_count, 1)
@patch(MODULE_PATH + '.EveSwaggerProvider.get_faction')
def test_faction_undefined(self, mock_provider_get_faction):
self.my_character.faction_id = None
self.assertEqual(self.my_character.faction, Entity())
self.assertEqual(mock_provider_get_faction.call_count, 0)
class TestItemType(TestCase):
@ -449,10 +578,10 @@ class TestEveSwaggerProvider(TestCase):
@patch(MODULE_PATH + '.esi_client_factory')
def test_get_alliance(self, mock_esi_client_factory):
mock_esi_client_factory.return_value\
mock_esi_client_factory.return_value \
.Alliance.get_alliances_alliance_id \
= TestEveSwaggerProvider.esi_get_alliances_alliance_id
mock_esi_client_factory.return_value\
mock_esi_client_factory.return_value \
.Alliance.get_alliances_alliance_id_corporations \
= TestEveSwaggerProvider.esi_get_alliances_alliance_id_corporations
@ -477,7 +606,7 @@ class TestEveSwaggerProvider(TestCase):
@patch(MODULE_PATH + '.esi_client_factory')
def test_get_corp(self, mock_esi_client_factory):
mock_esi_client_factory.return_value\
mock_esi_client_factory.return_value \
.Corporation.get_corporations_corporation_id \
= TestEveSwaggerProvider.esi_get_corporations_corporation_id
@ -503,10 +632,10 @@ class TestEveSwaggerProvider(TestCase):
@patch(MODULE_PATH + '.esi_client_factory')
def test_get_character(self, mock_esi_client_factory):
mock_esi_client_factory.return_value\
mock_esi_client_factory.return_value \
.Character.get_characters_character_id \
= TestEveSwaggerProvider.esi_get_characters_character_id
mock_esi_client_factory.return_value\
mock_esi_client_factory.return_value \
.Character.post_characters_affiliation \
= TestEveSwaggerProvider.esi_post_characters_affiliation
@ -530,7 +659,7 @@ class TestEveSwaggerProvider(TestCase):
@patch(MODULE_PATH + '.esi_client_factory')
def test_get_itemtype(self, mock_esi_client_factory):
mock_esi_client_factory.return_value\
mock_esi_client_factory.return_value \
.Universe.get_universe_types_type_id \
= TestEveSwaggerProvider.esi_get_universe_types_type_id
@ -556,7 +685,7 @@ class TestEveSwaggerProvider(TestCase):
@patch(MODULE_PATH + '.settings.DEBUG', False)
@patch('socket.socket')
def test_create_client_on_normal_startup_w_old_swagger_spec(
self, mock_socket
self, mock_socket
):
mock_socket.side_effect = Exception('Network blocked for testing')
my_provider = EveSwaggerProvider()
@ -572,7 +701,7 @@ class TestEveSwaggerProvider(TestCase):
@patch(MODULE_PATH + '.settings.DEBUG', False)
@patch(MODULE_PATH + '.esi_client_factory')
def test_dont_create_client_if_client_creation_fails_on_normal_startup(
self, mock_esi_client_factory
self, mock_esi_client_factory
):
mock_esi_client_factory.side_effect = RefResolutionError(cause='Test')
my_provider = EveSwaggerProvider()
@ -582,7 +711,7 @@ class TestEveSwaggerProvider(TestCase):
@patch(MODULE_PATH + '.settings.DEBUG', True)
@patch(MODULE_PATH + '.esi_client_factory')
def test_client_loads_on_demand(
self, mock_esi_client_factory
self, mock_esi_client_factory
):
mock_esi_client_factory.return_value = 'my_client'
my_provider = EveSwaggerProvider()
@ -597,7 +726,7 @@ class TestEveSwaggerProvider(TestCase):
def test_user_agent_header(self):
my_provider = EveSwaggerProvider()
my_client = my_provider.client
operation = my_client.Status.get_status()
operation = my_client.Universe.get_universe_factions()
self.assertEqual(
operation.future.request.headers['User-Agent'], 'allianceauth v1.0.0'
)

View File

@ -207,7 +207,7 @@ class TestColumnRendering(TestDataMixin, TestCase):
self.assertEqual(result, expected)
def test_user_main_organization_u3(self):
expected = None
expected = ''
result = user_main_organization(self.user_3.discord)
self.assertEqual(result, expected)

View File

@ -142,7 +142,7 @@ class AuthUtils:
@classmethod
def add_main_character(cls, user, name, character_id, corp_id=2345, corp_name='', corp_ticker='', alliance_id=None,
alliance_name=''):
alliance_name='', faction_id=None, faction_name=''):
if alliance_id:
try:
alliance_id = int(alliance_id)
@ -157,6 +157,8 @@ class AuthUtils:
corporation_ticker=corp_ticker,
alliance_id=alliance_id,
alliance_name=alliance_name,
faction_id=faction_id,
faction_name=faction_name
)
UserProfile.objects.update_or_create(user=user, defaults={'main_character': char})

View File

@ -42,6 +42,10 @@ This lets you select which Corporations the state is available to. Corporations
This lets you select which Alliances the state is available to. Alliances can be added by selecting the green plus icon.
### Member Factions
This lets you select which factions the state is available to. Factions can be added by selecting the green plus icon, and are limited to those which can be enlisted in for faction warfare.
## Determining a User's State
States are mutually exclusive, meaning a user can only be in one at a time.