mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-10 00:56:19 +01:00
Add update username feature
This commit is contained in:
@@ -117,6 +117,36 @@ class DiscordUser(models.Model):
|
||||
logger.warning('Failed to update groups for %s', self.user)
|
||||
return success
|
||||
|
||||
def update_username(self) -> bool:
|
||||
"""Updates the username incl. the discriminator
|
||||
from the Discord server and saves it
|
||||
|
||||
Returns:
|
||||
- True on success
|
||||
- None if user is no longer a member of the Discord server
|
||||
- False on error or raises exception
|
||||
"""
|
||||
|
||||
client = DiscordUser.objects._bot_client()
|
||||
user_info = client.guild_member(guild_id=DISCORD_GUILD_ID, user_id=self.uid)
|
||||
if user_info is None:
|
||||
success = None
|
||||
elif (
|
||||
user_info
|
||||
and 'user' in user_info
|
||||
and 'username' in user_info['user']
|
||||
and 'discriminator' in user_info['user']
|
||||
):
|
||||
self.username = user_info['user']['username']
|
||||
self.discriminator = user_info['user']['discriminator']
|
||||
self.save()
|
||||
logger.info('Username for %s has been updated', self.user)
|
||||
success = True
|
||||
else:
|
||||
logger.warning('Failed to update username for %s', self.user)
|
||||
success = False
|
||||
return success
|
||||
|
||||
def delete_user(
|
||||
self, notify_user: bool = False, is_rate_limited: bool = True
|
||||
) -> bool:
|
||||
|
||||
@@ -47,6 +47,18 @@ def update_nickname(self, user_pk: int) -> None:
|
||||
_task_perform_user_action(self, user_pk, 'update_nickname')
|
||||
|
||||
|
||||
@shared_task(
|
||||
bind=True, name='discord.update_username', base=QueueOnce, max_retries=None
|
||||
)
|
||||
def update_username(self, user_pk: int) -> None:
|
||||
"""Update locally stored Discord username from Discord server for given user
|
||||
|
||||
Params:
|
||||
- user_pk: PK of given user
|
||||
"""
|
||||
_task_perform_user_action(self, user_pk, 'update_username')
|
||||
|
||||
|
||||
@shared_task(
|
||||
bind=True, name='discord.delete_user', base=QueueOnce, max_retries=None
|
||||
)
|
||||
@@ -171,16 +183,45 @@ def _bulk_update_nicknames_for_users(discord_users_qs: QuerySet) -> None:
|
||||
chain(update_nicknames_chain).apply_async(priority=BULK_TASK_PRIORITY)
|
||||
|
||||
|
||||
@shared_task(name='discord.update_all_usernames')
|
||||
def update_all_usernames() -> None:
|
||||
"""Update all usernames for all known users with a Discord account."""
|
||||
discord_users_qs = DiscordUser.objects.all()
|
||||
_bulk_update_usernames_for_users(discord_users_qs)
|
||||
|
||||
|
||||
@shared_task(name='discord.update_usernames_bulk')
|
||||
def update_usernames_bulk(user_pks: list) -> None:
|
||||
"""Update usernames for list of users with a Discord account in bulk."""
|
||||
discord_users_qs = DiscordUser.objects\
|
||||
.filter(user__pk__in=user_pks)\
|
||||
.select_related()
|
||||
_bulk_update_usernames_for_users(discord_users_qs)
|
||||
|
||||
|
||||
def _bulk_update_usernames_for_users(discord_users_qs: QuerySet) -> None:
|
||||
logger.info(
|
||||
"Starting to bulk update discord usernames for %d users",
|
||||
discord_users_qs.count()
|
||||
)
|
||||
update_usernames_chain = list()
|
||||
for discord_user in discord_users_qs:
|
||||
update_usernames_chain.append(update_username.si(discord_user.user.pk))
|
||||
|
||||
chain(update_usernames_chain).apply_async(priority=BULK_TASK_PRIORITY)
|
||||
|
||||
|
||||
@shared_task(name='discord.update_all')
|
||||
def update_all() -> None:
|
||||
"""Updates groups and nicknames (when activated) for all users."""
|
||||
discord_users_qs = DiscordUser.objects.all()
|
||||
logger.info(
|
||||
'Starting to bulk update all %s Discord users', discord_users_qs.count()
|
||||
'Starting to bulk update all for %s Discord users', discord_users_qs.count()
|
||||
)
|
||||
update_all_chain = list()
|
||||
for discord_user in discord_users_qs:
|
||||
update_all_chain.append(update_groups.si(discord_user.user.pk))
|
||||
update_all_chain.append(update_username.si(discord_user.user.pk))
|
||||
if DISCORD_SYNC_NAMES:
|
||||
update_all_chain.append(update_nickname.si(discord_user.user.pk))
|
||||
|
||||
|
||||
@@ -42,22 +42,11 @@ class TestBasicsAndHelpers(TestCase):
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
class TestUpdateNick(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user, uid=TEST_USER_ID
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def user_info(nick):
|
||||
return {
|
||||
'user': {
|
||||
'id': TEST_USER_ID,
|
||||
'username': TEST_USER_NAME
|
||||
},
|
||||
'nick': nick,
|
||||
'roles': [1, 2, 3]
|
||||
}
|
||||
|
||||
def test_can_update(self, mock_DiscordClient):
|
||||
AuthUtils.add_main_character_2(self.user, TEST_MAIN_NAME, TEST_MAIN_ID)
|
||||
@@ -74,9 +63,7 @@ class TestUpdateNick(TestCase):
|
||||
self.assertFalse(result)
|
||||
self.assertFalse(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
|
||||
def test_return_none_if_user_no_longer_a_member(
|
||||
self, mock_DiscordClient
|
||||
):
|
||||
def test_return_none_if_user_no_longer_a_member(self, mock_DiscordClient):
|
||||
AuthUtils.add_main_character_2(self.user, TEST_MAIN_NAME, TEST_MAIN_ID)
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = None
|
||||
|
||||
@@ -93,12 +80,94 @@ class TestUpdateNick(TestCase):
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
class TestUpdateUsername(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
|
||||
def setUp(self):
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user,
|
||||
uid=TEST_USER_ID,
|
||||
username=TEST_MAIN_NAME,
|
||||
discriminator='1234'
|
||||
)
|
||||
|
||||
def test_can_update(self, mock_DiscordClient):
|
||||
new_username = 'New name'
|
||||
new_discriminator = '9876'
|
||||
user_info = {
|
||||
'user': {
|
||||
'id': str(TEST_USER_ID),
|
||||
'username': new_username,
|
||||
'discriminator': new_discriminator,
|
||||
}
|
||||
}
|
||||
mock_DiscordClient.return_value.guild_member.return_value = user_info
|
||||
|
||||
result = self.discord_user.update_username()
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.guild_member.called)
|
||||
self.discord_user.refresh_from_db()
|
||||
self.assertEqual(self.discord_user.username, new_username)
|
||||
self.assertEqual(self.discord_user.discriminator, new_discriminator)
|
||||
|
||||
def test_return_none_if_user_no_longer_a_member(self, mock_DiscordClient):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = None
|
||||
result = self.discord_user.update_username()
|
||||
self.assertIsNone(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.guild_member.called)
|
||||
|
||||
def test_return_false_if_api_returns_false(self, mock_DiscordClient):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = False
|
||||
result = self.discord_user.update_username()
|
||||
self.assertFalse(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.guild_member.called)
|
||||
|
||||
def test_return_false_if_api_returns_corrput_data_1(self, mock_DiscordClient):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = {'invalid': True}
|
||||
result = self.discord_user.update_username()
|
||||
self.assertFalse(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.guild_member.called)
|
||||
|
||||
def test_return_false_if_api_returns_corrput_data_2(self, mock_DiscordClient):
|
||||
user_info = {
|
||||
'user': {
|
||||
'id': str(TEST_USER_ID),
|
||||
'discriminator': '1234',
|
||||
}
|
||||
}
|
||||
mock_DiscordClient.return_value.guild_member.return_value = user_info
|
||||
result = self.discord_user.update_username()
|
||||
self.assertFalse(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.guild_member.called)
|
||||
|
||||
def test_return_false_if_api_returns_corrput_data_3(self, mock_DiscordClient):
|
||||
user_info = {
|
||||
'user': {
|
||||
'id': str(TEST_USER_ID),
|
||||
'username': TEST_USER_NAME,
|
||||
}
|
||||
}
|
||||
mock_DiscordClient.return_value.guild_member.return_value = user_info
|
||||
result = self.discord_user.update_username()
|
||||
self.assertFalse(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.guild_member.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.models.notify')
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
class TestDeleteUser(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
|
||||
def setUp(self):
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user, uid=TEST_USER_ID
|
||||
)
|
||||
@@ -170,8 +239,12 @@ class TestDeleteUser(TestCase):
|
||||
@patch(MODULE_PATH + '.models.DiscordUser.objects.user_group_names')
|
||||
class TestUpdateGroups(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user, uid=TEST_USER_ID
|
||||
)
|
||||
|
||||
@@ -150,13 +150,29 @@ class TestUpdateNickname(TestCase):
|
||||
update_nickname_inner(mock_task, self.user.pk)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.DiscordUser.update_username')
|
||||
class TestUpdateUsername(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_member(TEST_USER_NAME)
|
||||
cls.discord_user = DiscordUser.objects.create(user=cls.user, uid=TEST_USER_ID)
|
||||
|
||||
def test_can_update_username(self, mock_update_username):
|
||||
mock_update_username.return_value = True
|
||||
|
||||
tasks.update_username(self.user.pk)
|
||||
self.assertTrue(mock_update_username.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.DiscordUser.delete_user')
|
||||
class TestDeleteUser(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_member('Peter Parker')
|
||||
cls.user = AuthUtils.create_member(TEST_USER_NAME)
|
||||
cls.discord_user = DiscordUser.objects.create(user=cls.user, uid=TEST_USER_ID)
|
||||
|
||||
def test_can_delete_user(self, mock_delete_user):
|
||||
@@ -270,11 +286,37 @@ class TestBulkTasks(TestCase):
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
@patch(MODULE_PATH + '.update_username.si')
|
||||
def test_can_update_username_for_multiple_users(self, mock_update_username):
|
||||
du_1 = DiscordUser.objects.create(user=self.user_1, uid=123)
|
||||
du_2 = DiscordUser.objects.create(user=self.user_2, uid=456)
|
||||
DiscordUser.objects.create(user=self.user_3, uid=789)
|
||||
expected_pks = [du_1.pk, du_2.pk]
|
||||
|
||||
tasks.update_usernames_bulk(expected_pks)
|
||||
self.assertEqual(mock_update_username.call_count, 2)
|
||||
current_pks = [args[0][0] for args in mock_update_username.call_args_list]
|
||||
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
@patch(MODULE_PATH + '.update_username.si')
|
||||
def test_can_update_all_usernames(self, mock_update_username):
|
||||
du_1 = DiscordUser.objects.create(user=self.user_1, uid=123)
|
||||
du_2 = DiscordUser.objects.create(user=self.user_2, uid=456)
|
||||
du_3 = DiscordUser.objects.create(user=self.user_3, uid=789)
|
||||
|
||||
tasks.update_all_usernames()
|
||||
self.assertEqual(mock_update_username.call_count, 3)
|
||||
current_pks = [args[0][0] for args in mock_update_username.call_args_list]
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
@patch(MODULE_PATH + '.DISCORD_SYNC_NAMES', True)
|
||||
@patch(MODULE_PATH + '.update_nickname')
|
||||
@patch(MODULE_PATH + '.update_groups')
|
||||
@patch(MODULE_PATH + '.update_username')
|
||||
def test_can_update_all_incl_nicknames(
|
||||
self, mock_update_groups, mock_update_nickname
|
||||
self, mock_update_usernames, mock_update_groups, mock_update_nickname
|
||||
):
|
||||
du_1 = DiscordUser.objects.create(user=self.user_1, uid=123)
|
||||
du_2 = DiscordUser.objects.create(user=self.user_2, uid=456)
|
||||
@@ -291,11 +333,17 @@ class TestBulkTasks(TestCase):
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
self.assertEqual(mock_update_usernames.si.call_count, 3)
|
||||
current_pks = [args[0][0] for args in mock_update_usernames.si.call_args_list]
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
@patch(MODULE_PATH + '.DISCORD_SYNC_NAMES', False)
|
||||
@patch(MODULE_PATH + '.update_nickname')
|
||||
@patch(MODULE_PATH + '.update_groups')
|
||||
@patch(MODULE_PATH + '.update_username')
|
||||
def test_can_update_all_excl_nicknames(
|
||||
self, mock_update_groups, mock_update_nickname
|
||||
self, mock_update_usernames, mock_update_groups, mock_update_nickname
|
||||
):
|
||||
du_1 = DiscordUser.objects.create(user=self.user_1, uid=123)
|
||||
du_2 = DiscordUser.objects.create(user=self.user_2, uid=456)
|
||||
@@ -308,3 +356,8 @@ class TestBulkTasks(TestCase):
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
self.assertEqual(mock_update_nickname.si.call_count, 0)
|
||||
|
||||
self.assertEqual(mock_update_usernames.si.call_count, 3)
|
||||
current_pks = [args[0][0] for args in mock_update_usernames.si.call_args_list]
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
Reference in New Issue
Block a user