mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-09 12:30:15 +02:00
130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
"""Core functionality of the Discord service not directly related to models."""
|
|
|
|
import logging
|
|
from typing import List, Optional, Tuple
|
|
|
|
from requests.exceptions import HTTPError
|
|
|
|
from django.contrib.auth.models import Group, User
|
|
|
|
from allianceauth.groupmanagement.models import ReservedGroupName
|
|
from allianceauth.services.hooks import NameFormatter
|
|
|
|
from . import __title__
|
|
from .app_settings import DISCORD_BOT_TOKEN, DISCORD_GUILD_ID
|
|
from .discord_client import DiscordClient, RolesSet, Role
|
|
from .discord_client.exceptions import DiscordClientException
|
|
from .utils import LoggerAddTag
|
|
|
|
logger = LoggerAddTag(logging.getLogger(__name__), __title__)
|
|
|
|
|
|
def create_bot_client(is_rate_limited: bool = True) -> DiscordClient:
|
|
"""Create new bot client for accessing the configured Discord server.
|
|
|
|
Args:
|
|
is_rate_limited: Set to False to turn off rate limiting (use with care).
|
|
|
|
Return:
|
|
Discord client instance
|
|
"""
|
|
return DiscordClient(DISCORD_BOT_TOKEN, is_rate_limited=is_rate_limited)
|
|
|
|
|
|
def calculate_roles_for_user(
|
|
user: User,
|
|
client: DiscordClient,
|
|
discord_uid: int,
|
|
state_name: str = None,
|
|
) -> Tuple[RolesSet, Optional[bool]]:
|
|
"""Calculate current Discord roles for an Auth user.
|
|
|
|
Takes into account reserved groups and existing managed roles (e.g. nitro).
|
|
|
|
Returns:
|
|
- Discord roles, changed flag:
|
|
- True when roles have changed,
|
|
- False when they have not changed,
|
|
- None if user is not a member of the guild
|
|
"""
|
|
roles_calculated = client.match_or_create_roles_from_names_2(
|
|
guild_id=DISCORD_GUILD_ID,
|
|
role_names=_user_group_names(user=user, state_name=state_name),
|
|
)
|
|
logger.debug("Calculated roles for user %s: %s", user, roles_calculated.ids())
|
|
roles_current = client.guild_member_roles(
|
|
guild_id=DISCORD_GUILD_ID, user_id=discord_uid
|
|
)
|
|
if roles_current is None:
|
|
logger.debug("User %s is not a member of the guild.", user)
|
|
return roles_calculated, None
|
|
logger.debug("Current roles user %s: %s", user, roles_current.ids())
|
|
reserved_role_names = ReservedGroupName.objects.values_list("name", flat=True)
|
|
roles_reserved = roles_current.subset(role_names=reserved_role_names)
|
|
roles_managed = roles_current.subset(managed_only=True)
|
|
roles_persistent = roles_managed.union(roles_reserved)
|
|
if roles_calculated == roles_current.difference(roles_persistent):
|
|
return roles_calculated, False
|
|
return roles_calculated.union(roles_persistent), True
|
|
|
|
|
|
def _user_group_names(user: User, state_name: str = None) -> List[str]:
|
|
"""Names of groups and state the given user is a member of."""
|
|
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_formatted_nick(user: User) -> Optional[str]:
|
|
"""Name of the given user's main character with name formatting applied.
|
|
|
|
Returns:
|
|
Name or ``None`` if user has no main.
|
|
"""
|
|
from .auth_hooks import DiscordService
|
|
|
|
if user.profile.main_character:
|
|
return NameFormatter(DiscordService(), user).format_name()
|
|
return None
|
|
|
|
|
|
def group_to_role(group: Group) -> Optional[Role]:
|
|
"""Fetch the Discord role matching the given Django group by name.
|
|
|
|
Returns:
|
|
Discord role or None if no matching role exist
|
|
"""
|
|
return default_bot_client.match_role_from_name(
|
|
guild_id=DISCORD_GUILD_ID, role_name=group.name
|
|
)
|
|
|
|
|
|
def server_name(use_cache: bool = True) -> str:
|
|
"""Fetches the name of the current Discord server.
|
|
|
|
Args:
|
|
use_cache: When set False will force an API call to get the server name
|
|
|
|
Returns:
|
|
Server name or an empty string if the name could not be retrieved
|
|
"""
|
|
try:
|
|
server_name = default_bot_client.guild_name(
|
|
guild_id=DISCORD_GUILD_ID, use_cache=use_cache
|
|
)
|
|
except (HTTPError, DiscordClientException):
|
|
server_name = ""
|
|
except Exception:
|
|
logger.warning(
|
|
"Unexpected error when trying to retrieve the server name from Discord",
|
|
exc_info=True,
|
|
)
|
|
server_name = ""
|
|
return server_name
|
|
|
|
|
|
# Default bot client to be used by modules of this package
|
|
default_bot_client = create_bot_client()
|