Source code for melisa.models.guild.member

# Copyright MelisaDev 2022 - Present
# Full MIT License can be found in `LICENSE.txt` at the project root.

from __future__ import annotations

import datetime
from dataclasses import dataclass
from typing import List, Dict, Optional, Union

from melisa.utils.timestamp import Timestamp
from melisa.utils.snowflake import Snowflake
from melisa.models.user.user import User
from melisa.utils.types import APINullable, UNDEFINED
from melisa.utils.api_model import APIModelBase


[docs]@dataclass(repr=False) class GuildMember(APIModelBase): """ This model represents a guild member. **The field user won't be included in the member object attached to ``MESSAGE_CREATE`` and ``MESSAGE_UPDATE`` gateway events.** In ``GUILD_`` events, ``pending`` will always be included as true or false. In non ``GUILD_`` events which can only be triggered by non-``pending`` users, ``pending`` will not be included. Attributes ----------- user: :class:`~melisa.models.user.user.User` The user this guild member represents nick: Optional[:class:`str`] This user's guild nickname avatar: Optional[:class:`str`] The member's guild avatar hash role_ids: List[:class:`~melisa.utils.snowflake.Snowflake`] List of role ids. joined_at: Optional[:class:`~melisa.utils.timestamp.Timestamp`] When the user joined the guild premium_since: Optional[:class:`~melisa.utils.timestamp.Timestamp`] When the user started boosting the guild is_deaf: :class:`bool` Whether the user is deafened in voice channels is_mute: :class:`bool` Whether the user is muted in voice channels pending: Optional[:class:`bool`] the user has not yet passed the guild's Membership Screening requirements permissions: Optional[:class:`str`] Total permissions of the member in the channel, including overwrites, returned when in the interaction object communication_disabled_until: Optional[:class:`~melisa.utils.timestamp.Timestamp`] When the user's timeout will expire and the user will be able to communicate in the guild again, null or a time in the past if the user is not timed out guild_id: List[:class:`~melisa.utils.snowflake.Snowflake`] The id of the guild this member belongs to. """ user: APINullable[User] = None nick: APINullable[str] = None guild_avatar: APINullable[str] = None role_ids: List[Snowflake] = None joined_at: APINullable[Timestamp] = None premium_since: APINullable[datetime.datetime] = None is_deaf: bool = None is_mute: bool = None is_pending: APINullable[bool] = None permissions: APINullable[str] = None communication_disabled_until: APINullable[datetime.datetime] = None guild_id: APINullable[Snowflake] = None
[docs] def make_guild_avatar_url(self, size: int = 1024) -> str: # ToDo: Add extensions parameter """User guild avatar url (from the Discord CDN server) Parameters ---------- size: int The size to set for the URL, defaults to 1024. Can be any power of two between 16 and 4096. """ return "https://cdn.discordapp.com/guilds/{}/users/{}/avatars/{}.png?size={}".format( self.guild_id, self.user.id, self.guild_avatar, size )
[docs] @classmethod def from_dict(cls, data: Dict[str, any]) -> GuildMember: """Generate a guild member from the given data. Parameters ---------- data: :class:`dict` The dictionary to convert into a guild member. """ self: GuildMember = super().__new__(cls) self.user = ( User.from_dict(data["user"]) if data.get("user") is not None else None ) self.nick = data.get("nick") self.guild_avatar = data.get("avatar") self.role_ids = [Snowflake(x) for x in data.get("roles", [])] self.joined_at = ( Timestamp.parse(data["joined_at"]) if data.get("joined_at") is not None else None ) self.premium_since = ( Timestamp.parse(data["premium_since"]) if data.get("premium_since") is not None else None ) self.is_deaf = data.get("deaf") self.is_mute = data.get("mute") self.is_pending = data.get("pending") self.permissions = data.get("permissions") self.communication_disabled_until = ( Timestamp.parse(data["communication_disabled_until"]) if data.get("communication_disabled_until") is not None else None ) self.guild_id = data.get("guild_id") return self
[docs] async def timeout( self, *, duration: Optional[float] = None, until: Optional[datetime.datetime] = None, ): """|coro| Times out the member from the guild; until then, the member will not be able to interact with the guild. **Required permissions:** ``MODERATE_MEMBERS`` duration: Optional[class:`float`] The duration (seconds) of the member's timeout. Set to ``None`` to remove the timeout. Supports up to 28 days in the future. until: Optional[:class:`datetime.datetime`] The expiry date/time of the member's timeout. Set to ``None`` to remove the timeout. Supports up to 28 days in the future. Raises ------- HTTPException The request to perform the action failed with other http exception. ForbiddenError You do not have proper permissions to do the actions required. BadRequestError You provided a wrong type of argument/ Returns ------- :class:`~melisa.models.guild.member.GuildMember` This member object. """ if duration is None and until is None: await self._client.rest.modify_guild_member( self.guild_id, self.user.id, communication_disabled_until=None ) elif duration is not None: await self._client.rest.modify_guild_member( self.guild_id, self.user.id, communication_disabled_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=duration), ) else: await self._client.rest.modify_guild_member( self.guild_id, self.user.id, communication_disabled_until=until ) return self
[docs] async def kick( self, *, reason: Optional[str] = None, ): """|coro| Kicks member from a guild. **Required permissions:** ``KICK_MEMBERS`` Parameters ---------- reason: Optional[:class:`str`] The reason of the action. Raises ------- HTTPException The request to perform the action failed with other http exception. ForbiddenError You do not have proper permissions to do the actions required. """ await self._client.rest.remove_guild_member( self.guild_id, self.user.id, reason=reason )
[docs] async def ban( self, *, delete_message_days: Optional[int] = 0, reason: Optional[str] = None, ): """|coro| Ban guild member, and optionally delete previous messages sent by the banned user. **Required permissions:** ``BAN_MEMBERS`` Parameters ---------- delete_message_days: Optional[:class:`int`] Number of days to delete messages for (0-7) reason: Optional[:class:`str`] The reason of the action. Raises ------- HTTPException The request to perform the action failed with other http exception. ForbiddenError You do not have proper permissions to do the actions required. BadRequestError You provided a wrong guild, user or something else """ await self._client.rest.create_guild_ban( self.guild_id, self.user.id, delete_message_days=delete_message_days, reason=reason, )
[docs] async def add_role( self, role_id: Union[Snowflake, str, int], *, reason: Optional[str] = None, ): """|coro| Add a role to a guild member. **Required permissions:** ``MANAGE_ROLES`` Parameters ---------- role_id: Optional[:class:`int`] Id of role to add. reason: Optional[:class:`str`] The reason of the action. Raises ------- HTTPException The request to perform the action failed with other http exception. ForbiddenError You do not have proper permissions to do the actions required. BadRequestError You provided a wrong guild, user or something else """ await self._client.rest.add_guild_member_role( self.guild_id, self.user.id, role_id, reason=reason )
[docs] async def remove_role( self, role_id: Union[Snowflake, str, int], *, reason: Optional[str] = None, ): """|coro| Add a role to remove from a guild member. **Required permissions:** ``MANAGE_ROLES`` Parameters ---------- role_id: Optional[:class:`int`] Id of role to remove. reason: Optional[:class:`str`] The reason of the action. Raises ------- HTTPException The request to perform the action failed with other http exception. ForbiddenError You do not have proper permissions to do the actions required. BadRequestError You provided a wrong guild, user or something else """ await self._client.rest.remove_guild_member_role( self.guild_id, self.user.id, role_id, reason=reason )
[docs] def avatar_url(self, *, size: int = 1024, image_format: str = None) -> str | None: # ToDo: Add Docstrings """Avatar url (from the Discord CDN server)""" if self.guild_avatar is None: return self.user.avatar_url() return self._client.rest.cdn.guild_member_avatar_url( self.guild_id, self.user.id, self.guild_avatar, size=size, image_format=image_format, )