import logging from dataclasses import dataclass from typing import List, Union from bson import ObjectId, Regex from classes.errors import GuildAlreadyExistsError, GuildNotFoundError from classes.pycord_challenge import PycordChallenge from classes.pycord_guild_channels import PycordGuildChannels from classes.pycord_guild_roles import PycordGuildRoles from modules.database import col_guilds logger = logging.getLogger(__name__) @dataclass class PycordGuild: """Dataclass of DB entry of a member""" __slots__ = ("_id", "id", "channels", "roles") _id: ObjectId id: int channels: PycordGuildChannels roles: PycordGuildRoles @classmethod async def find(cls, id: Union[int, ObjectId]): """Find guild in the database. ### Args: * id (`Union[int, ObjectId]`): Guild's Discord ID ### Raises: * `GuildNotFoundError`: Raised when guild entry could not be found. ### Returns: * `PycordGuild`: Guild with its database data. """ db_entry = await col_guilds.find_one( ({"id": id} if isinstance(id, int) else {"_id": id}) ) if not db_entry: raise GuildNotFoundError(id) db_entry["channels"] = PycordGuildChannels(**db_entry["channels"]) db_entry["roles"] = PycordGuildRoles(**db_entry["roles"]) return cls(**db_entry) @classmethod async def create( cls, id: int, channels: PycordGuildChannels = PycordGuildChannels(), roles: PycordGuildRoles = PycordGuildRoles(), ): if await col_guilds.find_one({"id": id}): raise GuildAlreadyExistsError(id) guild = {"id": id, "channels": channels.dict(), "roles": roles.dict()} inserted = await col_guilds.insert_one(guild) guild["_id"] = inserted.inserted_id return cls(**guild) def is_valid(self) -> bool: """Check if all attributes are valid and return boolean of that. ### Returns: * `bool`: `True` if all attributes are valid and `False` if not """ return bool(self.id and self.channels.is_valid() and self.roles.is_valid()) async def add_challenge( self, challenge: str, answers: List[Regex], enabled: bool ) -> PycordChallenge: """Create new guild's challenge entry in a database. ### Args: * challenge (`str`): Challenge text * answers (`List[Regex]`): List of regex patterns that are answers to the challenge * enabled (`bool`, *optional*): Whether the challenge is enabled. Defaults to `True`. ### Returns: * `PycordChallenge`: The challenge object """ return await PycordChallenge.create( self._id, challenge, answers, enabled=enabled )