diff --git a/.editorconfig b/.editorconfig
index 93b7b093..765b35c4 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -22,3 +22,7 @@ indent_style = tab
[*.bat]
indent_style = tab
+
+[{Dockerfile,*.dockerfile}]
+indent_style = space
+indent_size = 4
diff --git a/.gitignore b/.gitignore
index cf9bfc18..dc83a16a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,7 +38,6 @@ htmlcov/
.tox/
.coverage
.cache
-nosetests.xml
coverage.xml
# Translations
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 20ec9e74..7d97c031 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,15 @@
+.only-default: &only-default
+ only:
+ - master
+ - branches
+ - merge_requests
+
stages:
- pre-commit
- gitlab
- test
- deploy
+- docker
include:
- template: Dependency-Scanning.gitlab-ci.yml
@@ -15,6 +22,7 @@ before_script:
- pip install wheel tox
pre-commit-check:
+ <<: *only-default
stage: pre-commit
image: python:3.6-buster
variables:
@@ -39,6 +47,7 @@ dependency_scanning:
- pip install wheel tox
test-3.7-core:
+ <<: *only-default
image: python:3.7-bullseye
script:
- tox -e py37-core
@@ -48,6 +57,7 @@ test-3.7-core:
cobertura: coverage.xml
test-3.8-core:
+ <<: *only-default
image: python:3.8-bullseye
script:
- tox -e py38-core
@@ -57,6 +67,7 @@ test-3.8-core:
cobertura: coverage.xml
test-3.9-core:
+ <<: *only-default
image: python:3.9-bullseye
script:
- tox -e py39-core
@@ -65,7 +76,18 @@ test-3.9-core:
reports:
cobertura: coverage.xml
+test-3.10-core:
+ <<: *only-default
+ image: python:3.10-bullseye
+ script:
+ - tox -e py310-core
+ artifacts:
+ when: always
+ reports:
+ cobertura: coverage.xml
+
test-3.7-all:
+ <<: *only-default
image: python:3.7-bullseye
script:
- tox -e py37-all
@@ -75,6 +97,7 @@ test-3.7-all:
cobertura: coverage.xml
test-3.8-all:
+ <<: *only-default
image: python:3.8-bullseye
script:
- tox -e py38-all
@@ -84,6 +107,7 @@ test-3.8-all:
cobertura: coverage.xml
test-3.9-all:
+ <<: *only-default
image: python:3.9-bullseye
script:
- tox -e py39-all
@@ -92,9 +116,19 @@ test-3.9-all:
reports:
cobertura: coverage.xml
+test-3.10-all:
+ <<: *only-default
+ image: python:3.10-bullseye
+ script:
+ - tox -e py310-all
+ artifacts:
+ when: always
+ reports:
+ cobertura: coverage.xml
+
deploy_production:
stage: deploy
- image: python:3.9-bullseye
+ image: python:3.10-bullseye
before_script:
- pip install twine wheel
@@ -105,3 +139,65 @@ deploy_production:
rules:
- if: $CI_COMMIT_TAG
+
+build-image:
+ before_script: []
+ image: docker:20.10.10
+ stage: docker
+ services:
+ - docker:20.10.10-dind
+ script: |
+ CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
+ IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_SHORT_SHA
+ CURRENT_TAG=$CI_REGISTRY_IMAGE/auth:$CI_COMMIT_TAG
+ MINOR_TAG=$CI_REGISTRY_IMAGE/auth:$(echo $CI_COMMIT_TAG | cut -d '.' -f 1-2)
+ MAJOR_TAG=$CI_REGISTRY_IMAGE/auth:$(echo $CI_COMMIT_TAG | cut -d '.' -f 1)
+ LATEST_TAG=$CI_REGISTRY_IMAGE/auth:latest
+
+ docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ docker build . -t $IMAGE_TAG -f docker/Dockerfile --build-arg AUTH_VERSION=$(echo $CI_COMMIT_TAG | cut -c 2-)
+ docker tag $IMAGE_TAG $CURRENT_TAG
+ docker tag $IMAGE_TAG $MINOR_TAG
+ docker tag $IMAGE_TAG $MAJOR_TAG
+ docker tag $IMAGE_TAG $LATEST_TAG
+ docker image push --all-tags $CI_REGISTRY_IMAGE/auth
+ rules:
+ - if: $CI_COMMIT_TAG
+
+build-image-dev:
+ before_script: []
+ image: docker:20.10.10
+ stage: docker
+ services:
+ - docker:20.10.10-dind
+ script: |
+ CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
+ IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_BRANCH-$CI_COMMIT_SHORT_SHA
+
+ docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ docker build . -t $IMAGE_TAG -f docker/Dockerfile --build-arg AUTH_PACKAGE=git+https://gitlab.com/allianceauth/allianceauth@$CI_COMMIT_BRANCH
+ docker push $IMAGE_TAG
+ rules:
+ - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == ""'
+ when: manual
+ - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME != ""'
+ when: never
+
+build-image-mr:
+ before_script: []
+ image: docker:20.10.10
+ stage: docker
+ services:
+ - docker:20.10.10-dind
+ script: |
+ CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
+ IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME-$CI_COMMIT_SHORT_SHA
+
+ docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ docker build . -t $IMAGE_TAG -f docker/Dockerfile --build-arg AUTH_PACKAGE=git+$CI_MERGE_REQUEST_SOURCE_PROJECT_URL@$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
+ docker push $IMAGE_TAG
+ rules:
+ - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
+ when: manual
+ - if: '$CI_PIPELINE_SOURCE != "merge_request_event"'
+ when: never
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 63a70cba..cf5af39a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -22,7 +22,13 @@ repos:
args: [ '--remove' ]
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
- rev: 2.3.5
+ rev: 2.3.54
hooks:
- id: editorconfig-checker
exclude: ^(LICENSE|allianceauth\/static\/css\/themes\/bootstrap-locals.less|allianceauth\/eveonline\/swagger.json|(.*.po)|(.*.mo))
+
+ - repo: https://github.com/asottile/pyupgrade
+ rev: v2.29.0
+ hooks:
+ - id: pyupgrade
+ args: [ --py37-plus ]
diff --git a/allianceauth/__init__.py b/allianceauth/__init__.py
index 0c8c5e16..8d04fd9d 100644
--- a/allianceauth/__init__.py
+++ b/allianceauth/__init__.py
@@ -1,8 +1,8 @@
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
-__version__ = '2.9.0'
+__version__ = '2.9.3'
__title__ = 'Alliance Auth'
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
-NAME = '%s v%s' % (__title__, __version__)
+NAME = f'{__title__} v{__version__}'
default_app_config = 'allianceauth.apps.AllianceAuthConfig'
diff --git a/allianceauth/analytics/migrations/0005_alter_analyticspath_ignore_path.py b/allianceauth/analytics/migrations/0005_alter_analyticspath_ignore_path.py
new file mode 100644
index 00000000..e36f41f3
--- /dev/null
+++ b/allianceauth/analytics/migrations/0005_alter_analyticspath_ignore_path.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.8 on 2021-10-17 16:26
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('analytics', '0004_auto_20211015_0502'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='analyticspath',
+ name='ignore_path',
+ field=models.CharField(default='/example/', help_text='Regex Expression, If matched no Analytics Page View is sent', max_length=254),
+ ),
+ ]
diff --git a/allianceauth/analytics/models.py b/allianceauth/analytics/models.py
index bc290162..29a0fd1d 100644
--- a/allianceauth/analytics/models.py
+++ b/allianceauth/analytics/models.py
@@ -16,7 +16,7 @@ class AnalyticsIdentifier(models.Model):
raise ValidationError('There is can be only one \
AnalyticsIdentifier instance')
self.pk = self.id = 1 # If this happens to be deleted and recreated, force it to be 1
- return super(AnalyticsIdentifier, self).save(*args, **kwargs)
+ return super().save(*args, **kwargs)
class AnalyticsPath(models.Model):
diff --git a/allianceauth/authentication/admin.py b/allianceauth/authentication/admin.py
index b39623cf..7dc50768 100644
--- a/allianceauth/authentication/admin.py
+++ b/allianceauth/authentication/admin.py
@@ -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
@@ -36,8 +36,8 @@ def make_service_hooks_update_groups_action(service):
for user in queryset: # queryset filtering doesn't work here?
service.update_groups(user)
- update_service_groups.__name__ = str('update_{}_groups'.format(slugify(service.name)))
- update_service_groups.short_description = "Sync groups for selected {} accounts".format(service.title)
+ update_service_groups.__name__ = str(f'update_{slugify(service.name)}_groups')
+ update_service_groups.short_description = f"Sync groups for selected {service.title} accounts"
return update_service_groups
@@ -54,8 +54,8 @@ def make_service_hooks_sync_nickname_action(service):
for user in queryset: # queryset filtering doesn't work here?
service.sync_nickname(user)
- sync_nickname.__name__ = str('sync_{}_nickname'.format(slugify(service.name)))
- sync_nickname.short_description = "Sync nicknames for selected {} accounts".format(service.title)
+ sync_nickname.__name__ = str(f'sync_{slugify(service.name)}_nickname')
+ sync_nickname.short_description = f"Sync nicknames for selected {service.title} accounts"
return sync_nickname
@@ -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(
- '{}
{}',
- corporation,
- user_obj.profile.main_character.alliance_name
- )
- else:
- result = corporation
- return result
+ result += f'
{user_obj.profile.main_character.alliance_name}'
+ elif user_obj.profile.main_character.faction_name:
+ result += f'
{user_obj.profile.main_character.faction_name}'
+ return format_html(result)
user_main_organization.short_description = 'Corporation / Alliance (Main)'
@@ -194,7 +190,7 @@ class MainCorporationsFilter(admin.SimpleListFilter):
.distinct()\
.order_by(Lower('corporation_name'))
return tuple(
- [(x['corporation_id'], x['corporation_name']) for x in qs]
+ (x['corporation_id'], x['corporation_name']) for x in qs
)
def queryset(self, request, qs):
@@ -228,7 +224,7 @@ class MainAllianceFilter(admin.SimpleListFilter):
.distinct()\
.order_by(Lower('alliance_name'))
return tuple(
- [(x['alliance_id'], x['alliance_name']) for x in qs]
+ (x['alliance_id'], x['alliance_name']) for x in qs
)
def queryset(self, request, qs):
@@ -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:
@@ -252,7 +280,7 @@ def update_main_character_model(modeladmin, request, queryset):
modeladmin.message_user(
request,
- 'Update from ESI started for {} characters'.format(tasks_count)
+ f'Update from ESI started for {tasks_count} characters'
)
@@ -342,6 +370,7 @@ class UserAdmin(BaseUserAdmin):
'groups',
MainCorporationsFilter,
MainAllianceFilter,
+ MainFactionFilter,
'is_active',
'date_joined',
'is_staff',
@@ -369,7 +398,7 @@ class UserAdmin(BaseUserAdmin):
_state.admin_order_field = 'profile__state'
def _groups(self, obj):
- my_groups = sorted([group.name for group in list(obj.groups.all())])
+ my_groups = sorted(group.name for group in list(obj.groups.all()))
return self._list_2_html_w_tooltips(
my_groups, AUTHENTICATION_ADMIN_USERS_MAX_GROUPS
)
@@ -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)
@@ -455,7 +489,7 @@ class StateAdmin(admin.ModelAdmin):
def has_delete_permission(self, request, obj=None):
if obj == get_guest_state():
return False
- return super(StateAdmin, self).has_delete_permission(request, obj=obj)
+ return super().has_delete_permission(request, obj=obj)
def get_fieldsets(self, request, obj=None):
if obj == get_guest_state():
@@ -464,7 +498,7 @@ class StateAdmin(admin.ModelAdmin):
'fields': ('permissions', 'priority'),
}),
)
- return super(StateAdmin, self).get_fieldsets(request, obj=obj)
+ return super().get_fieldsets(request, obj=obj)
class BaseOwnershipAdmin(admin.ModelAdmin):
@@ -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,
diff --git a/allianceauth/authentication/apps.py b/allianceauth/authentication/apps.py
index 10726de1..dd12e95d 100644
--- a/allianceauth/authentication/apps.py
+++ b/allianceauth/authentication/apps.py
@@ -7,6 +7,6 @@ class AuthenticationConfig(AppConfig):
label = 'authentication'
def ready(self):
- super(AuthenticationConfig, self).ready()
+ super().ready()
from allianceauth.authentication import checks, signals
register(Tags.security)(checks.check_login_scopes_setting)
diff --git a/allianceauth/authentication/backends.py b/allianceauth/authentication/backends.py
index d0cecf4a..526950d9 100644
--- a/allianceauth/authentication/backends.py
+++ b/allianceauth/authentication/backends.py
@@ -36,17 +36,17 @@ class StateBackend(ModelBackend):
try:
ownership = CharacterOwnership.objects.get(character__character_id=token.character_id)
if ownership.owner_hash == token.character_owner_hash:
- logger.debug('Authenticating {0} by ownership of character {1}'.format(ownership.user, token.character_name))
+ logger.debug(f'Authenticating {ownership.user} by ownership of character {token.character_name}')
return ownership.user
else:
- logger.debug('{0} has changed ownership. Creating new user account.'.format(token.character_name))
+ logger.debug(f'{token.character_name} has changed ownership. Creating new user account.')
ownership.delete()
return self.create_user(token)
except CharacterOwnership.DoesNotExist:
try:
# insecure legacy main check for pre-sso registration auth installs
profile = UserProfile.objects.get(main_character__character_id=token.character_id)
- logger.debug('Authenticating {0} by their main character {1} without active ownership.'.format(profile.user, profile.main_character))
+ logger.debug(f'Authenticating {profile.user} by their main character {profile.main_character} without active ownership.')
# attach an ownership
token.user = profile.user
CharacterOwnership.objects.create_by_token(token)
@@ -59,13 +59,13 @@ class StateBackend(ModelBackend):
user = records[0].user
token.user = user
co = CharacterOwnership.objects.create_by_token(token)
- logger.debug('Authenticating {0} by matching owner hash record of character {1}'.format(user, co.character))
+ logger.debug(f'Authenticating {user} by matching owner hash record of character {co.character}')
if not user.profile.main_character:
# set this as their main by default if they have none
user.profile.main_character = co.character
user.profile.save()
return user
- logger.debug('Unable to authenticate character {0}. Creating new user.'.format(token.character_name))
+ logger.debug(f'Unable to authenticate character {token.character_name}. Creating new user.')
return self.create_user(token)
def create_user(self, token):
@@ -77,7 +77,7 @@ class StateBackend(ModelBackend):
co = CharacterOwnership.objects.create_by_token(token) # assign ownership to this user
user.profile.main_character = co.character # assign main character as token character
user.profile.save()
- logger.debug('Created new user {0}'.format(user))
+ logger.debug(f'Created new user {user}')
return user
@staticmethod
@@ -87,10 +87,10 @@ class StateBackend(ModelBackend):
if User.objects.filter(username__startswith=name).exists():
u = User.objects.filter(username__startswith=name)
num = len(u)
- username = "%s_%s" % (name, num)
+ username = f"{name}_{num}"
while u.filter(username=username).exists():
num += 1
- username = "%s_%s" % (name, num)
+ username = f"{name}_{num}"
else:
username = name
return username
diff --git a/allianceauth/authentication/management/commands/checkmains.py b/allianceauth/authentication/management/commands/checkmains.py
index 6c4b7fb2..5605687b 100644
--- a/allianceauth/authentication/management/commands/checkmains.py
+++ b/allianceauth/authentication/management/commands/checkmains.py
@@ -11,10 +11,10 @@ class Command(BaseCommand):
if profiles.exists():
for profile in profiles:
self.stdout.write(self.style.ERROR(
- '{0} does not have an ownership. Resetting user {1} main character.'.format(profile.main_character,
+ '{} does not have an ownership. Resetting user {} main character.'.format(profile.main_character,
profile.user)))
profile.main_character = None
profile.save()
- self.stdout.write(self.style.WARNING('Reset {0} main characters.'.format(profiles.count())))
+ self.stdout.write(self.style.WARNING(f'Reset {profiles.count()} main characters.'))
else:
self.stdout.write(self.style.SUCCESS('All main characters have active ownership.'))
diff --git a/allianceauth/authentication/managers.py b/allianceauth/authentication/managers.py
index 3b2e8ed0..5959db96 100755
--- a/allianceauth/authentication/managers.py
+++ b/allianceauth/authentication/managers.py
@@ -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
@@ -49,7 +51,7 @@ class StateQuerySet(QuerySet):
for state in self:
for profile in state.userprofile_set.all():
profile.assign_state(state=self.model.objects.exclude(pk=state.pk).get_for_user(profile.user))
- super(StateQuerySet, self).delete()
+ super().delete()
class StateManager(Manager):
diff --git a/allianceauth/authentication/migrations/0001_initial.py b/allianceauth/authentication/migrations/0001_initial.py
index 3f9454e6..a7d3ff64 100644
--- a/allianceauth/authentication/migrations/0001_initial.py
+++ b/allianceauth/authentication/migrations/0001_initial.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-05 21:38
-from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
diff --git a/allianceauth/authentication/migrations/0002_auto_20160907_1914.py b/allianceauth/authentication/migrations/0002_auto_20160907_1914.py
index 8045e83e..f8ed8f1d 100644
--- a/allianceauth/authentication/migrations/0002_auto_20160907_1914.py
+++ b/allianceauth/authentication/migrations/0002_auto_20160907_1914.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-07 19:14
-from __future__ import unicode_literals
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0003_authservicesinfo_state.py b/allianceauth/authentication/migrations/0003_authservicesinfo_state.py
index 9ac14c83..4da327a4 100644
--- a/allianceauth/authentication/migrations/0003_authservicesinfo_state.py
+++ b/allianceauth/authentication/migrations/0003_authservicesinfo_state.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-09 20:29
-from __future__ import unicode_literals
from django.db import migrations, models
diff --git a/allianceauth/authentication/migrations/0004_create_permissions.py b/allianceauth/authentication/migrations/0004_create_permissions.py
index f63928fa..1f938d21 100644
--- a/allianceauth/authentication/migrations/0004_create_permissions.py
+++ b/allianceauth/authentication/migrations/0004_create_permissions.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-09 23:19
-from __future__ import unicode_literals
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0005_delete_perms.py b/allianceauth/authentication/migrations/0005_delete_perms.py
index a674c95c..e870b8cd 100644
--- a/allianceauth/authentication/migrations/0005_delete_perms.py
+++ b/allianceauth/authentication/migrations/0005_delete_perms.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-09 23:11
-from __future__ import unicode_literals
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0006_auto_20160910_0542.py b/allianceauth/authentication/migrations/0006_auto_20160910_0542.py
index 0bdd3498..03e1abb0 100644
--- a/allianceauth/authentication/migrations/0006_auto_20160910_0542.py
+++ b/allianceauth/authentication/migrations/0006_auto_20160910_0542.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-10 05:42
-from __future__ import unicode_literals
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0007_remove_authservicesinfo_is_blue.py b/allianceauth/authentication/migrations/0007_remove_authservicesinfo_is_blue.py
index 8150d6b8..4eac80bb 100644
--- a/allianceauth/authentication/migrations/0007_remove_authservicesinfo_is_blue.py
+++ b/allianceauth/authentication/migrations/0007_remove_authservicesinfo_is_blue.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-10 21:50
-from __future__ import unicode_literals
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0008_set_state.py b/allianceauth/authentication/migrations/0008_set_state.py
index 039409bd..7b55b97b 100644
--- a/allianceauth/authentication/migrations/0008_set_state.py
+++ b/allianceauth/authentication/migrations/0008_set_state.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-12 13:04
-from __future__ import unicode_literals
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0009_auto_20161021_0228.py b/allianceauth/authentication/migrations/0009_auto_20161021_0228.py
index 853a01db..588169dc 100644
--- a/allianceauth/authentication/migrations/0009_auto_20161021_0228.py
+++ b/allianceauth/authentication/migrations/0009_auto_20161021_0228.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.2 on 2016-10-21 02:28
-from __future__ import unicode_literals
from django.db import migrations, models
diff --git a/allianceauth/authentication/migrations/0010_only_one_authservicesinfo.py b/allianceauth/authentication/migrations/0010_only_one_authservicesinfo.py
index b08e5283..a88bb301 100644
--- a/allianceauth/authentication/migrations/0010_only_one_authservicesinfo.py
+++ b/allianceauth/authentication/migrations/0010_only_one_authservicesinfo.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2017-01-07 06:47
-from __future__ import unicode_literals
from django.db import migrations
@@ -9,7 +8,7 @@ def count_completed_fields(model):
def forward(apps, schema_editor):
# this ensures only one model exists per user
AuthServicesInfo = apps.get_model('authentication', 'AuthServicesInfo')
- users = set([a.user for a in AuthServicesInfo.objects.all()])
+ users = {a.user for a in AuthServicesInfo.objects.all()}
for u in users:
auths = AuthServicesInfo.objects.filter(user=u)
if auths.count() > 1:
diff --git a/allianceauth/authentication/migrations/0011_authservicesinfo_user_onetoonefield.py b/allianceauth/authentication/migrations/0011_authservicesinfo_user_onetoonefield.py
index ef694024..d12f2875 100644
--- a/allianceauth/authentication/migrations/0011_authservicesinfo_user_onetoonefield.py
+++ b/allianceauth/authentication/migrations/0011_authservicesinfo_user_onetoonefield.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2017-01-07 07:11
-from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
diff --git a/allianceauth/authentication/migrations/0012_remove_add_delete_authservicesinfo_permissions.py b/allianceauth/authentication/migrations/0012_remove_add_delete_authservicesinfo_permissions.py
index 208ea120..60fcc189 100644
--- a/allianceauth/authentication/migrations/0012_remove_add_delete_authservicesinfo_permissions.py
+++ b/allianceauth/authentication/migrations/0012_remove_add_delete_authservicesinfo_permissions.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.5 on 2017-01-12 00:59
-from __future__ import unicode_literals
from django.db import migrations, models
diff --git a/allianceauth/authentication/migrations/0013_service_modules.py b/allianceauth/authentication/migrations/0013_service_modules.py
index c7801dbd..f046905c 100644
--- a/allianceauth/authentication/migrations/0013_service_modules.py
+++ b/allianceauth/authentication/migrations/0013_service_modules.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.2 on 2016-12-11 23:14
-from __future__ import unicode_literals
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0014_fleetup_permission.py b/allianceauth/authentication/migrations/0014_fleetup_permission.py
index cfe60109..715d1b00 100644
--- a/allianceauth/authentication/migrations/0014_fleetup_permission.py
+++ b/allianceauth/authentication/migrations/0014_fleetup_permission.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.1 on 2016-09-09 23:19
-from __future__ import unicode_literals
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0015_user_profiles.py b/allianceauth/authentication/migrations/0015_user_profiles.py
index dccd1808..10ba691c 100644
--- a/allianceauth/authentication/migrations/0015_user_profiles.py
+++ b/allianceauth/authentication/migrations/0015_user_profiles.py
@@ -1,5 +1,4 @@
# Generated by Django 1.10.5 on 2017-03-22 23:09
-from __future__ import unicode_literals
import allianceauth.authentication.models
import django.db.models.deletion
diff --git a/allianceauth/authentication/migrations/0017_remove_fleetup_permission.py b/allianceauth/authentication/migrations/0017_remove_fleetup_permission.py
index f83b7a6a..38821f41 100644
--- a/allianceauth/authentication/migrations/0017_remove_fleetup_permission.py
+++ b/allianceauth/authentication/migrations/0017_remove_fleetup_permission.py
@@ -1,5 +1,3 @@
-from __future__ import unicode_literals
-
from django.db import migrations
diff --git a/allianceauth/authentication/migrations/0018_alter_state_name_length.py b/allianceauth/authentication/migrations/0018_alter_state_name_length.py
new file mode 100644
index 00000000..1b8096d6
--- /dev/null
+++ b/allianceauth/authentication/migrations/0018_alter_state_name_length.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.8 on 2021-10-20 05:22
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('authentication', '0017_remove_fleetup_permission'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='state',
+ name='name',
+ field=models.CharField(max_length=32, unique=True),
+ ),
+ ]
diff --git a/allianceauth/authentication/migrations/0018_state_member_factions.py b/allianceauth/authentication/migrations/0018_state_member_factions.py
new file mode 100644
index 00000000..b5c481a9
--- /dev/null
+++ b/allianceauth/authentication/migrations/0018_state_member_factions.py
@@ -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'),
+ ),
+ ]
diff --git a/allianceauth/authentication/migrations/0019_merge_20211026_0919.py b/allianceauth/authentication/migrations/0019_merge_20211026_0919.py
new file mode 100644
index 00000000..600d109a
--- /dev/null
+++ b/allianceauth/authentication/migrations/0019_merge_20211026_0919.py
@@ -0,0 +1,14 @@
+# Generated by Django 3.2.8 on 2021-10-26 09:19
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('authentication', '0018_alter_state_name_length'),
+ ('authentication', '0018_state_member_factions'),
+ ]
+
+ operations = [
+ ]
diff --git a/allianceauth/authentication/models.py b/allianceauth/authentication/models.py
index e95fe031..9dc2df64 100755
--- a/allianceauth/authentication/models.py
+++ b/allianceauth/authentication/models.py
@@ -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
@@ -12,13 +12,18 @@ logger = logging.getLogger(__name__)
class State(models.Model):
- name = models.CharField(max_length=20, unique=True)
+ name = models.CharField(max_length=32, unique=True)
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()
@@ -39,7 +44,7 @@ class State(models.Model):
with transaction.atomic():
for profile in self.userprofile_set.all():
profile.assign_state(state=State.objects.exclude(pk=self.pk).get_for_user(profile.user))
- super(State, self).delete(**kwargs)
+ super().delete(**kwargs)
def get_guest_state():
@@ -67,7 +72,7 @@ class UserProfile(models.Model):
if self.state != state:
self.state = state
if commit:
- logger.info('Updating {} state to {}'.format(self.user, self.state))
+ logger.info(f'Updating {self.user} state to {self.state}')
self.save(update_fields=['state'])
notify(
self.user,
@@ -102,7 +107,7 @@ class CharacterOwnership(models.Model):
objects = CharacterOwnershipManager()
def __str__(self):
- return "%s: %s" % (self.user, self.character)
+ return f"{self.user}: {self.character}"
class OwnershipRecord(models.Model):
@@ -115,4 +120,4 @@ class OwnershipRecord(models.Model):
ordering = ['-created']
def __str__(self):
- return "%s: %s on %s" % (self.user, self.character, self.created)
+ return f"{self.user}: {self.character} on {self.created}"
diff --git a/allianceauth/authentication/signals.py b/allianceauth/authentication/signals.py
index 335a1c00..f007c838 100644
--- a/allianceauth/authentication/signals.py
+++ b/allianceauth/authentication/signals.py
@@ -29,27 +29,32 @@ def trigger_state_check(state):
@receiver(m2m_changed, sender=State.member_characters.through)
def state_member_characters_changed(sender, instance, action, *args, **kwargs):
if action.startswith('post_'):
- logger.debug('State {} member characters changed. Re-evaluating membership.'.format(instance))
+ logger.debug(f'State {instance} member characters changed. Re-evaluating membership.')
trigger_state_check(instance)
@receiver(m2m_changed, sender=State.member_corporations.through)
def state_member_corporations_changed(sender, instance, action, *args, **kwargs):
if action.startswith('post_'):
- logger.debug('State {} member corporations changed. Re-evaluating membership.'.format(instance))
+ logger.debug(f'State {instance} member corporations changed. Re-evaluating membership.')
trigger_state_check(instance)
@receiver(m2m_changed, sender=State.member_alliances.through)
def state_member_alliances_changed(sender, instance, action, *args, **kwargs):
if action.startswith('post_'):
- logger.debug('State {} member alliances changed. Re-evaluating membership.'.format(instance))
+ 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):
- logger.debug('State {} saved. Re-evaluating membership.'.format(instance))
+ logger.debug(f'State {instance} saved. Re-evaluating membership.')
trigger_state_check(instance)
@@ -60,7 +65,7 @@ def reassess_on_profile_save(sender, instance, created, *args, **kwargs):
if not created:
update_fields = kwargs.pop('update_fields', []) or []
if 'state' not in update_fields:
- logger.debug('Profile for {} saved without state change. Re-evaluating state.'.format(instance.user))
+ logger.debug(f'Profile for {instance.user} saved without state change. Re-evaluating state.')
instance.assign_state()
@@ -68,14 +73,14 @@ def reassess_on_profile_save(sender, instance, created, *args, **kwargs):
def create_required_models(sender, instance, created, *args, **kwargs):
# ensure all users have a model
if created:
- logger.debug('User {} created. Creating default UserProfile.'.format(instance))
+ logger.debug(f'User {instance} created. Creating default UserProfile.')
UserProfile.objects.get_or_create(user=instance)
@receiver(post_save, sender=Token)
def record_character_ownership(sender, instance, created, *args, **kwargs):
if created:
- logger.debug('New token for {0} character {1} saved. Evaluating ownership.'.format(instance.user, instance.character_name))
+ logger.debug(f'New token for {instance.user} character {instance.character_name} saved. Evaluating ownership.')
if instance.user:
query = Q(owner_hash=instance.character_owner_hash) & Q(user=instance.user)
else:
@@ -84,13 +89,13 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
CharacterOwnership.objects.filter(character__character_id=instance.character_id).exclude(query).delete()
# create character if needed
if EveCharacter.objects.filter(character_id=instance.character_id).exists() is False:
- logger.debug('Token is for a new character. Creating model for {0} ({1})'.format(instance.character_name, instance.character_id))
+ logger.debug(f'Token is for a new character. Creating model for {instance.character_name} ({instance.character_id})')
EveCharacter.objects.create_character(instance.character_id)
char = EveCharacter.objects.get(character_id=instance.character_id)
# check if we need to create ownership
if instance.user and not CharacterOwnership.objects.filter(
character__character_id=instance.character_id).exists():
- logger.debug("Character {0} is not yet owned. Assigning ownership to {1}".format(instance.character_name, instance.user))
+ logger.debug(f"Character {instance.character_name} is not yet owned. Assigning ownership to {instance.user}")
CharacterOwnership.objects.update_or_create(character=char, defaults={'owner_hash': instance.character_owner_hash, 'user': instance.user})
@@ -98,7 +103,7 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
def validate_main_character(sender, instance, *args, **kwargs):
try:
if instance.user.profile.main_character == instance.character:
- logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
+ logger.info("Ownership of a main character {} has been revoked. Resetting {} main character.".format(
instance.character, instance.user))
# clear main character as user no longer owns them
instance.user.profile.main_character = None
@@ -111,7 +116,7 @@ def validate_main_character(sender, instance, *args, **kwargs):
@receiver(post_delete, sender=Token)
def validate_ownership(sender, instance, *args, **kwargs):
if not Token.objects.filter(character_owner_hash=instance.character_owner_hash).filter(refresh_token__isnull=False).exists():
- logger.info("No remaining tokens to validate ownership of character {0}. Revoking ownership.".format(instance.character_name))
+ logger.info(f"No remaining tokens to validate ownership of character {instance.character_name}. Revoking ownership.")
CharacterOwnership.objects.filter(owner_hash=instance.character_owner_hash).delete()
@@ -122,11 +127,11 @@ def assign_state_on_active_change(sender, instance, *args, **kwargs):
old_instance = User.objects.get(pk=instance.pk)
if old_instance.is_active != instance.is_active:
if instance.is_active:
- logger.debug("User {0} has been activated. Assigning state.".format(instance))
+ logger.debug(f"User {instance} has been activated. Assigning state.")
instance.profile.assign_state()
else:
logger.debug(
- "User {0} has been deactivated. Revoking state and assigning to guest state.".format(instance))
+ f"User {instance} has been deactivated. Revoking state and assigning to guest state.")
instance.profile.state = get_guest_state()
instance.profile.save(update_fields=['state'])
@@ -135,10 +140,10 @@ def assign_state_on_active_change(sender, instance, *args, **kwargs):
def check_state_on_character_update(sender, instance, *args, **kwargs):
# if this is a main character updating, check that user's state
try:
- logger.debug("Character {0} has been saved. Assessing owner's state for changes.".format(instance))
+ logger.debug(f"Character {instance} has been saved. Assessing owner's state for changes.")
instance.userprofile.assign_state()
except UserProfile.DoesNotExist:
- logger.debug("Character {0} is not a main character. No state assessment required.".format(instance))
+ logger.debug(f"Character {instance} is not a main character. No state assessment required.")
pass
@@ -148,7 +153,7 @@ def ownership_record_creation(sender, instance, created, *args, **kwargs):
records = OwnershipRecord.objects.filter(owner_hash=instance.owner_hash).filter(character=instance.character)
if records.exists():
if records[0].user == instance.user: # most recent record is sorted first
- logger.debug("Already have ownership record of {0} by user {1}".format(instance.character, instance.user))
+ logger.debug(f"Already have ownership record of {instance.character} by user {instance.user}")
return
- logger.info("Character {0} has a new owner {1}. Creating ownership record.".format(instance.character, instance.user))
+ logger.info(f"Character {instance.character} has a new owner {instance.user}. Creating ownership record.")
OwnershipRecord.objects.create(user=instance.user, character=instance.character, owner_hash=instance.owner_hash)
diff --git a/allianceauth/authentication/tasks.py b/allianceauth/authentication/tasks.py
index 3a9064f1..eaf3c59a 100644
--- a/allianceauth/authentication/tasks.py
+++ b/allianceauth/authentication/tasks.py
@@ -22,13 +22,13 @@ def check_character_ownership(owner_hash):
continue
except (KeyError, IncompleteResponseError):
# We can't validate the hash hasn't changed but also can't assume it has. Abort for now.
- logger.warning("Failed to validate owner hash of {0} due to problems contacting SSO servers.".format(
+ logger.warning("Failed to validate owner hash of {} due to problems contacting SSO servers.".format(
tokens[0].character_name))
break
if not t.character_owner_hash == old_hash:
logger.info(
- 'Character %s has changed ownership. Revoking %s tokens.' % (t.character_name, tokens.count()))
+ f'Character {t.character_name} has changed ownership. Revoking {tokens.count()} tokens.')
tokens.delete()
break
diff --git a/allianceauth/authentication/templates/authentication/dashboard.html b/allianceauth/authentication/templates/authentication/dashboard.html
index 49dfa762..4d2fc049 100644
--- a/allianceauth/authentication/templates/authentication/dashboard.html
+++ b/allianceauth/authentication/templates/authentication/dashboard.html
@@ -2,10 +2,10 @@
{% load static %}
{% load i18n %}
-{% block page_title %}{% trans "Dashboard" %}{% endblock %}
+{% block page_title %}{% translate "Dashboard" %}{% endblock %}
{% block content %}
-
+ |
+
{{ main.faction_name }} | +
-
+ {% if main.alliance_id %}
+
+ {% endif %}
+ {% if main.faction_id %}
+
+ {% endif %}
{{ main.character_name }}
{{ main.corporation_name }}
- {{ main.alliance_name }}
+ {% if main.alliance_id %}
+ {{ main.alliance_name }}
+ {% endif %}
+ {% if main.faction_id %}
+ {{ main.faction_name }}
+ {% endif %}
+ You're receiving this email because someone has entered this email address while registering for an account on {{ site.domain }} +
+ ++ If this was you, please click on the link below to confirm your email address: +
+ +
+ ++ This link will expire in {{ expiration_days }} day(s). +
+ ++ If this was not you, it is safe to ignore this email. +
diff --git a/allianceauth/authentication/templates/registration/password_reset_email.html b/allianceauth/authentication/templates/registration/password_reset_email.html index 6d66e74f..79d19b0e 100644 --- a/allianceauth/authentication/templates/registration/password_reset_email.html +++ b/allianceauth/authentication/templates/registration/password_reset_email.html @@ -2,13 +2,13 @@ {% blocktrans trimmed %}You're receiving this email because you requested a password reset for your user account.{% endblocktrans %} - {% trans "Please go to the following page and choose a new password:" %} + {% translate "Please go to the following page and choose a new password:" %} {% block reset_link %} {{domain}}{% url 'password_reset_confirm' uidb64=uid token=token %} {% endblock %} - {% trans "Your username, in case you've forgotten:" %} {{ user.get_username }} + {% translate "Your username, in case you've forgotten:" %} {{ user.get_username }} - {% trans "Thanks for using our site!" %} + {% translate "Thanks for using our site!" %} {% blocktrans %}Your IT Team{% endblocktrans %} diff --git a/allianceauth/authentication/templates/registration/registration_form.html b/allianceauth/authentication/templates/registration/registration_form.html index 12dbe6d2..5c35fe88 100644 --- a/allianceauth/authentication/templates/registration/registration_form.html +++ b/allianceauth/authentication/templates/registration/registration_form.html @@ -2,13 +2,13 @@ {% load bootstrap %} {% load i18n %} {% load static %} -{% block page_title %}Register{% endblock %} +{% block page_title %}{% translate "Register" %}{% endblock %} {% block middle_box_content %} {% endblock %} diff --git a/allianceauth/authentication/tests/test_admin.py b/allianceauth/authentication/tests/test_admin.py index 41d5a88b..e48f3623 100644 --- a/allianceauth/authentication/tests/test_admin.py +++ b/allianceauth/authentication/tests/test_admin.py @@ -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, @@ -36,7 +37,7 @@ from . import get_admin_change_view_url, get_admin_search_url MODULE_PATH = 'allianceauth.authentication.admin' -class MockRequest(object): +class MockRequest: def __init__(self, user=None): self.user = user @@ -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( @@ -188,7 +213,7 @@ def make_generic_search_request(ModelClass: type, search_term: str): c = Client() c.login(username='superuser', password='secret') return c.get( - '%s?q=%s' % (get_admin_search_url(ModelClass), quote(search_term)) + f'{get_admin_search_url(ModelClass)}?q={quote(search_term)}' ) @@ -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