Discord service major overhaul

This commit is contained in:
Erik Kalkoken
2020-05-18 01:01:13 +00:00
committed by Ariel Rin
parent 53f1b94475
commit 38083ed284
42 changed files with 4859 additions and 1151 deletions

View File

@@ -1,18 +1,179 @@
import logging
from requests.exceptions import HTTPError
from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import gettext_lazy
from allianceauth.notifications import notify
from . import __title__
from .app_settings import DISCORD_GUILD_ID
from .discord_client import DiscordClient, DiscordApiBackoff
from .managers import DiscordUserManager
from .utils import LoggerAddTag
logger = LoggerAddTag(logging.getLogger(__name__), __title__)
class DiscordUser(models.Model):
user = models.OneToOneField(User,
primary_key=True,
on_delete=models.CASCADE,
related_name='discord')
uid = models.CharField(max_length=254)
def __str__(self):
return "{} - {}".format(self.user.username, self.uid)
USER_RELATED_NAME = 'discord'
user = models.OneToOneField(
User,
primary_key=True,
on_delete=models.CASCADE,
related_name=USER_RELATED_NAME,
help_text='Auth user owning this Discord account'
)
uid = models.BigIntegerField(
db_index=True,
help_text='user\'s ID on Discord'
)
username = models.CharField(
max_length=32,
default='',
blank=True,
db_index=True,
help_text='user\'s username on Discord'
)
discriminator = models.CharField(
max_length=4,
default='',
blank=True,
help_text='user\'s discriminator on Discord'
)
activated = models.DateTimeField(
default=None,
null=True,
blank=True,
help_text='Date & time this service account was activated'
)
objects = DiscordUserManager()
class Meta:
permissions = (
("access_discord", u"Can access the Discord service"),
("access_discord", "Can access the Discord service"),
)
def __str__(self):
return f'{self.user.username} - {self.uid}'
def __repr__(self):
return f'{type(self).__name__}(user=\'{self.user}\', uid={self.uid})'
def update_nickname(self) -> bool:
"""Update nickname with formatted name of main character
Returns:
- True on success
- None if user is no longer a member of the Discord server
- False on error or raises exception
"""
requested_nick = DiscordUser.objects.user_formatted_nick(self.user)
if requested_nick:
client = DiscordUser.objects._bot_client()
success = client.modify_guild_member(
guild_id=DISCORD_GUILD_ID,
user_id=self.uid,
nick=requested_nick
)
if success:
logger.info('Nickname for %s has been updated', self.user)
else:
logger.warning('Failed to update nickname for %s', self.user)
return success
else:
return False
def update_groups(self) -> bool:
"""update groups for a user based on his current group memberships.
Will add or remove roles of a user as needed.
Returns:
- True on success
- None if user is no longer a member of the Discord server
- False on error or raises exception
"""
role_names = DiscordUser.objects.user_group_names(self.user)
client = DiscordUser.objects._bot_client()
requested_role_ids = self._guild_get_or_create_role_ids(client, role_names)
logger.debug(
'Requested to update groups for user %s: %s', self.user, requested_role_ids
)
success = client.modify_guild_member(
guild_id=DISCORD_GUILD_ID,
user_id=self.uid,
role_ids=requested_role_ids
)
if success:
logger.info('Groups for %s have been updated', self.user)
else:
logger.warning('Failed to update groups for %s', self.user)
return success
def delete_user(
self, notify_user: bool = False, is_rate_limited: bool = True
) -> bool:
"""Deletes the Discount user both on the server and locally
Params:
- notify_user: When True will sent a notification to the user
informing him about the deleting of his account
- is_rate_limited: When False will disable default rate limiting (use with care)
Returns True when successful, otherwise False or raises exceptions
Return None if user does no longer exist
"""
try:
client = DiscordUser.objects._bot_client(is_rate_limited=is_rate_limited)
success = client.remove_guild_member(
guild_id=DISCORD_GUILD_ID, user_id=self.uid
)
if success is not False:
deleted_count, _ = self.delete()
if deleted_count > 0:
if notify_user:
notify(
user=self.user,
title=gettext_lazy('Discord Account Disabled'),
message=gettext_lazy(
'Your Discord account was disabeled automatically '
'by Auth. If you think this was a mistake, '
'please contact an admin.'
),
level='warning'
)
logger.info('Account for user %s was deleted.', self.user)
return True
else:
logger.debug('Account for user %s was already deleted.', self.user)
return None
else:
logger.warning(
'Failed to remove user %s from the Discord server', self.user
)
return False
except (HTTPError, ConnectionError, DiscordApiBackoff) as ex:
logger.exception(
'Failed to remove user %s from Discord server: %s', self.user, ex
)
return False
@staticmethod
def _guild_get_or_create_role_ids(client: DiscordClient, role_names: list) -> list:
"""wrapper for DiscordClient.match_guild_roles_to_names()
that only returns the list of IDs
"""
return [
x[0]['id'] for x in client.match_guild_roles_to_names(
guild_id=DISCORD_GUILD_ID, role_names=role_names
)
]