Add admin tests, some fixes

This commit is contained in:
ErikKalkoken 2020-02-13 00:40:41 +01:00
parent 47babf2ed7
commit ff168d1c9e
2 changed files with 422 additions and 39 deletions

View File

@ -3,7 +3,7 @@ from django.conf import settings
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User as BaseUser, \ from django.contrib.auth.models import User as BaseUser, \
Permission as BasePermission Permission as BasePermission, Group
from django.db.models import Q, F from django.db.models import Q, F
from allianceauth.services.hooks import ServicesHook from allianceauth.services.hooks import ServicesHook
from django.db.models.signals import pre_save, post_save, pre_delete, \ 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) user_obj.profile.main_character.portrait_url(size=32)
) )
else: else:
return '' return None
user_profile_pic.short_description = '' user_profile_pic.short_description = ''
@ -131,12 +131,18 @@ def user_username(obj):
args=(obj.pk,) args=(obj.pk,)
) )
user_obj = obj.user if hasattr(obj, 'user') else obj user_obj = obj.user if hasattr(obj, 'user') else obj
if user_obj.profile.main_character:
return format_html( return format_html(
'<strong><a href="{}">{}</a></strong><br>{}', '<strong><a href="{}">{}</a></strong><br>{}',
link, link,
user_obj.username, user_obj.username,
user_obj.profile.main_character.character_name \ user_obj.profile.main_character.character_name
if user_obj.profile.main_character else '' )
else:
return format_html(
'<strong><a href="{}">{}</a></strong>',
link,
user_obj.username,
) )
user_username.short_description = 'user / main' user_username.short_description = 'user / main'
@ -150,20 +156,18 @@ def user_main_organization(obj):
To be used for all user based admin lists To be used for all user based admin lists
""" """
user_obj = obj.user if hasattr(obj, 'user') else obj 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 corporation = user_obj.profile.main_character.corporation_name
else: if user_obj.profile.main_character.alliance_id:
corporation = '' result = format_html('{}<br>{}',
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('{}<br>{}',
corporation, corporation,
alliance user_obj.profile.main_character.alliance_name
) )
else:
result = corporation
return result
user_main_organization.short_description = 'Corporation / Alliance (Main)' user_main_organization.short_description = 'Corporation / Alliance (Main)'
user_main_organization.admin_order_field = \ user_main_organization.admin_order_field = \
@ -177,7 +181,7 @@ class MainCorporationsFilter(admin.SimpleListFilter):
To be used for all user based admin lists To be used for all user based admin lists
""" """
title = 'corporation' title = 'corporation'
parameter_name = 'main_corporations' parameter_name = 'main_corporation_id__exact'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
qs = EveCharacter.objects\ qs = EveCharacter.objects\
@ -210,7 +214,7 @@ class MainAllianceFilter(admin.SimpleListFilter):
To be used for all user based admin lists To be used for all user based admin lists
""" """
title = 'alliance' title = 'alliance'
parameter_name = 'main_alliances' parameter_name = 'main_alliance_id__exact'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
qs = EveCharacter.objects\ qs = EveCharacter.objects\
@ -251,7 +255,7 @@ class UserAdmin(BaseUserAdmin):
class RealGroupsFilter(admin.SimpleListFilter): class RealGroupsFilter(admin.SimpleListFilter):
"""Custom filter to get groups w/o Autogroups""" """Custom filter to get groups w/o Autogroups"""
title = 'group' title = 'group'
parameter_name = 'real_groups' parameter_name = 'group_id__exact'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
qs = Group.objects.all().order_by(Lower('name')) qs = Group.objects.all().order_by(Lower('name'))
@ -267,7 +271,6 @@ class UserAdmin(BaseUserAdmin):
else: else:
return queryset.filter(groups__pk=self.value()) return queryset.filter(groups__pk=self.value())
def update_main_character_model(self, request, queryset): def update_main_character_model(self, request, queryset):
tasks_count = 0 tasks_count = 0
for obj in queryset: for obj in queryset:
@ -283,7 +286,6 @@ class UserAdmin(BaseUserAdmin):
update_main_character_model.short_description = \ update_main_character_model.short_description = \
'Update main character model from ESI' 'Update main character model from ESI'
def get_actions(self, request): def get_actions(self, request):
actions = super(BaseUserAdmin, self).get_actions(request) actions = super(BaseUserAdmin, self).get_actions(request)
@ -313,21 +315,22 @@ class UserAdmin(BaseUserAdmin):
) )
return actions return actions
def _list_2_html_w_tooltips(self, my_items: list, max_items: int) -> str: def _list_2_html_w_tooltips(self, my_items: list, max_items: int) -> str:
"""converts list of strings into HTML with cutoff and tooltip""" """converts list of strings into HTML with cutoff and tooltip"""
items_truncated_str = ', '.join(my_items[:max_items]) items_truncated_str = ', '.join(my_items[:max_items])
if len(my_items) <= max_items: if not my_items:
return items_truncated_str result = None
elif len(my_items) <= max_items:
result = items_truncated_str
else: else:
items_truncated_str += ' (...)' items_truncated_str += ', (...)'
items_all_str = ', '.join(my_items) items_all_str = ', '.join(my_items)
return format_html( result = format_html(
'<span data-tooltip="{}" class="tooltip">{}</span>', '<span data-tooltip="{}" class="tooltip">{}</span>',
items_all_str, items_all_str,
items_truncated_str items_truncated_str
) )
return result
inlines = BaseUserAdmin.inlines + [UserProfileInline] inlines = BaseUserAdmin.inlines + [UserProfileInline]
@ -380,12 +383,11 @@ class UserAdmin(BaseUserAdmin):
def _state(self, obj): def _state(self, obj):
return obj.profile.state return obj.profile.state.name
_state.short_description = 'state' _state.short_description = 'state'
_state.admin_order_field = 'profile__state' _state.admin_order_field = 'profile__state'
def _groups(self, obj): def _groups(self, obj):
if not _has_auto_groups: if not _has_auto_groups:
my_groups = [x.name for x in obj.groups.order_by('name')] my_groups = [x.name for x in obj.groups.order_by('name')]
@ -404,7 +406,6 @@ class UserAdmin(BaseUserAdmin):
_groups.short_description = 'groups' _groups.short_description = 'groups'
def _role(self, obj): def _role(self, obj):
if obj.is_superuser: if obj.is_superuser:
role = 'Superuser' role = 'Superuser'
@ -412,12 +413,10 @@ class UserAdmin(BaseUserAdmin):
role = 'Staff' role = 'Staff'
else: else:
role = 'User' role = 'User'
return role return role
_role.short_description = 'role' _role.short_description = 'role'
def has_change_permission(self, request, obj=None): def has_change_permission(self, request, obj=None):
return request.user.has_perm('auth.change_user') return request.user.has_perm('auth.change_user')

View File

@ -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 = ('<img src="https://images.evetech.net/characters/1001/'
'portrait?size=32" class="img-circle">')
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 = (
'<strong><a href="/admin/authentication/user/{}/change/">'
'Bruce_Wayne</a></strong><br>Bruce Wayne'.format(self.user_1.pk)
)
self.assertEqual(user_username(self.user_1), expected)
def test_user_username_3(self):
expected = (
'<strong><a href="/admin/authentication/user/{}/change/">'
'Lex_Luthor</a></strong>'.format(self.user_3.pk)
)
self.assertEqual(user_username(self.user_3), expected)
def test_user_main_organization_1(self):
expected = 'Wayne Technologies<br>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 = ('<span data-tooltip="one, two, three" '
'class="tooltip">one, two, (...)</span>')
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))