diff --git a/allianceauth/authentication/admin.py b/allianceauth/authentication/admin.py
index a3df70b2..dac057d8 100644
--- a/allianceauth/authentication/admin.py
+++ b/allianceauth/authentication/admin.py
@@ -3,7 +3,7 @@ from django.conf import settings
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User as BaseUser, \
- Permission as BasePermission
+ Permission as BasePermission, Group
from django.db.models import Q, F
from allianceauth.services.hooks import ServicesHook
from django.db.models.signals import pre_save, post_save, pre_delete, \
@@ -113,7 +113,7 @@ def user_profile_pic(obj):
user_obj.profile.main_character.portrait_url(size=32)
)
else:
- return ''
+ return None
user_profile_pic.short_description = ''
@@ -131,13 +131,19 @@ def user_username(obj):
args=(obj.pk,)
)
user_obj = obj.user if hasattr(obj, 'user') else obj
- return format_html(
- '{}
{}',
- link,
- user_obj.username,
- user_obj.profile.main_character.character_name \
- if user_obj.profile.main_character else ''
- )
+ if user_obj.profile.main_character:
+ return format_html(
+ '{}
{}',
+ link,
+ user_obj.username,
+ user_obj.profile.main_character.character_name
+ )
+ else:
+ return format_html(
+ '{}',
+ link,
+ user_obj.username,
+ )
user_username.short_description = 'user / main'
user_username.admin_order_field = 'username'
@@ -150,20 +156,18 @@ def user_main_organization(obj):
To be used for all user based admin lists
"""
user_obj = obj.user if hasattr(obj, 'user') else obj
- if user_obj.profile.main_character:
+ if not user_obj.profile.main_character:
+ result = None
+ else:
corporation = user_obj.profile.main_character.corporation_name
- else:
- corporation = ''
- if (user_obj.profile.main_character
- and user_obj.profile.main_character.alliance_id
- ):
- alliance = user_obj.profile.main_character.alliance_name
- else:
- alliance = ''
- return format_html('{}
{}',
- corporation,
- alliance
- )
+ if user_obj.profile.main_character.alliance_id:
+ result = format_html('{}
{}',
+ corporation,
+ user_obj.profile.main_character.alliance_name
+ )
+ else:
+ result = corporation
+ return result
user_main_organization.short_description = 'Corporation / Alliance (Main)'
user_main_organization.admin_order_field = \
@@ -177,7 +181,7 @@ class MainCorporationsFilter(admin.SimpleListFilter):
To be used for all user based admin lists
"""
title = 'corporation'
- parameter_name = 'main_corporations'
+ parameter_name = 'main_corporation_id__exact'
def lookups(self, request, model_admin):
qs = EveCharacter.objects\
@@ -210,7 +214,7 @@ class MainAllianceFilter(admin.SimpleListFilter):
To be used for all user based admin lists
"""
title = 'alliance'
- parameter_name = 'main_alliances'
+ parameter_name = 'main_alliance_id__exact'
def lookups(self, request, model_admin):
qs = EveCharacter.objects\
@@ -251,7 +255,7 @@ class UserAdmin(BaseUserAdmin):
class RealGroupsFilter(admin.SimpleListFilter):
"""Custom filter to get groups w/o Autogroups"""
title = 'group'
- parameter_name = 'real_groups'
+ parameter_name = 'group_id__exact'
def lookups(self, request, model_admin):
qs = Group.objects.all().order_by(Lower('name'))
@@ -267,7 +271,6 @@ class UserAdmin(BaseUserAdmin):
else:
return queryset.filter(groups__pk=self.value())
-
def update_main_character_model(self, request, queryset):
tasks_count = 0
for obj in queryset:
@@ -283,7 +286,6 @@ class UserAdmin(BaseUserAdmin):
update_main_character_model.short_description = \
'Update main character model from ESI'
-
def get_actions(self, request):
actions = super(BaseUserAdmin, self).get_actions(request)
@@ -313,21 +315,22 @@ class UserAdmin(BaseUserAdmin):
)
return actions
-
def _list_2_html_w_tooltips(self, my_items: list, max_items: int) -> str:
"""converts list of strings into HTML with cutoff and tooltip"""
items_truncated_str = ', '.join(my_items[:max_items])
- if len(my_items) <= max_items:
- return items_truncated_str
+ if not my_items:
+ result = None
+ elif len(my_items) <= max_items:
+ result = items_truncated_str
else:
- items_truncated_str += ' (...)'
+ items_truncated_str += ', (...)'
items_all_str = ', '.join(my_items)
- return format_html(
+ result = format_html(
'{}',
items_all_str,
items_truncated_str
)
-
+ return result
inlines = BaseUserAdmin.inlines + [UserProfileInline]
@@ -380,12 +383,11 @@ class UserAdmin(BaseUserAdmin):
def _state(self, obj):
- return obj.profile.state
+ return obj.profile.state.name
_state.short_description = 'state'
_state.admin_order_field = 'profile__state'
-
def _groups(self, obj):
if not _has_auto_groups:
my_groups = [x.name for x in obj.groups.order_by('name')]
@@ -404,20 +406,17 @@ class UserAdmin(BaseUserAdmin):
_groups.short_description = 'groups'
-
def _role(self, obj):
if obj.is_superuser:
role = 'Superuser'
elif obj.is_staff:
role = 'Staff'
else:
- role = 'User'
-
+ role = 'User'
return role
_role.short_description = 'role'
-
def has_change_permission(self, request, obj=None):
return request.user.has_perm('auth.change_user')
diff --git a/allianceauth/authentication/tests/test_admin.py b/allianceauth/authentication/tests/test_admin.py
new file mode 100644
index 00000000..961ff3c9
--- /dev/null
+++ b/allianceauth/authentication/tests/test_admin.py
@@ -0,0 +1,384 @@
+from unittest.mock import patch
+
+from django.test import TestCase, RequestFactory
+from django.contrib import admin
+from django.contrib.admin.sites import AdminSite
+from django.contrib.auth.models import User as BaseUser, Group
+
+from allianceauth.authentication.models import CharacterOwnership, State
+from allianceauth.eveonline.autogroups.models import AutogroupsConfig
+from allianceauth.eveonline.models import (
+ EveCharacter, EveCorporationInfo, EveAllianceInfo
+)
+
+from ..admin import (
+ BaseUserAdmin,
+ MainCorporationsFilter,
+ MainAllianceFilter,
+ User,
+ UserAdmin,
+ user_main_organization,
+ user_profile_pic,
+ user_username,
+)
+
+
+MODULE_PATH = 'allianceauth.authentication.admin'
+
+
+class MockRequest(object):
+
+ def __init__(self, user=None):
+ self.user = user
+
+
+class TestUserAdmin(TestCase):
+
+ def setUp(self):
+ self.factory = RequestFactory()
+ self.modeladmin = UserAdmin(
+ model=User, admin_site=AdminSite()
+ )
+ # groups
+ self.group_1 = Group.objects.create(
+ name='Group 1'
+ )
+ self.group_2 = Group.objects.create(
+ name='Group 2'
+ )
+
+ # user 1 - corp and alliance, normal user
+ self.character_1 = EveCharacter.objects.create(
+ character_id='1001',
+ character_name='Bruce Wayne',
+ corporation_id='2001',
+ corporation_name='Wayne Technologies',
+ corporation_ticker='WT',
+ alliance_id='3001',
+ alliance_name='Wayne Enterprises',
+ alliance_ticker='WE',
+ )
+ self.character_1a = EveCharacter.objects.create(
+ character_id='1002',
+ character_name='Batman',
+ corporation_id='2001',
+ corporation_name='Wayne Technologies',
+ corporation_ticker='WT',
+ alliance_id='3001',
+ alliance_name='Wayne Enterprises',
+ alliance_ticker='WE',
+ )
+ alliance = EveAllianceInfo.objects.create(
+ alliance_id='3001',
+ alliance_name='Wayne Enterprises',
+ alliance_ticker='WE',
+ executor_corp_id='2001'
+ )
+ EveCorporationInfo.objects.create(
+ corporation_id='2001',
+ corporation_name='Wayne Technologies',
+ corporation_ticker='WT',
+ member_count=42,
+ alliance=alliance
+ )
+ self.user_1 = User.objects.create_user(
+ self.character_1.character_name.replace(' ', '_'),
+ 'abc@example.com',
+ 'password'
+ )
+ CharacterOwnership.objects.create(
+ character=self.character_1,
+ owner_hash='x1' + self.character_1.character_name,
+ user=self.user_1
+ )
+ CharacterOwnership.objects.create(
+ character=self.character_1a,
+ owner_hash='x1' + self.character_1a.character_name,
+ user=self.user_1
+ )
+ self.user_1.profile.main_character = self.character_1
+ self.user_1.profile.save()
+ self.user_1.groups.add(self.group_1)
+
+ # user 2 - corp only, staff
+ self.character_2 = EveCharacter.objects.create(
+ character_id=1003,
+ character_name='Clark Kent',
+ corporation_id=2002,
+ corporation_name='Daily Planet',
+ corporation_ticker='DP',
+ alliance_id=None
+ )
+ EveCorporationInfo.objects.create(
+ corporation_id=2002,
+ corporation_name='Daily Plane',
+ corporation_ticker='DP',
+ member_count=99,
+ alliance=None
+ )
+ self.user_2 = User.objects.create_user(
+ self.character_2.character_name.replace(' ', '_'),
+ 'abc@example.com',
+ 'password'
+ )
+ CharacterOwnership.objects.create(
+ character=self.character_2,
+ owner_hash='x1' + self.character_2.character_name,
+ user=self.user_2
+ )
+ self.user_2.profile.main_character = self.character_2
+ self.user_2.profile.save()
+ self.user_2.groups.add(self.group_2)
+ self.user_2.is_staff = True
+ self.user_2.save()
+
+ # user 3 - no main, no group, superuser
+ self.character_3 = EveCharacter.objects.create(
+ character_id=1101,
+ character_name='Lex Luthor',
+ corporation_id=2101,
+ corporation_name='Lex Corp',
+ corporation_ticker='LC',
+ alliance_id=None
+ )
+ EveCorporationInfo.objects.create(
+ corporation_id=2101,
+ corporation_name='Lex Corp',
+ corporation_ticker='LC',
+ member_count=666,
+ alliance=None
+ )
+ EveAllianceInfo.objects.create(
+ alliance_id='3101',
+ alliance_name='Lex World Domination',
+ alliance_ticker='LWD',
+ executor_corp_id=''
+ )
+ self.user_3 = User.objects.create_user(
+ self.character_3.character_name.replace(' ', '_'),
+ 'abc@example.com',
+ 'password'
+ )
+ CharacterOwnership.objects.create(
+ character=self.character_3,
+ owner_hash='x1' + self.character_3.character_name,
+ user=self.user_3
+ )
+ self.user_3.is_superuser = True
+ self.user_3.save()
+
+ # create autogroups for corps and alliances
+ autogroups_config = AutogroupsConfig(
+ corp_groups = True,
+ alliance_groups = True
+ )
+ autogroups_config.save()
+ for state in State.objects.all():
+ autogroups_config.states.add(state)
+ autogroups_config.update_corp_group_membership(self.user_1)
+
+ # column rendering
+
+ def test_user_profile_pic_1(self):
+ expected = ('
')
+ self.assertEqual(user_profile_pic(self.user_1), expected)
+
+ def test_user_profile_pic_3(self):
+ self.assertIsNone(user_profile_pic(self.user_3))
+
+ def test_user_username_1(self):
+ expected = (
+ ''
+ 'Bruce_Wayne
Bruce Wayne'.format(self.user_1.pk)
+ )
+ self.assertEqual(user_username(self.user_1), expected)
+
+ def test_user_username_3(self):
+ expected = (
+ ''
+ 'Lex_Luthor'.format(self.user_3.pk)
+ )
+ self.assertEqual(user_username(self.user_3), expected)
+
+ def test_user_main_organization_1(self):
+ expected = 'Wayne Technologies
Wayne Enterprises'
+ self.assertEqual(user_main_organization(self.user_1), expected)
+
+ def test_user_main_organization_2(self):
+ expected = 'Daily Planet'
+ self.assertEqual(user_main_organization(self.user_2), expected)
+
+ def test_user_main_organization_3(self):
+ expected = None
+ self.assertEqual(user_main_organization(self.user_3), expected)
+
+ def test_characters_1(self):
+ expected = 'Batman, Bruce Wayne'
+ result = self.modeladmin._characters(self.user_1)
+ self.assertEqual(result, expected)
+
+ def test_characters_2(self):
+ expected = 'Clark Kent'
+ result = self.modeladmin._characters(self.user_2)
+ self.assertEqual(result, expected)
+
+ def test_characters_3(self):
+ expected = 'Lex Luthor'
+ result = self.modeladmin._characters(self.user_3)
+ self.assertEqual(result, expected)
+
+ def test_groups_1(self):
+ expected = 'Group 1'
+ result = self.modeladmin._groups(self.user_1)
+ self.assertEqual(result, expected)
+
+ def test_groups_2(self):
+ expected = 'Group 2'
+ result = self.modeladmin._groups(self.user_2)
+ self.assertEqual(result, expected)
+
+ def test_groups_3(self):
+ result = self.modeladmin._groups(self.user_3)
+ self.assertIsNone(result)
+
+ def test_state(self):
+ expected = 'Guest'
+ result = self.modeladmin._state(self.user_1)
+ self.assertEqual(result, expected)
+
+ def test_role_1(self):
+ expected = 'User'
+ result = self.modeladmin._role(self.user_1)
+ self.assertEqual(result, expected)
+
+ def test_role_2(self):
+ expected = 'Staff'
+ result = self.modeladmin._role(self.user_2)
+ self.assertEqual(result, expected)
+
+ def test_role_3(self):
+ expected = 'Superuser'
+ result = self.modeladmin._role(self.user_3)
+ self.assertEqual(result, expected)
+
+ def test_list_2_html_w_tooltips_no_cutoff(self):
+ items = ['one', 'two', 'three']
+ expected = 'one, two, three'
+ result = self.modeladmin._list_2_html_w_tooltips(items, 5)
+ self.assertEqual(expected, result)
+
+ def test_list_2_html_w_tooltips_w_cutoff(self):
+ items = ['one', 'two', 'three']
+ expected = ('one, two, (...)')
+ result = self.modeladmin._list_2_html_w_tooltips(items, 2)
+ self.assertEqual(expected, result)
+
+ def test_list_2_html_w_tooltips_empty_list(self):
+ items = []
+ expected = None
+ result = self.modeladmin._list_2_html_w_tooltips(items, 5)
+ self.assertEqual(expected, result)
+
+ # actions
+
+ @patch(MODULE_PATH + '.UserAdmin.message_user', auto_spec=True)
+ @patch(MODULE_PATH + '.update_character')
+ def test_action_update_main_character_model(
+ self, mock_task, mock_message_user
+ ):
+ users_qs = User.objects.filter(pk__in=[self.user_1.pk, self.user_2.pk])
+ self.modeladmin.update_main_character_model(
+ MockRequest(self.user_1), users_qs
+ )
+ self.assertEqual(mock_task.delay.call_count, 2)
+ self.assertTrue(mock_message_user.called)
+
+ # filters
+
+ def test_filter_real_groups(self):
+
+ class UserAdminTest(BaseUserAdmin):
+ list_filter = (UserAdmin.RealGroupsFilter,)
+
+ my_modeladmin = UserAdminTest(User, AdminSite())
+
+ # Make sure the lookups are correct
+ request = self.factory.get('/')
+ request.user = self.user_1
+ changelist = my_modeladmin.get_changelist_instance(request)
+ filters = changelist.get_filters(request)
+ filterspec = filters[0][0]
+ expected = [
+ (self.group_1.pk, self.group_1.name),
+ (self.group_2.pk, self.group_2.name),
+ ]
+ self.assertEqual(filterspec.lookup_choices, expected)
+
+ # Make sure the correct queryset is returned
+ request = self.factory.get('/', {'group_id__exact': self.group_1.pk})
+ request.user = self.user_1
+ changelist = my_modeladmin.get_changelist_instance(request)
+ queryset = changelist.get_queryset(request)
+ expected = User.objects.filter(groups__in=[self.group_1])
+ self.assertSetEqual(set(queryset), set(expected))
+
+ def test_filter_main_corporations(self):
+
+ class UserAdminTest(BaseUserAdmin):
+ list_filter = (MainCorporationsFilter,)
+
+ my_modeladmin = UserAdminTest(User, AdminSite())
+
+ # Make sure the lookups are correct
+ request = self.factory.get('/')
+ request.user = self.user_1
+ changelist = my_modeladmin.get_changelist_instance(request)
+ filters = changelist.get_filters(request)
+ filterspec = filters[0][0]
+ expected = [
+ ('2002', 'Daily Planet'),
+ ('2001', 'Wayne Technologies'),
+ ]
+ self.assertEqual(filterspec.lookup_choices, expected)
+
+ # Make sure the correct queryset is returned
+ request = self.factory.get(
+ '/',
+ {'main_corporation_id__exact': self.character_1.corporation_id}
+ )
+ request.user = self.user_1
+ changelist = my_modeladmin.get_changelist_instance(request)
+ queryset = changelist.get_queryset(request)
+ expected = [self.user_1]
+ self.assertSetEqual(set(queryset), set(expected))
+
+ def test_filter_main_alliances(self):
+
+ class UserAdminTest(BaseUserAdmin):
+ list_filter = (MainAllianceFilter,)
+
+ my_modeladmin = UserAdminTest(User, AdminSite())
+
+ # Make sure the lookups are correct
+ request = self.factory.get('/')
+ request.user = self.user_1
+ changelist = my_modeladmin.get_changelist_instance(request)
+ filters = changelist.get_filters(request)
+ filterspec = filters[0][0]
+ expected = [
+ ('3001', 'Wayne Enterprises'),
+ ]
+ self.assertEqual(filterspec.lookup_choices, expected)
+
+ # Make sure the correct queryset is returned
+ request = self.factory.get(
+ '/',
+ {'main_alliance_id__exact': self.character_1.alliance_id}
+ )
+ request.user = self.user_1
+ changelist = my_modeladmin.get_changelist_instance(request)
+ queryset = changelist.get_queryset(request)
+ expected = [self.user_1]
+ self.assertSetEqual(set(queryset), set(expected))
\ No newline at end of file