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 %} -

{% trans "Dashboard" %}

+

{% translate "Dashboard" %}

{% if user.is_staff %} {% include 'allianceauth/admin-status/include.html' %} {% endif %} @@ -60,6 +60,17 @@ {{ main.alliance_name }} + {% elif main.faction_id %} + + + + + + + +
+ +
{{ main.faction_name }}
{% endif %} @@ -67,29 +78,39 @@

- + {% 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 %}

{% endwith %} {% else %} {% endif %}
{% trans 'Add Character' %} + title="Add Character">{% translate 'Add Character' %}
{% trans "Change Main" %} + title="Change Main Character">{% translate "Change Main" %}
@@ -98,7 +119,7 @@
-

{% trans "Group Memberships" %}

+

{% translate "Group Memberships" %}

@@ -118,7 +139,7 @@

- {% trans 'Characters' %} + {% translate 'Characters' %}

@@ -126,9 +147,9 @@ - {% trans 'Name' %} - {% trans 'Corp' %} - {% trans 'Alliance' %} + {% translate 'Name' %} + {% translate 'Corp' %} + {% translate 'Alliance' %} diff --git a/allianceauth/authentication/templates/public/base.html b/allianceauth/authentication/templates/public/base.html index 798c270f..9ca3fc9c 100644 --- a/allianceauth/authentication/templates/public/base.html +++ b/allianceauth/authentication/templates/public/base.html @@ -12,7 +12,7 @@ {% include 'allianceauth/icons.html' %} - {% block title %}{{ SITE_NAME }}{% endblock %} + {% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %} {% include 'bundles/bootstrap-css.html' %} {% include 'bundles/fontawesome.html' %} diff --git a/allianceauth/authentication/templates/public/login.html b/allianceauth/authentication/templates/public/login.html index 9a7921e7..5460b330 100644 --- a/allianceauth/authentication/templates/public/login.html +++ b/allianceauth/authentication/templates/public/login.html @@ -1,6 +1,10 @@ {% extends 'public/middle_box.html' %} + +{% load i18n %} {% load static %} -{% block page_title %}Login{% endblock %} + +{% block page_title %}{% translate "Login" %}{% endblock %} + {% block middle_box_content %} diff --git a/allianceauth/authentication/templates/public/middle_box.html b/allianceauth/authentication/templates/public/middle_box.html index 005e86bf..cb127c36 100644 --- a/allianceauth/authentication/templates/public/middle_box.html +++ b/allianceauth/authentication/templates/public/middle_box.html @@ -1,6 +1,5 @@ {% extends 'public/base.html' %} {% load static %} -{% block title %}Login{% endblock %} {% block content %}
{% if messages %} diff --git a/allianceauth/authentication/templates/public/register.html b/allianceauth/authentication/templates/public/register.html index 05bc685b..9ddeea9d 100644 --- a/allianceauth/authentication/templates/public/register.html +++ b/allianceauth/authentication/templates/public/register.html @@ -1,13 +1,17 @@ {% extends 'public/base.html' %} + {% load static %} {% load bootstrap %} {% load i18n %} -{% block page_title %}Registration{% endblock %} + +{% block page_title %}{% translate "Registration" %}{% endblock %} + {% block extra_include %} {% include 'bundles/bootstrap-css.html' %} {% include 'bundles/fontawesome.html' %} {% include 'bundles/bootstrap-js.html' %} {% endblock %} + {% block content %}
@@ -15,7 +19,7 @@
{% csrf_token %} {{ form|bootstrap }} - +
diff --git a/allianceauth/authentication/templates/registration/activate.html b/allianceauth/authentication/templates/registration/activate.html index c5635df5..b5b9bfc1 100644 --- a/allianceauth/authentication/templates/registration/activate.html +++ b/allianceauth/authentication/templates/registration/activate.html @@ -1,5 +1,5 @@ {% extends 'public/middle_box.html' %} {% load i18n %} {% block middle_box_content %} -
{% trans 'Invalid or expired activation link.' %}
+
{% translate 'Invalid or expired activation link.' %}
{% endblock %} diff --git a/allianceauth/authentication/templates/registration/activation_email.txt b/allianceauth/authentication/templates/registration/activation_email.txt index 028fbd2b..d303bf16 100644 --- a/allianceauth/authentication/templates/registration/activation_email.txt +++ b/allianceauth/authentication/templates/registration/activation_email.txt @@ -2,10 +2,6 @@ You're receiving this email because someone has entered this email address while If this was you, please click on the link below to confirm your email address: -
Confirm email address - -Link not working? Try copy/pasting this URL into your browser: - {{ scheme }}://{{ url }} This link will expire in {{ expiration_days }} day(s). diff --git a/allianceauth/authentication/templates/registration/activation_email_html.txt b/allianceauth/authentication/templates/registration/activation_email_html.txt new file mode 100644 index 00000000..907f2db9 --- /dev/null +++ b/allianceauth/authentication/templates/registration/activation_email_html.txt @@ -0,0 +1,19 @@ +

+ 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: +

+ +

+ Confirm 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
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) @@ -390,7 +419,7 @@ class TestUserAdmin(TestCaseWithTestData): # actions - @patch(MODULE_PATH + '.UserAdmin.message_user', auto_spec=True) + @patch(MODULE_PATH + '.UserAdmin.message_user', auto_spec=True, unsafe=True) @patch(MODULE_PATH + '.update_character') def test_action_update_main_character_model( self, mock_task, mock_message_user @@ -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' diff --git a/allianceauth/authentication/tests/test_backend.py b/allianceauth/authentication/tests/test_backend.py index 212cae46..ed984521 100644 --- a/allianceauth/authentication/tests/test_backend.py +++ b/allianceauth/authentication/tests/test_backend.py @@ -114,12 +114,12 @@ class TestAuthenticate(TestCase): def test_authenticate_main_character(self): t = Token(character_id=self.main_character.character_id, character_owner_hash='1') user = StateBackend().authenticate(token=t) - self.assertEquals(user, self.user) + self.assertEqual(user, self.user) def test_authenticate_alt_character(self): t = Token(character_id=self.alt_character.character_id, character_owner_hash='2') user = StateBackend().authenticate(token=t) - self.assertEquals(user, self.user) + self.assertEqual(user, self.user) def test_authenticate_unclaimed_character(self): t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='3') diff --git a/allianceauth/authentication/tests/test_models.py b/allianceauth/authentication/tests/test_models.py index 485a3413..4dca31ff 100644 --- a/allianceauth/authentication/tests/test_models.py +++ b/allianceauth/authentication/tests/test_models.py @@ -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 @@ -36,8 +36,8 @@ class CharacterOwnershipTestCase(TestCase): character_owner_hash='1', ) co = CharacterOwnership.objects.get(character=self.character) - self.assertEquals(co.user, self.user) - self.assertEquals(co.owner_hash, '1') + self.assertEqual(co.user, self.user) + self.assertEqual(co.owner_hash, '1') def test_transfer_ownership(self): Token.objects.create( @@ -54,7 +54,7 @@ class CharacterOwnershipTestCase(TestCase): ) co = CharacterOwnership.objects.get(character=self.character) self.assertNotEqual(self.user, co.user) - self.assertEquals(self.alt_user, co.user) + self.assertEqual(self.alt_user, co.user) def test_clear_main_character(self): Token.objects.create( @@ -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, @@ -98,29 +100,38 @@ class StateTestCase(TestCase): def test_state_assignment_on_character_change(self): self.member_state.member_characters.add(self.test_character) self._refresh_user() - self.assertEquals(self.user.profile.state, self.member_state) + self.assertEqual(self.user.profile.state, self.member_state) self.member_state.member_characters.remove(self.test_character) self._refresh_user() - self.assertEquals(self.user.profile.state, self.guest_state) + self.assertEqual(self.user.profile.state, self.guest_state) def test_state_assignment_on_corporation_change(self): self.member_state.member_corporations.add(self.test_corporation) self._refresh_user() - self.assertEquals(self.user.profile.state, self.member_state) + self.assertEqual(self.user.profile.state, self.member_state) self.member_state.member_corporations.remove(self.test_corporation) self._refresh_user() - self.assertEquals(self.user.profile.state, self.guest_state) + self.assertEqual(self.user.profile.state, self.guest_state) def test_state_assignment_on_alliance_addition(self): self.member_state.member_alliances.add(self.test_alliance) self._refresh_user() - self.assertEquals(self.user.profile.state, self.member_state) + self.assertEqual(self.user.profile.state, self.member_state) self.member_state.member_alliances.remove(self.test_alliance) self._refresh_user() - self.assertEquals(self.user.profile.state, self.guest_state) + 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) @@ -130,10 +141,10 @@ class StateTestCase(TestCase): ) higher_state.member_characters.add(self.test_character) self._refresh_user() - self.assertEquals(higher_state, self.user.profile.state) + self.assertEqual(higher_state, self.user.profile.state) higher_state.member_characters.clear() self._refresh_user() - self.assertEquals(self.member_state, self.user.profile.state) + self.assertEqual(self.member_state, self.user.profile.state) self.member_state.member_characters.clear() def test_state_assignment_on_lower_priority_state_creation(self): @@ -144,10 +155,10 @@ class StateTestCase(TestCase): ) lower_state.member_characters.add(self.test_character) self._refresh_user() - self.assertEquals(self.member_state, self.user.profile.state) + self.assertEqual(self.member_state, self.user.profile.state) lower_state.member_characters.clear() self._refresh_user() - self.assertEquals(self.member_state, self.user.profile.state) + self.assertEqual(self.member_state, self.user.profile.state) self.member_state.member_characters.clear() def test_state_assignment_on_priority_change(self): @@ -161,11 +172,11 @@ class StateTestCase(TestCase): lower_state.priority = 500 lower_state.save() self._refresh_user() - self.assertEquals(lower_state, self.user.profile.state) + self.assertEqual(lower_state, self.user.profile.state) lower_state.priority = 125 lower_state.save() self._refresh_user() - self.assertEquals(self.member_state, self.user.profile.state) + self.assertEqual(self.member_state, self.user.profile.state) def test_state_assignment_on_state_deletion(self): self.member_state.member_characters.add(self.test_character) @@ -175,11 +186,11 @@ class StateTestCase(TestCase): ) higher_state.member_characters.add(self.test_character) self._refresh_user() - self.assertEquals(higher_state, self.user.profile.state) + self.assertEqual(higher_state, self.user.profile.state) higher_state.delete() self.assertFalse(State.objects.filter(name='Higher State').count()) self._refresh_user() - self.assertEquals(self.member_state, self.user.profile.state) + self.assertEqual(self.member_state, self.user.profile.state) def test_state_assignment_on_public_toggle(self): self.member_state.member_characters.add(self.test_character) @@ -188,26 +199,26 @@ class StateTestCase(TestCase): priority=200, ) self._refresh_user() - self.assertEquals(self.member_state, self.user.profile.state) + self.assertEqual(self.member_state, self.user.profile.state) higher_state.public = True higher_state.save() self._refresh_user() - self.assertEquals(higher_state, self.user.profile.state) + self.assertEqual(higher_state, self.user.profile.state) higher_state.public = False higher_state.save() self._refresh_user() - self.assertEquals(self.member_state, self.user.profile.state) + self.assertEqual(self.member_state, self.user.profile.state) def test_state_assignment_on_active_changed(self): self.member_state.member_characters.add(self.test_character) self.user.is_active = False self.user.save() self._refresh_user() - self.assertEquals(self.user.profile.state, self.guest_state) + self.assertEqual(self.user.profile.state, self.guest_state) self.user.is_active = True self.user.save() self._refresh_user() - self.assertEquals(self.user.profile.state, self.member_state) + self.assertEqual(self.user.profile.state, self.member_state) class CharacterOwnershipCheckTestCase(TestCase): diff --git a/allianceauth/authentication/tests/test_templatetags.py b/allianceauth/authentication/tests/test_templatetags.py index 5409f840..50361724 100644 --- a/allianceauth/authentication/tests/test_templatetags.py +++ b/allianceauth/authentication/tests/test_templatetags.py @@ -1,6 +1,7 @@ from math import ceil from unittest.mock import patch +import requests import requests_mock from packaging.version import Version as Pep440Version @@ -169,11 +170,7 @@ class TestVersionTags(TestCase): # when result = _current_version_summary() # then - self.assertTrue(result['latest_major']) - self.assertTrue(result['latest_minor']) self.assertTrue(result['latest_patch']) - self.assertEqual(result['latest_major_version'], '2.0.0') - self.assertEqual(result['latest_minor_version'], '2.4.0') self.assertEqual(result['latest_patch_version'], '2.4.5') self.assertEqual(result['latest_beta_version'], '2.4.6a1') @@ -222,9 +219,7 @@ class TestLatestsVersion(TestCase): tags = create_tags_list( ['2.1.1', '2.1.0', '2.0.0', '2.1.1a1', '1.1.1', '1.1.0', '1.0.0'] ) - major, minor, patch, beta = _latests_versions(tags) - self.assertEqual(major, Pep440Version('2.0.0')) - self.assertEqual(minor, Pep440Version('2.1.0')) + patch, beta = _latests_versions(tags) self.assertEqual(patch, Pep440Version('2.1.1')) self.assertEqual(beta, Pep440Version('2.1.1a1')) @@ -233,9 +228,7 @@ class TestLatestsVersion(TestCase): tags = create_tags_list( ['2.1.2', '2.1.1', '2.0.1', '2.1.1a1', '1.1.1', '1.1.0', '1.0.0'] ) - major, minor, patch, beta = _latests_versions(tags) - self.assertEqual(major, Pep440Version('2.0.1')) - self.assertEqual(minor, Pep440Version('2.1.1')) + patch, beta = _latests_versions(tags) self.assertEqual(patch, Pep440Version('2.1.2')) self.assertEqual(beta, Pep440Version('2.1.1a1')) @@ -244,9 +237,7 @@ class TestLatestsVersion(TestCase): tags = create_tags_list( ['2.1.1', '2.1.0', '2.0.0', '2.1.1a1', 'invalid'] ) - major, minor, patch, beta = _latests_versions(tags) - self.assertEqual(major, Pep440Version('2.0.0')) - self.assertEqual(minor, Pep440Version('2.1.0')) + patch, beta = _latests_versions(tags) self.assertEqual(patch, Pep440Version('2.1.1')) self.assertEqual(beta, Pep440Version('2.1.1a1')) @@ -317,3 +308,25 @@ class TestFetchListFromGitlab(TestCase): result = _fetch_list_from_gitlab(self.url, max_pages=max_pages) self.assertEqual(result, GITHUB_TAGS[:4]) self.assertEqual(requests_mocker.call_count, max_pages) + + @requests_mock.mock() + @patch(MODULE_PATH + '.admin_status.logger') + def test_should_not_raise_any_exception_from_github_request_but_log_as_warning( + self, requests_mocker, mock_logger + ): + for my_exception in [ + requests.exceptions.ConnectionError, + requests.exceptions.HTTPError, + requests.exceptions.URLRequired, + requests.exceptions.TooManyRedirects, + requests.exceptions.ConnectTimeout, + requests.exceptions.Timeout, + + ]: + requests_mocker.get(self.url, exc=my_exception) + try: + result = _fetch_list_from_gitlab(self.url) + except Exception as ex: + self.fail(f"Unexpected exception raised: {ex}") + self.assertTrue(mock_logger.warning.called) + self.assertListEqual(result, []) diff --git a/allianceauth/authentication/views.py b/allianceauth/authentication/views.py index b173ec9f..779f9a1c 100644 --- a/allianceauth/authentication/views.py +++ b/allianceauth/authentication/views.py @@ -6,8 +6,10 @@ from django.contrib.auth import login, authenticate from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.core import signing +from django.core.mail import EmailMultiAlternatives from django.http import JsonResponse from django.shortcuts import redirect, render +from django.template.loader import render_to_string from django.urls import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ @@ -63,7 +65,7 @@ def dashboard(request): @login_required @token_required(scopes=settings.LOGIN_TOKEN_SCOPES) def main_character_change(request, token): - logger.debug("main_character_change called by user %s for character %s" % (request.user, token.character_name)) + logger.debug(f"main_character_change called by user {request.user} for character {token.character_name}") try: co = CharacterOwnership.objects.get(character__character_id=token.character_id, user=request.user) except CharacterOwnership.DoesNotExist: @@ -137,9 +139,52 @@ class RegistrationView(BaseRegistrationView): form_class = RegistrationForm template_name = "public/register.html" email_body_template = "registration/activation_email.txt" + email_body_template_html = "registration/activation_email_html.txt" email_subject_template = "registration/activation_email_subject.txt" success_url = reverse_lazy('registration_complete') + def send_activation_email(self, user): + """ + Implement our own way to send a mail to make sure we + send a RFC conform multipart email + :param user: + :type user: + """ + + activation_key = self.get_activation_key(user) + context = self.get_email_context(activation_key) + context["user"] = user + + # email subject + subject = render_to_string( + template_name=self.email_subject_template, + context=context, + request=self.request, + ) + subject = "".join(subject.splitlines()) + + # plaintext email body part + message = render_to_string( + template_name=self.email_body_template, + context=context, + request=self.request, + ) + + # html email body part + message_html = render_to_string( + template_name=self.email_body_template_html, + context=context, + request=self.request, + ) + + # send it + user.email_user( + subject, + message, + settings.DEFAULT_FROM_EMAIL, + **{'html_message': message_html}, + ) + def get_success_url(self, user): if not getattr(settings, 'REGISTRATION_VERIFY_EMAIL', True): return reverse_lazy('authentication:dashboard') @@ -154,7 +199,7 @@ class RegistrationView(BaseRegistrationView): if not getattr(settings, 'REGISTRATION_VERIFY_EMAIL', True): # Keep the request so the user can be automagically logged in. setattr(self, 'request', request) - return super(RegistrationView, self).dispatch(request, *args, **kwargs) + return super().dispatch(request, *args, **kwargs) def register(self, form): user = User.objects.get(pk=self.request.session.get('registration_uid')) @@ -173,7 +218,7 @@ class RegistrationView(BaseRegistrationView): return signing.dumps(obj=[getattr(user, User.USERNAME_FIELD), user.email], salt=REGISTRATION_SALT) def get_email_context(self, activation_key): - context = super(RegistrationView, self).get_email_context(activation_key) + context = super().get_email_context(activation_key) context['url'] = context['site'].domain + reverse('registration_activate', args=[activation_key]) return context diff --git a/allianceauth/bin/allianceauth.py b/allianceauth/bin/allianceauth.py index ae54e1fd..5d64601f 100644 --- a/allianceauth/bin/allianceauth.py +++ b/allianceauth/bin/allianceauth.py @@ -41,7 +41,7 @@ def create_project(parser, options, args): # Call the command with extra context call_command(StartProject(), *args, **command_options) - print("Success! %(project_name)s has been created." % {'project_name': args[0]}) # noqa + print(f"Success! {args[0]} has been created.") # noqa def update_settings(parser, options, args): @@ -69,10 +69,10 @@ def update_settings(parser, options, args): template_settings_path = os.path.join(template_path, 'project_name/settings/base.py') # overwrite the local project's base settings - with open(template_settings_path, 'r') as template, open(settings_path, 'w') as target: + with open(template_settings_path) as template, open(settings_path, 'w') as target: target.write(template.read()) - print("Successfully updated %(project_name)s settings." % {'project_name': project_name}) + print(f"Successfully updated {project_name} settings.") COMMANDS = { diff --git a/allianceauth/corputils/managers.py b/allianceauth/corputils/managers.py index 8607b613..87b2ffdd 100644 --- a/allianceauth/corputils/managers.py +++ b/allianceauth/corputils/managers.py @@ -29,7 +29,7 @@ class CorpStatsQuerySet(models.QuerySet): if user.has_perm('corputils.view_state_corpstats'): queries.append(models.Q(corp__in=user.profile.state.member_corporations.all())) queries.append(models.Q(corp__alliance__in=user.profile.state.member_alliances.all())) - logger.debug('%s queries for user %s visible corpstats.' % (len(queries), user)) + logger.debug(f'{len(queries)} queries for user {user} visible corpstats.') # filter based on queries query = queries.pop() for q in queries: diff --git a/allianceauth/corputils/migrations/0001_initial.py b/allianceauth/corputils/migrations/0001_initial.py index 7da61bdd..49d71b75 100644 --- a/allianceauth/corputils/migrations/0001_initial.py +++ b/allianceauth/corputils/migrations/0001_initial.py @@ -1,5 +1,4 @@ # Generated by Django 1.10.1 on 2016-12-14 21:36 -from __future__ import unicode_literals from django.db import migrations, models import django.db.models.deletion diff --git a/allianceauth/corputils/migrations/0002_migrate_permissions.py b/allianceauth/corputils/migrations/0002_migrate_permissions.py index 2c0e462d..fce155e4 100644 --- a/allianceauth/corputils/migrations/0002_migrate_permissions.py +++ b/allianceauth/corputils/migrations/0002_migrate_permissions.py @@ -1,5 +1,4 @@ # Generated by Django 1.10.1 on 2016-12-14 21:48 -from __future__ import unicode_literals from django.db import migrations diff --git a/allianceauth/corputils/migrations/0003_granular_permissions.py b/allianceauth/corputils/migrations/0003_granular_permissions.py index 8256106d..446a0c48 100644 --- a/allianceauth/corputils/migrations/0003_granular_permissions.py +++ b/allianceauth/corputils/migrations/0003_granular_permissions.py @@ -1,5 +1,4 @@ # Generated by Django 1.10.5 on 2017-03-22 23:35 -from __future__ import unicode_literals from django.db import migrations diff --git a/allianceauth/corputils/migrations/0004_member_models.py b/allianceauth/corputils/migrations/0004_member_models.py index 83b6b546..b8e2e291 100644 --- a/allianceauth/corputils/migrations/0004_member_models.py +++ b/allianceauth/corputils/migrations/0004_member_models.py @@ -1,5 +1,4 @@ # Generated by Django 1.10.5 on 2017-03-26 20:13 -from __future__ import unicode_literals from django.db import migrations, models import django.db.models.deletion @@ -48,7 +47,7 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name='corpmember', - unique_together=set([('corpstats', 'character_id')]), + unique_together={('corpstats', 'character_id')}, ), migrations.RunPython(convert_json_to_members, convert_members_to_json), migrations.RemoveField( diff --git a/allianceauth/corputils/migrations/0005_cleanup_permissions.py b/allianceauth/corputils/migrations/0005_cleanup_permissions.py index 27f8d73f..f73c37ca 100644 --- a/allianceauth/corputils/migrations/0005_cleanup_permissions.py +++ b/allianceauth/corputils/migrations/0005_cleanup_permissions.py @@ -1,5 +1,4 @@ # Generated by Django 1.11.2 on 2017-06-10 15:34 -from __future__ import unicode_literals from django.db import migrations diff --git a/allianceauth/corputils/models.py b/allianceauth/corputils/models.py index 8d7c6628..7ac03b7e 100644 --- a/allianceauth/corputils/models.py +++ b/allianceauth/corputils/models.py @@ -43,7 +43,7 @@ class CorpStats(models.Model): objects = CorpStatsManager() def __str__(self): - return "%s for %s" % (self.__class__.__name__, self.corp) + return f"{self.__class__.__name__} for {self.corp}" def update(self): try: @@ -73,7 +73,7 @@ class CorpStats(models.Model): self.save() except TokenError as e: - logger.warning("%s failed to update: %s" % (self, e)) + logger.warning(f"{self} failed to update: {e}") if self.token.user: notify( self.token.user, "%s failed to update with your ESI token." % self, @@ -81,9 +81,9 @@ class CorpStats(models.Model): level="error") self.delete() except HTTPForbidden as e: - logger.warning("%s failed to update: %s" % (self, e)) + logger.warning(f"{self} failed to update: {e}") if self.token.user: - notify(self.token.user, "%s failed to update with your ESI token." % self, message="%s: %s" % (e.status_code, e.message), level="error") + notify(self.token.user, "%s failed to update with your ESI token." % self, message=f"{e.status_code}: {e.message}", level="error") self.delete() except AssertionError: logger.warning("%s token character no longer in corp." % self) @@ -99,7 +99,7 @@ class CorpStats(models.Model): @property def user_count(self): - return len(set([m.main_character for m in self.members.all() if m.main_character])) + return len({m.main_character for m in self.members.all() if m.main_character}) @property def registered_member_count(self): diff --git a/allianceauth/corputils/templates/corputils/base.html b/allianceauth/corputils/templates/corputils/base.html index d23bd86e..17300d94 100644 --- a/allianceauth/corputils/templates/corputils/base.html +++ b/allianceauth/corputils/templates/corputils/base.html @@ -1,15 +1,15 @@ {% extends 'allianceauth/base.html' %} {% load i18n %} -{% block page_title %}{% trans "Corporation Member Data" %}{% endblock %} +{% block page_title %}{% translate "Corporation Member Data" %}{% endblock %} {% block content %}
-

{% trans "Corporation Member Data" %}

+

{% translate "Corporation Member Data" %}