-
{% trans "Main Character" %}
+
+ {% blocktrans with state=request.user.profile.state %}
+ Main Character (State: {{ state }})
+ {% endblocktrans %}
+
{% if request.user.profile.main_character %}
diff --git a/allianceauth/authentication/tests/test_backend.py b/allianceauth/authentication/tests/test_backend.py
index ef541684..2a846c7c 100644
--- a/allianceauth/authentication/tests/test_backend.py
+++ b/allianceauth/authentication/tests/test_backend.py
@@ -1,10 +1,13 @@
-from unittest.mock import Mock, patch
-
from django.contrib.auth.models import User, Group
from django.test import TestCase
+
+from allianceauth.eveonline.models import EveCharacter
from allianceauth.tests.auth_utils import AuthUtils
+from esi.models import Token
+
from ..backends import StateBackend
+from ..models import CharacterOwnership, UserProfile, OwnershipRecord
MODULE_PATH = 'allianceauth.authentication'
@@ -76,10 +79,71 @@ class TestStatePermissions(TestCase):
self.assertTrue(user.has_perm(PERMISSION_2))
+class TestAuthenticate(TestCase):
+ @classmethod
+ def setUpTestData(cls):
+ cls.main_character = EveCharacter.objects.create(
+ character_id=1,
+ character_name='Main Character',
+ corporation_id=1,
+ corporation_name='Corp',
+ corporation_ticker='CORP',
+ )
+ cls.alt_character = EveCharacter.objects.create(
+ character_id=2,
+ character_name='Alt Character',
+ corporation_id=1,
+ corporation_name='Corp',
+ corporation_ticker='CORP',
+ )
+ cls.unclaimed_character = EveCharacter.objects.create(
+ character_id=3,
+ character_name='Unclaimed Character',
+ corporation_id=1,
+ corporation_name='Corp',
+ corporation_ticker='CORP',
+ )
+ cls.user = AuthUtils.create_user('test_user', disconnect_signals=True)
+ cls.old_user = AuthUtils.create_user('old_user', disconnect_signals=True)
+ AuthUtils.disconnect_signals()
+ CharacterOwnership.objects.create(user=cls.user, character=cls.main_character, owner_hash='1')
+ CharacterOwnership.objects.create(user=cls.user, character=cls.alt_character, owner_hash='2')
+ UserProfile.objects.update_or_create(user=cls.user, defaults={'main_character': cls.main_character})
+ AuthUtils.connect_signals()
+ 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)
+ 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)
+ 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')
+ user = StateBackend().authenticate(token=t)
+ self.assertNotEqual(user, self.user)
+ self.assertEqual(user.username, 'Unclaimed_Character')
+ self.assertEqual(user.profile.main_character, self.unclaimed_character)
-
+ def test_authenticate_character_record(self):
+ t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='4')
+ OwnershipRecord.objects.create(user=self.old_user, character=self.unclaimed_character, owner_hash='4')
+ user = StateBackend().authenticate(token=t)
+ self.assertEqual(user, self.old_user)
+ self.assertTrue(CharacterOwnership.objects.filter(owner_hash='4', user=self.old_user).exists())
+ self.assertTrue(user.profile.main_character)
-
+ def test_iterate_username(self):
+ t = Token(character_id=self.unclaimed_character.character_id,
+ character_name=self.unclaimed_character.character_name, character_owner_hash='3')
+ username = StateBackend().authenticate(token=t).username
+ t.character_owner_hash = '4'
+ username_1 = StateBackend().authenticate(token=t).username
+ t.character_owner_hash = '5'
+ username_2 = StateBackend().authenticate(token=t).username
+ self.assertNotEqual(username, username_1, username_2)
+ self.assertTrue(username_1.endswith('_1'))
+ self.assertTrue(username_2.endswith('_2'))
diff --git a/allianceauth/authentication/tests/test_commands.py b/allianceauth/authentication/tests/test_commands.py
new file mode 100644
index 00000000..5131183d
--- /dev/null
+++ b/allianceauth/authentication/tests/test_commands.py
@@ -0,0 +1,35 @@
+from io import StringIO
+
+from django.core.management import call_command
+from django.test import TestCase
+
+from allianceauth.tests.auth_utils import AuthUtils
+
+from ..models import CharacterOwnership, UserProfile
+
+
+class ManagementCommandTestCase(TestCase):
+ @classmethod
+ def setUpTestData(cls):
+ cls.user = AuthUtils.create_user('test user', disconnect_signals=True)
+ AuthUtils.add_main_character(cls.user, 'test character', '1', '2', 'test corp', 'test')
+ character = UserProfile.objects.get(user=cls.user).main_character
+ CharacterOwnership.objects.create(user=cls.user, character=character, owner_hash='test')
+
+ def setUp(self):
+ self.stdout = StringIO()
+
+ def test_ownership(self):
+ call_command('checkmains', stdout=self.stdout)
+ self.assertFalse(UserProfile.objects.filter(main_character__isnull=True).count())
+ self.assertNotIn(self.user.username, self.stdout.getvalue())
+ self.assertIn('All main characters', self.stdout.getvalue())
+
+ def test_no_ownership(self):
+ user = AuthUtils.create_user('v1 user', disconnect_signals=True)
+ AuthUtils.add_main_character(user, 'v1 character', '10', '20', 'test corp', 'test')
+ self.assertFalse(UserProfile.objects.filter(main_character__isnull=True).count())
+
+ call_command('checkmains', stdout=self.stdout)
+ self.assertEqual(UserProfile.objects.filter(main_character__isnull=True).count(), 1)
+ self.assertIn(user.username, self.stdout.getvalue())
diff --git a/allianceauth/authentication/tests/test_decorators.py b/allianceauth/authentication/tests/test_decorators.py
new file mode 100644
index 00000000..69c3949e
--- /dev/null
+++ b/allianceauth/authentication/tests/test_decorators.py
@@ -0,0 +1,68 @@
+from unittest import mock
+from urllib import parse
+
+from django.conf import settings
+from django.contrib.auth.models import AnonymousUser
+from django.http.response import HttpResponse
+from django.shortcuts import reverse
+from django.test import TestCase
+from django.test.client import RequestFactory
+
+from allianceauth.eveonline.models import EveCharacter
+from allianceauth.tests.auth_utils import AuthUtils
+
+from ..decorators import main_character_required
+from ..models import CharacterOwnership
+
+
+MODULE_PATH = 'allianceauth.authentication'
+
+
+class DecoratorTestCase(TestCase):
+ @staticmethod
+ @main_character_required
+ def dummy_view(*args, **kwargs):
+ return HttpResponse(status=200)
+
+ @classmethod
+ def setUpTestData(cls):
+ cls.main_user = AuthUtils.create_user('main_user', disconnect_signals=True)
+ cls.no_main_user = AuthUtils.create_user(
+ 'no_main_user', disconnect_signals=True
+ )
+ main_character = EveCharacter.objects.create(
+ character_id=1,
+ character_name='Main Character',
+ corporation_id=1,
+ corporation_name='Corp',
+ corporation_ticker='CORP',
+ )
+ CharacterOwnership.objects.create(
+ user=cls.main_user, character=main_character, owner_hash='1'
+ )
+ cls.main_user.profile.main_character = main_character
+
+ def setUp(self):
+ self.request = RequestFactory().get('/test/')
+
+ @mock.patch(MODULE_PATH + '.decorators.messages')
+ def test_login_redirect(self, m):
+ setattr(self.request, 'user', AnonymousUser())
+ response = self.dummy_view(self.request)
+ self.assertEqual(response.status_code, 302)
+ url = getattr(response, 'url', None)
+ self.assertEqual(parse.urlparse(url).path, reverse(settings.LOGIN_URL))
+
+ @mock.patch(MODULE_PATH + '.decorators.messages')
+ def test_main_character_redirect(self, m):
+ setattr(self.request, 'user', self.no_main_user)
+ response = self.dummy_view(self.request)
+ self.assertEqual(response.status_code, 302)
+ url = getattr(response, 'url', None)
+ self.assertEqual(url, reverse('authentication:dashboard'))
+
+ @mock.patch(MODULE_PATH + '.decorators.messages')
+ def test_successful_request(self, m):
+ setattr(self.request, 'user', self.main_user)
+ response = self.dummy_view(self.request)
+ self.assertEqual(response.status_code, 200)
diff --git a/allianceauth/authentication/tests/test_all.py b/allianceauth/authentication/tests/test_models.py
similarity index 59%
rename from allianceauth/authentication/tests/test_all.py
rename to allianceauth/authentication/tests/test_models.py
index 72aa6771..60338806 100644
--- a/allianceauth/authentication/tests/test_all.py
+++ b/allianceauth/authentication/tests/test_models.py
@@ -1,147 +1,20 @@
from unittest import mock
-from io import StringIO
-from urllib import parse
-from django.conf import settings
-from django.contrib.auth.models import AnonymousUser, User
-from django.core.management import call_command
-from django.http.response import HttpResponse
-from django.shortcuts import reverse
+from django.contrib.auth.models import User
from django.test import TestCase
-from django.test.client import RequestFactory
-
-from allianceauth.authentication.decorators import main_character_required
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo,\
EveAllianceInfo
from allianceauth.tests.auth_utils import AuthUtils
from esi.errors import IncompleteResponseError
from esi.models import Token
-from ..backends import StateBackend
-from ..models import CharacterOwnership, UserProfile, State, get_guest_state,\
- OwnershipRecord
+from ..models import CharacterOwnership, State, get_guest_state
from ..tasks import check_character_ownership
MODULE_PATH = 'allianceauth.authentication'
-class DecoratorTestCase(TestCase):
- @staticmethod
- @main_character_required
- def dummy_view(*args, **kwargs):
- return HttpResponse(status=200)
-
- @classmethod
- def setUpTestData(cls):
- cls.main_user = AuthUtils.create_user('main_user', disconnect_signals=True)
- cls.no_main_user = AuthUtils.create_user('no_main_user', disconnect_signals=True)
- main_character = EveCharacter.objects.create(
- character_id=1,
- character_name='Main Character',
- corporation_id=1,
- corporation_name='Corp',
- corporation_ticker='CORP',
- )
- CharacterOwnership.objects.create(user=cls.main_user, character=main_character, owner_hash='1')
- cls.main_user.profile.main_character = main_character
-
- def setUp(self):
- self.request = RequestFactory().get('/test/')
-
- @mock.patch(MODULE_PATH + '.decorators.messages')
- def test_login_redirect(self, m):
- setattr(self.request, 'user', AnonymousUser())
- response = self.dummy_view(self.request)
- self.assertEqual(response.status_code, 302)
- url = getattr(response, 'url', None)
- self.assertEqual(parse.urlparse(url).path, reverse(settings.LOGIN_URL))
-
- @mock.patch(MODULE_PATH + '.decorators.messages')
- def test_main_character_redirect(self, m):
- setattr(self.request, 'user', self.no_main_user)
- response = self.dummy_view(self.request)
- self.assertEqual(response.status_code, 302)
- url = getattr(response, 'url', None)
- self.assertEqual(url, reverse('authentication:dashboard'))
-
- @mock.patch(MODULE_PATH + '.decorators.messages')
- def test_successful_request(self, m):
- setattr(self.request, 'user', self.main_user)
- response = self.dummy_view(self.request)
- self.assertEqual(response.status_code, 200)
-
-
-class BackendTestCase(TestCase):
- @classmethod
- def setUpTestData(cls):
- cls.main_character = EveCharacter.objects.create(
- character_id=1,
- character_name='Main Character',
- corporation_id=1,
- corporation_name='Corp',
- corporation_ticker='CORP',
- )
- cls.alt_character = EveCharacter.objects.create(
- character_id=2,
- character_name='Alt Character',
- corporation_id=1,
- corporation_name='Corp',
- corporation_ticker='CORP',
- )
- cls.unclaimed_character = EveCharacter.objects.create(
- character_id=3,
- character_name='Unclaimed Character',
- corporation_id=1,
- corporation_name='Corp',
- corporation_ticker='CORP',
- )
- cls.user = AuthUtils.create_user('test_user', disconnect_signals=True)
- cls.old_user = AuthUtils.create_user('old_user', disconnect_signals=True)
- AuthUtils.disconnect_signals()
- CharacterOwnership.objects.create(user=cls.user, character=cls.main_character, owner_hash='1')
- CharacterOwnership.objects.create(user=cls.user, character=cls.alt_character, owner_hash='2')
- UserProfile.objects.update_or_create(user=cls.user, defaults={'main_character': cls.main_character})
- AuthUtils.connect_signals()
-
- 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)
-
- 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)
-
- 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')
- user = StateBackend().authenticate(token=t)
- self.assertNotEqual(user, self.user)
- self.assertEqual(user.username, 'Unclaimed_Character')
- self.assertEqual(user.profile.main_character, self.unclaimed_character)
-
- def test_authenticate_character_record(self):
- t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='4')
- record = OwnershipRecord.objects.create(user=self.old_user, character=self.unclaimed_character, owner_hash='4')
- user = StateBackend().authenticate(token=t)
- self.assertEqual(user, self.old_user)
- self.assertTrue(CharacterOwnership.objects.filter(owner_hash='4', user=self.old_user).exists())
- self.assertTrue(user.profile.main_character)
-
- def test_iterate_username(self):
- t = Token(character_id=self.unclaimed_character.character_id,
- character_name=self.unclaimed_character.character_name, character_owner_hash='3')
- username = StateBackend().authenticate(token=t).username
- t.character_owner_hash = '4'
- username_1 = StateBackend().authenticate(token=t).username
- t.character_owner_hash = '5'
- username_2 = StateBackend().authenticate(token=t).username
- self.assertNotEqual(username, username_1, username_2)
- self.assertTrue(username_1.endswith('_1'))
- self.assertTrue(username_2.endswith('_2'))
-
-
class CharacterOwnershipTestCase(TestCase):
@classmethod
def setUpTestData(cls):
@@ -378,30 +251,3 @@ class CharacterOwnershipCheckTestCase(TestCase):
filter.return_value.exists.return_value = False
check_character_ownership(self.ownership)
self.assertTrue(filter.return_value.delete.called)
-
-
-class ManagementCommandTestCase(TestCase):
- @classmethod
- def setUpTestData(cls):
- cls.user = AuthUtils.create_user('test user', disconnect_signals=True)
- AuthUtils.add_main_character(cls.user, 'test character', '1', '2', 'test corp', 'test')
- character = UserProfile.objects.get(user=cls.user).main_character
- CharacterOwnership.objects.create(user=cls.user, character=character, owner_hash='test')
-
- def setUp(self):
- self.stdout = StringIO()
-
- def test_ownership(self):
- call_command('checkmains', stdout=self.stdout)
- self.assertFalse(UserProfile.objects.filter(main_character__isnull=True).count())
- self.assertNotIn(self.user.username, self.stdout.getvalue())
- self.assertIn('All main characters', self.stdout.getvalue())
-
- def test_no_ownership(self):
- user = AuthUtils.create_user('v1 user', disconnect_signals=True)
- AuthUtils.add_main_character(user, 'v1 character', '10', '20', 'test corp', 'test')
- self.assertFalse(UserProfile.objects.filter(main_character__isnull=True).count())
-
- call_command('checkmains', stdout=self.stdout)
- self.assertEqual(UserProfile.objects.filter(main_character__isnull=True).count(), 1)
- self.assertIn(user.username, self.stdout.getvalue())
diff --git a/allianceauth/services/modules/discord/auth_hooks.py b/allianceauth/services/modules/discord/auth_hooks.py
index 9a30eb1e..46c266c6 100644
--- a/allianceauth/services/modules/discord/auth_hooks.py
+++ b/allianceauth/services/modules/discord/auth_hooks.py
@@ -33,7 +33,8 @@ class DiscordService(ServicesHook):
if self.user_has_account(user):
logger.debug('Deleting user %s %s account', user, self.name)
tasks.delete_user.apply_async(
- kwargs={'user_pk': user.pk}, priority=SINGLE_TASK_PRIORITY
+ kwargs={'user_pk': user.pk, 'notify_user': notify_user},
+ priority=SINGLE_TASK_PRIORITY
)
def render_services_ctrl(self, request):
diff --git a/allianceauth/services/modules/discord/tasks.py b/allianceauth/services/modules/discord/tasks.py
index 99514fcc..41de134b 100644
--- a/allianceauth/services/modules/discord/tasks.py
+++ b/allianceauth/services/modules/discord/tasks.py
@@ -6,7 +6,6 @@ from requests.exceptions import HTTPError
from django.contrib.auth.models import User
from django.db.models.query import QuerySet
-from allianceauth.authentication.models import UserProfile
from allianceauth.services.tasks import QueueOnce
from . import __title__
diff --git a/allianceauth/services/modules/discord/tests/test_auth_hooks.py b/allianceauth/services/modules/discord/tests/test_auth_hooks.py
index 0853d3df..4aeeae8e 100644
--- a/allianceauth/services/modules/discord/tests/test_auth_hooks.py
+++ b/allianceauth/services/modules/discord/tests/test_auth_hooks.py
@@ -3,6 +3,7 @@ from unittest.mock import patch
from django.test import TestCase, RequestFactory
from django.test.utils import override_settings
+from allianceauth.notifications.models import Notification
from allianceauth.tests.auth_utils import AuthUtils
from . import TEST_USER_NAME, TEST_USER_ID, add_permissions_to_members, MODULE_PATH
@@ -30,6 +31,7 @@ class TestDiscordService(TestCase):
self.service = DiscordService
add_permissions_to_members()
self.factory = RequestFactory()
+ Notification.objects.all().delete()
def test_service_enabled(self):
service = self.service()
@@ -89,16 +91,17 @@ class TestDiscordService(TestCase):
service = self.service()
service.sync_nicknames_bulk([self.member])
self.assertTrue(mock_update_nicknames_bulk.delay.called)
-
+
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
- def test_delete_user_is_member(self, mock_DiscordClient):
+ def test_delete_user_is_member(self, mock_DiscordClient):
mock_DiscordClient.return_value.remove_guild_member.return_value = True
- service = self.service()
- service.delete_user(self.member)
+ service = self.service()
+ service.delete_user(self.member, notify_user=True)
self.assertTrue(mock_DiscordClient.return_value.remove_guild_member.called)
- self.assertFalse(DiscordUser.objects.filter(user=self.member).exists())
+ self.assertFalse(DiscordUser.objects.filter(user=self.member).exists())
+ self.assertTrue(Notification.objects.filter(user=self.member).exists())
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
def test_delete_user_is_not_member(self, mock_DiscordClient):
diff --git a/allianceauth/services/modules/discord/tests/test_integration.py b/allianceauth/services/modules/discord/tests/test_integration.py
index 24f78bc4..908cf198 100644
--- a/allianceauth/services/modules/discord/tests/test_integration.py
+++ b/allianceauth/services/modules/discord/tests/test_integration.py
@@ -21,6 +21,7 @@ from django.test.utils import override_settings
from allianceauth.authentication.models import State
from allianceauth.eveonline.models import EveCharacter
+from allianceauth.notifications.models import Notification
from allianceauth.tests.auth_utils import AuthUtils
from . import (
@@ -97,6 +98,7 @@ def reset_testdata():
State.objects.all().delete()
EveCharacter.objects.all().delete()
AuthUtils.connect_signals()
+ Notification.objects.all().delete()
@patch(MODULE_PATH + '.models.DISCORD_GUILD_ID', TEST_GUILD_ID)
@@ -109,9 +111,10 @@ class TestServiceFeatures(TransactionTestCase):
super().setUpClass()
cls.maxDiff = None
-
def setUp(self):
- """All tests: Given a user with member state, service permission and active Discord account"""
+ """All tests: Given a user with member state,
+ service permission and active Discord account
+ """
clear_cache()
reset_testdata()
self.group_charlie = Group.objects.create(name='charlie')
@@ -200,8 +203,7 @@ class TestServiceFeatures(TransactionTestCase):
# should not have called the API
requests_made = [
- requests_made.append(DiscordRequest(r.method, r.url))
- for r in requests_mocker.request_history
+ DiscordRequest(r.method, r.url) for r in requests_mocker.request_history
]
self.assertListEqual(requests_made, list())
@@ -230,7 +232,10 @@ class TestServiceFeatures(TransactionTestCase):
requests_made = [
DiscordRequest(r.method, r.url) for r in requests_mocker.request_history
]
- self.assertIn(remove_guild_member_request, requests_made)
+ self.assertIn(remove_guild_member_request, requests_made)
+
+ # verify user has been notified
+ self.assertTrue(Notification.objects.filter(user=self.user).exists())
def test_when_member_changes_to_blue_state_then_roles_are_updated_accordingly(
self, requests_mocker
@@ -238,7 +243,7 @@ class TestServiceFeatures(TransactionTestCase):
# request mocks
requests_mocker.get(
guild_member_request.url,
- json={'user': create_user_info(),'roles': ['3', '13', '99']}
+ json={'user': create_user_info(), 'roles': ['3', '13', '99']}
)
requests_mocker.get(
guild_roles_request.url,
@@ -322,7 +327,7 @@ class TestServiceFeatures(TransactionTestCase):
self.user.groups.add(self.group_charlie)
self.user.refresh_from_db()
- # verify roles for user where updated
+ # verify roles for user where updated
roles_updated = False
for r in requests_mocker.request_history:
my_request = DiscordRequest(r.method, r.url)
@@ -346,8 +351,14 @@ class StateTestCase(TestCase):
reset_testdata()
self.user = AuthUtils.create_user('test_user', disconnect_signals=True)
- AuthUtils.add_main_character(self.user, 'Perm Test Character', '99', corp_id='100', alliance_id='200',
- corp_name='Perm Test Corp', alliance_name='Perm Test Alliance')
+ AuthUtils.add_main_character(
+ self.user,
+ 'Perm Test Character', '99',
+ corp_id='100',
+ alliance_id='200',
+ corp_name='Perm Test Corp',
+ alliance_name='Perm Test Alliance'
+ )
self.test_character = EveCharacter.objects.get(character_id='99')
self.member_state = State.objects.create(
name='Test Member',
@@ -358,7 +369,9 @@ class StateTestCase(TestCase):
self.member_state.member_characters.add(self.test_character)
def _add_discord_user(self):
- self.discord_user = DiscordUser.objects.create(user=self.user, uid="12345678910")
+ self.discord_user = DiscordUser.objects.create(
+ user=self.user, uid="12345678910"
+ )
def _refresh_user(self):
self.user = User.objects.get(pk=self.user.pk)
@@ -636,4 +649,3 @@ class TestUserFeatures(WebTest):
# check we got can see the page and the "link server" button
self.assertEqual(response.status_int, 200)
self.assertIsNotNone(response.html.find(id='btnLinkDiscordServer'))
-
\ No newline at end of file