mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-12 05:50:16 +02:00
Fix state role not always updated due to lazy properties
This commit is contained in:
parent
3bab349d7b
commit
4d546f948d
@ -73,11 +73,17 @@ class UserProfile(models.Model):
|
|||||||
if commit:
|
if commit:
|
||||||
logger.info('Updating {} state to {}'.format(self.user, self.state))
|
logger.info('Updating {} state to {}'.format(self.user, self.state))
|
||||||
self.save(update_fields=['state'])
|
self.save(update_fields=['state'])
|
||||||
notify(self.user, _('State Changed'),
|
notify(
|
||||||
_('Your user state has been changed to %(state)s') % ({'state': state}),
|
self.user,
|
||||||
'info')
|
_('State Changed'),
|
||||||
|
_('Your user state has been changed to %(state)s')
|
||||||
|
% ({'state': state}),
|
||||||
|
'info'
|
||||||
|
)
|
||||||
from allianceauth.authentication.signals import state_changed
|
from allianceauth.authentication.signals import state_changed
|
||||||
state_changed.send(sender=self.__class__, user=self.user, state=self.state)
|
state_changed.send(
|
||||||
|
sender=self.__class__, user=self.user, state=self.state
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.user)
|
return str(self.user)
|
||||||
|
@ -23,9 +23,7 @@ def trigger_state_check(state):
|
|||||||
check_states = State.objects.filter(priority__lt=state.priority)
|
check_states = State.objects.filter(priority__lt=state.priority)
|
||||||
for profile in UserProfile.objects.filter(state__in=check_states):
|
for profile in UserProfile.objects.filter(state__in=check_states):
|
||||||
if state.available_to_user(profile.user):
|
if state.available_to_user(profile.user):
|
||||||
profile.state = state
|
profile.assign_state(state)
|
||||||
profile.save(update_fields=['state'])
|
|
||||||
state_changed.send(sender=state.__class__, user=profile.user, state=state)
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=State.member_characters.through)
|
@receiver(m2m_changed, sender=State.member_characters.through)
|
||||||
|
@ -70,6 +70,8 @@ class DiscordService(ServicesHook):
|
|||||||
tasks.update_nickname.apply_async(
|
tasks.update_nickname.apply_async(
|
||||||
kwargs={
|
kwargs={
|
||||||
'user_pk': user.pk,
|
'user_pk': user.pk,
|
||||||
|
# since the new nickname is not yet in the DB we need to
|
||||||
|
# provide it manually to the task
|
||||||
'nickname': DiscordUser.objects.user_formatted_nick(user)
|
'nickname': DiscordUser.objects.user_formatted_nick(user)
|
||||||
},
|
},
|
||||||
priority=SINGLE_TASK_PRIORITY
|
priority=SINGLE_TASK_PRIORITY
|
||||||
@ -90,10 +92,16 @@ class DiscordService(ServicesHook):
|
|||||||
tasks.update_all_groups.delay()
|
tasks.update_all_groups.delay()
|
||||||
|
|
||||||
def update_groups(self, user):
|
def update_groups(self, user):
|
||||||
logger.debug('Processing %s groups for %s', self.name, user)
|
logger.debug('Processing %s groups for %s', self.name, user)
|
||||||
if self.user_has_account(user):
|
if self.user_has_account(user):
|
||||||
tasks.update_groups.apply_async(
|
tasks.update_groups.apply_async(
|
||||||
kwargs={'user_pk': user.pk}, priority=SINGLE_TASK_PRIORITY
|
kwargs={
|
||||||
|
'user_pk': user.pk,
|
||||||
|
# since state changes may not yet be in the DB we need to
|
||||||
|
# provide the new state name manually to the task
|
||||||
|
'state_name': user.profile.state.name
|
||||||
|
},
|
||||||
|
priority=SINGLE_TASK_PRIORITY
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_groups_bulk(self, users: list):
|
def update_groups_bulk(self, users: list):
|
||||||
|
@ -127,9 +127,17 @@ class DiscordUserManager(models.Manager):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def user_group_names(user: User) -> list:
|
def user_group_names(user: User, state_name: str = None) -> list:
|
||||||
"""returns list of group names plus state the given user is a member of"""
|
"""returns list of group names plus state the given user is a member of"""
|
||||||
return [group.name for group in user.groups.all()] + [user.profile.state.name]
|
if not state_name:
|
||||||
|
state_name = user.profile.state.name
|
||||||
|
group_names = (
|
||||||
|
[group.name for group in user.groups.all()] + [state_name]
|
||||||
|
)
|
||||||
|
logger.debug(
|
||||||
|
"Group names for roles updates of user %s are: %s", user, group_names
|
||||||
|
)
|
||||||
|
return group_names
|
||||||
|
|
||||||
def user_has_account(self, user: User) -> bool:
|
def user_has_account(self, user: User) -> bool:
|
||||||
"""Returns True if the user has an Discord account, else False
|
"""Returns True if the user has an Discord account, else False
|
||||||
|
@ -96,10 +96,13 @@ class DiscordUser(models.Model):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def update_groups(self) -> bool:
|
def update_groups(self, state_name: str = None) -> bool:
|
||||||
"""update groups for a user based on his current group memberships.
|
"""update groups for a user based on his current group memberships.
|
||||||
Will add or remove roles of a user as needed.
|
Will add or remove roles of a user as needed.
|
||||||
|
|
||||||
|
Params:
|
||||||
|
- state_name: optional state name to be used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
- True on success
|
- True on success
|
||||||
- None if user is no longer a member of the Discord server
|
- None if user is no longer a member of the Discord server
|
||||||
@ -132,7 +135,9 @@ class DiscordUser(models.Model):
|
|||||||
requested_roles = match_or_create_roles_from_names(
|
requested_roles = match_or_create_roles_from_names(
|
||||||
client=client,
|
client=client,
|
||||||
guild_id=DISCORD_GUILD_ID,
|
guild_id=DISCORD_GUILD_ID,
|
||||||
role_names=DiscordUser.objects.user_group_names(self.user)
|
role_names=DiscordUser.objects.user_group_names(
|
||||||
|
user=self.user, state_name=state_name
|
||||||
|
)
|
||||||
)
|
)
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'Requested roles for user %s: %s', self.user, requested_roles.ids()
|
'Requested roles for user %s: %s', self.user, requested_roles.ids()
|
||||||
@ -148,13 +153,13 @@ class DiscordUser(models.Model):
|
|||||||
role_ids=list(new_roles.ids())
|
role_ids=list(new_roles.ids())
|
||||||
)
|
)
|
||||||
if success:
|
if success:
|
||||||
logger.info('Groups for %s have been updated', self.user)
|
logger.info('Roles for %s have been updated', self.user)
|
||||||
else:
|
else:
|
||||||
logger.warning('Failed to update groups for %s', self.user)
|
logger.warning('Failed to update roles for %s', self.user)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.info('No need to update groups for user %s', self.user)
|
logger.info('No need to update roles for user %s', self.user)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def update_username(self) -> bool:
|
def update_username(self) -> bool:
|
||||||
|
@ -6,6 +6,7 @@ from requests.exceptions import HTTPError
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
|
from allianceauth.authentication.models import UserProfile
|
||||||
from allianceauth.services.tasks import QueueOnce
|
from allianceauth.services.tasks import QueueOnce
|
||||||
|
|
||||||
from . import __title__
|
from . import __title__
|
||||||
@ -26,13 +27,14 @@ BULK_TASK_PRIORITY = 6
|
|||||||
@shared_task(
|
@shared_task(
|
||||||
bind=True, name='discord.update_groups', base=QueueOnce, max_retries=None
|
bind=True, name='discord.update_groups', base=QueueOnce, max_retries=None
|
||||||
)
|
)
|
||||||
def update_groups(self, user_pk: int) -> None:
|
def update_groups(self, user_pk: int, state_name: str = None) -> None:
|
||||||
"""Update roles on Discord for given user according to his current groups
|
"""Update roles on Discord for given user according to his current groups
|
||||||
|
|
||||||
Params:
|
Params:
|
||||||
- user_pk: PK of given user
|
- user_pk: PK of given user
|
||||||
"""
|
- state_name: optional state name to be used
|
||||||
_task_perform_user_action(self, user_pk, 'update_groups')
|
"""
|
||||||
|
_task_perform_user_action(self, user_pk, 'update_groups', state_name=state_name)
|
||||||
|
|
||||||
|
|
||||||
@shared_task(
|
@shared_task(
|
||||||
@ -76,6 +78,7 @@ def _task_perform_user_action(self, user_pk: int, method: str, **kwargs) -> None
|
|||||||
"""perform a user related action incl. managing all exceptions"""
|
"""perform a user related action incl. managing all exceptions"""
|
||||||
logger.debug("Starting %s for user with pk %s", method, user_pk)
|
logger.debug("Starting %s for user with pk %s", method, user_pk)
|
||||||
user = User.objects.get(pk=user_pk)
|
user = User.objects.get(pk=user_pk)
|
||||||
|
# logger.debug("user %s has state %s", user, user.profile.state)
|
||||||
if DiscordUser.objects.user_has_account(user):
|
if DiscordUser.objects.user_has_account(user):
|
||||||
logger.info("Running %s for user %s", method, user)
|
logger.info("Running %s for user %s", method, user)
|
||||||
try:
|
try:
|
||||||
|
@ -238,15 +238,21 @@ class TestServiceFeatures(TransactionTestCase):
|
|||||||
# request mocks
|
# request mocks
|
||||||
requests_mocker.get(
|
requests_mocker.get(
|
||||||
guild_member_request.url,
|
guild_member_request.url,
|
||||||
json={'user': create_user_info(),'roles': ['13', '99']}
|
json={'user': create_user_info(),'roles': ['3', '13', '99']}
|
||||||
)
|
)
|
||||||
requests_mocker.get(
|
requests_mocker.get(
|
||||||
guild_roles_request.url,
|
guild_roles_request.url,
|
||||||
json=[ROLE_ALPHA, ROLE_BRAVO, ROLE_MIKE, ROLE_MEMBER, ROLE_BLUE]
|
json=[
|
||||||
|
ROLE_ALPHA, ROLE_BRAVO, ROLE_CHARLIE, ROLE_MIKE, ROLE_MEMBER, ROLE_BLUE
|
||||||
|
]
|
||||||
)
|
)
|
||||||
requests_mocker.post(create_guild_role_request.url, json=ROLE_CHARLIE)
|
requests_mocker.post(create_guild_role_request.url, json=ROLE_CHARLIE)
|
||||||
requests_mocker.patch(modify_guild_member_request.url, status_code=204)
|
requests_mocker.patch(modify_guild_member_request.url, status_code=204)
|
||||||
|
|
||||||
|
AuthUtils.disconnect_signals()
|
||||||
|
self.user.groups.add(self.group_charlie)
|
||||||
|
AuthUtils.connect_signals()
|
||||||
|
|
||||||
# demote user to blue state
|
# demote user to blue state
|
||||||
self.blue_state.member_characters.add(self.main)
|
self.blue_state.member_characters.add(self.main)
|
||||||
self.member_state.member_characters.remove(self.main)
|
self.member_state.member_characters.remove(self.main)
|
||||||
@ -257,7 +263,7 @@ class TestServiceFeatures(TransactionTestCase):
|
|||||||
my_request = DiscordRequest(r.method, r.url)
|
my_request = DiscordRequest(r.method, r.url)
|
||||||
if my_request == modify_guild_member_request and "roles" in r.json():
|
if my_request == modify_guild_member_request and "roles" in r.json():
|
||||||
roles_updated = True
|
roles_updated = True
|
||||||
self.assertSetEqual(set(r.json()["roles"]), {13, 98})
|
self.assertSetEqual(set(r.json()["roles"]), {3, 13, 98})
|
||||||
break
|
break
|
||||||
|
|
||||||
self.assertTrue(roles_updated)
|
self.assertTrue(roles_updated)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user