Merge branch 'issue_1219' into 'master'

HOTFIX: Fix startup error when autogroups is not installed

Closes #1219

See merge request allianceauth/allianceauth!1169
This commit is contained in:
Ariel Rin 2020-02-22 12:58:28 +00:00
commit 40e9dbfda2
15 changed files with 480 additions and 291 deletions

View File

@ -6,25 +6,45 @@ before_script:
- python -V
- pip install wheel tox
test-3.5:
test-3.5-core:
image: python:3.5-buster
script:
- tox -e py35
- tox -e py35-core
test-3.6:
test-3.6-core:
image: python:3.6-buster
script:
- tox -e py36
- tox -e py36-core
test-3.7:
test-3.7-core:
image: python:3.7-buster
script:
- tox -e py37
- tox -e py37-core
test-3.8:
test-3.8-core:
image: python:3.8-buster
script:
- tox -e py38
- tox -e py38-core
test-3.5-all:
image: python:3.5-buster
script:
- tox -e py35-all
test-3.6-all:
image: python:3.6-buster
script:
- tox -e py36-all
test-3.7-all:
image: python:3.7-buster
script:
- tox -e py37-all
test-3.8-all:
image: python:3.8-buster
script:
- tox -e py38-all
deploy_production:
stage: deploy

View File

@ -18,14 +18,14 @@ from django.utils.text import slugify
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
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo,\
EveAllianceInfo
from allianceauth.eveonline.tasks import update_character
from .app_settings import AUTHENTICATION_ADMIN_USERS_MAX_GROUPS, \
AUTHENTICATION_ADMIN_USERS_MAX_CHARS
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
_has_auto_groups = True
from allianceauth.eveonline.autogroups.models import *
else:
_has_auto_groups = False
@ -241,6 +241,22 @@ class MainAllianceFilter(admin.SimpleListFilter):
self.value())
def update_main_character_model(modeladmin, request, queryset):
tasks_count = 0
for obj in queryset:
if obj.profile.main_character:
update_character.delay(obj.profile.main_character.character_id)
tasks_count += 1
modeladmin.message_user(
request,
'Update from ESI started for {} characters'.format(tasks_count)
)
update_main_character_model.short_description = \
'Update main character model from ESI'
class UserAdmin(BaseUserAdmin):
"""Extending Django's UserAdmin model
@ -272,28 +288,13 @@ 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:
if obj.profile.main_character:
update_character.delay(obj.profile.main_character.character_id)
tasks_count += 1
self.message_user(
request,
'Update from ESI started for {} characters'.format(tasks_count)
)
update_main_character_model.short_description = \
'Update main character model from ESI'
def get_actions(self, request):
actions = super(BaseUserAdmin, self).get_actions(request)
actions[self.update_main_character_model.__name__] = (
self.update_main_character_model,
self.update_main_character_model.__name__,
self.update_main_character_model.short_description
actions[update_main_character_model.__name__] = (
update_main_character_model,
update_main_character_model.__name__,
update_main_character_model.short_description
)
for hook in get_hooks('services_hook'):

View File

@ -0,0 +1,11 @@
from django.urls import reverse
def get_admin_change_view_url(obj: object) -> str:
return reverse(
'admin:{}_{}_change'.format(
obj._meta.app_label,
type(obj).__name__.lower()
),
args=(obj.pk,)
)

View File

@ -1,53 +1,60 @@
from unittest.mock import patch
from django.test import TestCase, RequestFactory
from django.conf import settings
from django.contrib import admin
from django.contrib.admin.sites import AdminSite
from django.contrib.auth.models import User as BaseUser, Group
from django.test import TestCase, RequestFactory, Client
from allianceauth.authentication.models import CharacterOwnership, State
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
from allianceauth.authentication.models import CharacterOwnership, State, \
OwnershipRecord
from allianceauth.eveonline.models import (
EveCharacter, EveCorporationInfo, EveAllianceInfo
)
from allianceauth.tests.auth_utils import AuthUtils
from ..admin import (
BaseUserAdmin,
CharacterOwnershipAdmin,
PermissionAdmin,
StateAdmin,
MainCorporationsFilter,
MainAllianceFilter,
OwnershipRecordAdmin,
User,
UserAdmin,
user_main_organization,
user_profile_pic,
user_username,
update_main_character_model
)
from . import get_admin_change_view_url
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
_has_auto_groups = True
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
else:
_has_auto_groups = False
MODULE_PATH = 'allianceauth.authentication.admin'
class MockRequest(object):
def __init__(self, user=None):
self.user = user
class TestUserAdmin(TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
def create_test_data():
# groups
cls.group_1 = Group.objects.create(
group_1 = Group.objects.create(
name='Group 1'
)
cls.group_2 = Group.objects.create(
group_2 = Group.objects.create(
name='Group 2'
)
# user 1 - corp and alliance, normal user
cls.character_1 = EveCharacter.objects.create(
character_1 = EveCharacter.objects.create(
character_id='1001',
character_name='Bruce Wayne',
corporation_id='2001',
@ -57,7 +64,7 @@ class TestUserAdmin(TestCase):
alliance_name='Wayne Enterprises',
alliance_ticker='WE',
)
cls.character_1a = EveCharacter.objects.create(
character_1a = EveCharacter.objects.create(
character_id='1002',
character_name='Batman',
corporation_id='2001',
@ -80,27 +87,27 @@ class TestUserAdmin(TestCase):
member_count=42,
alliance=alliance
)
cls.user_1 = User.objects.create_user(
cls.character_1.character_name.replace(' ', '_'),
user_1 = User.objects.create_user(
character_1.character_name.replace(' ', '_'),
'abc@example.com',
'password'
)
CharacterOwnership.objects.create(
character=cls.character_1,
owner_hash='x1' + cls.character_1.character_name,
user=cls.user_1
character=character_1,
owner_hash='x1' + character_1.character_name,
user=user_1
)
CharacterOwnership.objects.create(
character=cls.character_1a,
owner_hash='x1' + cls.character_1a.character_name,
user=cls.user_1
character=character_1a,
owner_hash='x1' + character_1a.character_name,
user=user_1
)
cls.user_1.profile.main_character = cls.character_1
cls.user_1.profile.save()
cls.user_1.groups.add(cls.group_1)
user_1.profile.main_character = character_1
user_1.profile.save()
user_1.groups.add(group_1)
# user 2 - corp only, staff
cls.character_2 = EveCharacter.objects.create(
character_2 = EveCharacter.objects.create(
character_id=1003,
character_name='Clark Kent',
corporation_id=2002,
@ -115,24 +122,24 @@ class TestUserAdmin(TestCase):
member_count=99,
alliance=None
)
cls.user_2 = User.objects.create_user(
cls.character_2.character_name.replace(' ', '_'),
user_2 = User.objects.create_user(
character_2.character_name.replace(' ', '_'),
'abc@example.com',
'password'
)
CharacterOwnership.objects.create(
character=cls.character_2,
owner_hash='x1' + cls.character_2.character_name,
user=cls.user_2
character=character_2,
owner_hash='x1' + character_2.character_name,
user=user_2
)
cls.user_2.profile.main_character = cls.character_2
cls.user_2.profile.save()
cls.user_2.groups.add(cls.group_2)
cls.user_2.is_staff = True
cls.user_2.save()
user_2.profile.main_character = character_2
user_2.profile.save()
user_2.groups.add(group_2)
user_2.is_staff = True
user_2.save()
# user 3 - no main, no group, superuser
cls.character_3 = EveCharacter.objects.create(
character_3 = EveCharacter.objects.create(
character_id=1101,
character_name='Lex Luthor',
corporation_id=2101,
@ -153,27 +160,115 @@ class TestUserAdmin(TestCase):
alliance_ticker='LWD',
executor_corp_id=''
)
cls.user_3 = User.objects.create_user(
cls.character_3.character_name.replace(' ', '_'),
user_3 = User.objects.create_user(
character_3.character_name.replace(' ', '_'),
'abc@example.com',
'password'
)
CharacterOwnership.objects.create(
character=cls.character_3,
owner_hash='x1' + cls.character_3.character_name,
user=cls.user_3
character=character_3,
owner_hash='x1' + character_3.character_name,
user=user_3
)
cls.user_3.is_superuser = True
cls.user_3.save()
user_3.is_superuser = True
user_3.save()
return user_1, user_2, user_3, group_1, group_2
class TestCharacterOwnershipAdmin(TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user_1, _, _, _, _ = create_test_data()
def setUp(self):
self.modeladmin = CharacterOwnershipAdmin(
model=User, admin_site=AdminSite()
)
def test_change_view_loads_normally(self):
User.objects.create_superuser(
username='superuser', password='secret', email='admin@example.com'
)
c = Client()
c.login(username='superuser', password='secret')
ownership = self.user_1.character_ownerships.first()
response = c.get(get_admin_change_view_url(ownership))
self.assertEqual(response.status_code, 200)
class TestOwnershipRecordAdmin(TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user_1, _, _, _, _ = create_test_data()
def setUp(self):
self.modeladmin = OwnershipRecordAdmin(
model=User, admin_site=AdminSite()
)
def test_change_view_loads_normally(self):
User.objects.create_superuser(
username='superuser', password='secret', email='admin@example.com'
)
c = Client()
c.login(username='superuser', password='secret')
ownership_record = OwnershipRecord.objects\
.filter(user=self.user_1)\
.first()
response = c.get(get_admin_change_view_url(ownership_record))
self.assertEqual(response.status_code, 200)
class TestStateAdmin(TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
create_test_data()
def setUp(self):
self.modeladmin = StateAdmin(
model=User, admin_site=AdminSite()
)
def test_change_view_loads_normally(self):
User.objects.create_superuser(
username='superuser', password='secret', email='admin@example.com'
)
c = Client()
c.login(username='superuser', password='secret')
guest_state = AuthUtils.get_guest_state()
response = c.get(get_admin_change_view_url(guest_state))
self.assertEqual(response.status_code, 200)
member_state = AuthUtils.get_member_state()
response = c.get(get_admin_change_view_url(member_state))
self.assertEqual(response.status_code, 200)
class TestUserAdmin(TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user_1, cls.user_2, cls.user_3, cls.group_1, cls.group_2 = \
create_test_data()
def setUp(self):
self.factory = RequestFactory()
self.modeladmin = UserAdmin(
model=User, admin_site=AdminSite()
)
self.character_1 = self.user_1.character_ownerships.first().character
def _create_autogroups(self):
"""create autogroups for corps and alliances"""
if _has_auto_groups:
autogroups_config = AutogroupsConfig(
corp_groups = True,
alliance_groups = True
@ -315,8 +410,8 @@ class TestUserAdmin(TestCase):
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
update_main_character_model(
self.modeladmin, MockRequest(self.user_1), users_qs
)
self.assertEqual(mock_task.delay.call_count, 2)
self.assertTrue(mock_message_user.called)
@ -437,3 +532,12 @@ class TestUserAdmin(TestCase):
queryset = changelist.get_queryset(request)
expected = [self.user_1]
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'
)
c = Client()
c.login(username='superuser', password='secret')
response = c.get(get_admin_change_view_url(self.user_1))
self.assertEqual(response.status_code, 200)

View File

@ -1,11 +1,11 @@
from unittest.mock import Mock, patch
from django.test import TestCase
from .. import app_settings
MODULE_PATH = 'allianceauth.authentication'
class TestSetAppSetting(TestCase):
@patch(MODULE_PATH + '.app_settings.settings')
@ -17,7 +17,6 @@ class TestSetAppSetting(TestCase):
)
self.assertEqual(result, False)
@patch(MODULE_PATH + '.app_settings.settings')
def test_default_if_not_set_for_none(self, mock_settings):
mock_settings.TEST_SETTING_DUMMY = Mock(spec=None)
@ -28,7 +27,6 @@ class TestSetAppSetting(TestCase):
)
self.assertEqual(result, None)
@patch(MODULE_PATH + '.app_settings.settings')
def test_true_stays_true(self, mock_settings):
mock_settings.TEST_SETTING_DUMMY = True
@ -56,7 +54,6 @@ class TestSetAppSetting(TestCase):
)
self.assertEqual(result, False)
@patch(MODULE_PATH + '.app_settings.settings')
def test_default_for_invalid_type_int(self, mock_settings):
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
@ -95,7 +92,6 @@ class TestSetAppSetting(TestCase):
)
self.assertEqual(result, 50)
@patch(MODULE_PATH + '.app_settings.settings')
def test_default_is_none_needs_required_type(self, mock_settings):
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
@ -104,5 +100,3 @@ class TestSetAppSetting(TestCase):
'TEST_SETTING_DUMMY',
default_value=None
)

View File

@ -1,7 +1,7 @@
from django.conf import settings
from django.contrib import admin
from django.contrib.auth.models import Group as BaseGroup
from django.contrib.auth.models import Group as BaseGroup, User
from django.db.models import Count
from django.db.models.functions import Lower
from django.db.models.signals import pre_save, post_save, pre_delete, \
@ -14,7 +14,6 @@ from . import signals
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
_has_auto_groups = True
from allianceauth.eveonline.autogroups.models import *
else:
_has_auto_groups = False
@ -22,19 +21,24 @@ else:
class AuthGroupInlineAdmin(admin.StackedInline):
model = AuthGroup
filter_horizontal = ('group_leaders', 'group_leader_groups', 'states',)
fields = ('description', 'group_leaders', 'group_leader_groups', 'states', 'internal', 'hidden', 'open', 'public')
fields = (
'description',
'group_leaders',
'group_leader_groups',
'states', 'internal',
'hidden',
'open',
'public'
)
verbose_name_plural = 'Auth Settings'
verbose_name = ''
def formfield_for_manytomany(self, db_field, request, **kwargs):
"""overriding this formfield to have sorted lists in the form"""
if db_field.name == "group_leaders":
kwargs["queryset"] = User.objects\
.filter(profile__state__name='Member')\
.order_by(Lower('username'))
kwargs["queryset"] = User.objects.order_by(Lower('username'))
elif db_field.name == "group_leader_groups":
kwargs["queryset"] = Group.objects\
.order_by(Lower('name'))
kwargs["queryset"] = Group.objects.order_by(Lower('name'))
return super().formfield_for_manytomany(db_field, request, **kwargs)
def has_add_permission(self, request):
@ -103,14 +107,16 @@ class GroupAdmin(admin.ModelAdmin):
'_member_count',
'has_leader'
)
list_filter = (
list_filter = [
'authgroup__internal',
'authgroup__hidden',
'authgroup__open',
'authgroup__public',
IsAutoGroupFilter,
HasLeaderFilter
)
]
if _has_auto_groups:
list_filter.append(IsAutoGroupFilter)
list_filter.append(HasLeaderFilter)
search_fields = ('name', 'authgroup__description')
def get_queryset(self, request):

View File

@ -0,0 +1,11 @@
from django.urls import reverse
def get_admin_change_view_url(obj: object) -> str:
return reverse(
'admin:{}_{}_change'.format(
obj._meta.app_label,
type(obj).__name__.lower()
),
args=(obj.pk,)
)

View File

@ -1,22 +1,29 @@
from unittest.mock import patch
from django.test import TestCase, RequestFactory
from django.conf import settings
from django.contrib import admin
from django.contrib.admin.sites import AdminSite
from django.contrib.auth.models import User
from django.test import TestCase, RequestFactory, Client
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 (
IsAutoGroupFilter,
HasLeaderFilter,
GroupAdmin,
Group
)
from . import get_admin_change_view_url
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
_has_auto_groups = True
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
from ..admin import IsAutoGroupFilter
else:
_has_auto_groups = False
MODULE_PATH = 'allianceauth.groupmanagement.admin'
@ -210,6 +217,7 @@ class TestGroupAdmin(TestCase):
def _create_autogroups(self):
"""create autogroups for corps and alliances"""
if _has_auto_groups:
autogroups_config = AutogroupsConfig(
corp_groups = True,
alliance_groups = True
@ -267,6 +275,7 @@ class TestGroupAdmin(TestCase):
result = self.modeladmin._properties(self.group_6)
self.assertListEqual(result, expected)
if _has_auto_groups:
@patch(MODULE_PATH + '._has_auto_groups', True)
def test_properties_6(self):
self._create_autogroups()
@ -281,6 +290,7 @@ class TestGroupAdmin(TestCase):
# filters
if _has_auto_groups:
@patch(MODULE_PATH + '._has_auto_groups', True)
def test_filter_is_auto_group(self):
@ -377,3 +387,11 @@ class TestGroupAdmin(TestCase):
]
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'
)
c = Client()
c.login(username='superuser', password='secret')
response = c.get(get_admin_change_view_url(self.group_1))
self.assertEqual(response.status_code, 200)

View File

@ -20,10 +20,7 @@ class ServicesUserAdmin(admin.ModelAdmin):
"all": ("services/admin.css",)
}
search_fields = (
'user__username',
'uid'
)
search_fields = ('user__username',)
ordering = ('user__username',)
list_select_related = True
list_display = (

View File

@ -6,9 +6,8 @@ from ...admin import ServicesUserAdmin
@admin.register(DiscordUser)
class DiscordUserAdmin(ServicesUserAdmin):
list_display = ServicesUserAdmin.list_display + (
'_uid',
)
list_display = ServicesUserAdmin.list_display + ('_uid',)
search_fields = ServicesUserAdmin.search_fields + ('uid', )
def _uid(self, obj):
return obj.uid

View File

@ -10,6 +10,7 @@ class Teamspeak3UserAdmin(ServicesUserAdmin):
'uid',
'perm_key'
)
search_fields = ServicesUserAdmin.search_fields + ('uid', )
@admin.register(AuthTS)

View File

@ -3,8 +3,6 @@ import os
import sys
if __name__ == "__main__":
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'
try:
from django.core.management import execute_from_command_line
except ImportError:

View File

@ -1,5 +1,7 @@
"""
Alliance Auth Test Suite Django settings.
Alliance Auth Test Suite Django settings
Testing all services and plug-in apps
"""
from allianceauth.project_template.project_name.settings.base import *
@ -41,14 +43,6 @@ ROOT_URLCONF = 'tests.urls'
CACHES['default'] = {'BACKEND': 'django.core.cache.backends.db.DatabaseCache'}
#####################
# HR Configuration
#####################
# JACK_KNIFE_URL - Url for the audit page of API Jack knife
# Should seriously replace with your own.
#####################
JACK_KNIFE_URL = 'http://example.com/eveapi/audit.php'
########################
# XenForo Configuration
########################

33
tests/settings_core.py Normal file
View File

@ -0,0 +1,33 @@
"""
Alliance Auth Test Suite Django settings
Testing core packages only
"""
from allianceauth.project_template.project_name.settings.base import *
# Use nose to run all tests
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
NOSE_ARGS = [
#'--with-coverage',
#'--cover-package=',
#'--exe', # If your tests need this to be found/run, check they py files are not chmodded +x
]
# Celery configuration
CELERY_ALWAYS_EAGER = True # Forces celery to run locally for testing
INSTALLED_APPS += [
'django_nose',
]
ROOT_URLCONF = 'tests.urls'
CACHES['default'] = {'BACKEND': 'django.core.cache.backends.db.DatabaseCache'}
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.MD5PasswordHasher',
]
LOGGING = None # Comment out to enable logging for debugging

10
tox.ini
View File

@ -1,11 +1,12 @@
[tox]
skipsdist = true
usedevelop = true
envlist = py{35,36,37,38}-dj{2X}
envlist = py{35,36,37,38}-{all}
[testenv]
setenv =
DJANGO_SETTINGS_MODULE = settings
all: DJANGO_SETTINGS_MODULE = tests.settings_all
core: DJANGO_SETTINGS_MODULE = tests.settings_core
basepython =
py35: python3.5
py36: python3.6
@ -13,8 +14,9 @@ basepython =
py38: python3.8
deps=
coverage
dj2X: Django>=2.0,<3.0
Django>=2.0,<3.0
install_command = pip install -e ".[testing]" -U {opts} {packages}
commands =
coverage run runtests.py -v 2
all: coverage run runtests.py -v 2
core: coverage run runtests.py allianceauth.authentication.tests.test_app_settings -v 2
coverage report -m