from __future__ import annotations from dataclasses import dataclass from datetime import datetime from enum import Enum, IntFlag class FileMime(Enum): AUDIO_OGG = 'audio/ogg' IMAGE_JPEG = 'image/jpeg' IMAGE_PNG = 'image/png' IMAGE_SVG = 'image/svg' JSON = 'application/json' PDF = 'application/pdf' TEXT_CSV = 'text/csv' TEXT_HTML = 'text/html' TEXT_MARKDOWN = 'text/markdown' TEXT_PLAIN = 'text/plain' VIDEO_MP4 = 'video/mp4' VIDEO_MPEG = 'video/mpeg' VIDEO_WEBM = 'video/webm' ZIP = 'application/zip' class ChannelType(Enum): GUILD_TEXT = 0 DM = 1 GUILD_VOICE = 2 GROUP_DM = 3 GUILD_CATEGORY = 4 GUILD_ANNOUNCEMENT = 5 ANNOUNCEMENT_THREAD = 10 PUBLIC_THREAD = 11 PRIVATE_THREAD = 12 GUILD_STAGE_VOICE = 13 GUILD_DIRECTORY = 14 GUILD_FORUM = 15 GUILD_MEDIA = 16 class ChannelFlags(IntFlag): # this thread is pinned to the top of its parent GUILD_FORUM or GUILD_MEDIA channel PINNED = 1 << 1 # whether a tag is required to be specified when creating a thread in a GUILD_FORUM or a GUILD_MEDIA channel. # Tags are specified in the applied_tags field. REQUIRE_TAG = 1 << 4 # when set hides the embedded media download options. Available only for media channels HIDE_MEDIA_DOWNLOAD_OPTIONS = 1 << 15 class OverwriteType(Enum): ROLE = 0 MEMBER = 1 class Permissions(IntFlag): NONE = 0 # Allows creation of instant invites CREATE_INSTANT_INVITE = 1 # Allows kicking members KICK_MEMBERS = 1 << 1 # Allows banning members BAN_MEMBERS = 1 << 2 # Allows all permissions and bypasses channel permission overwrites ADMINISTRATOR = 1 << 3 # Allows management and editing of channels MANAGE_CHANNELS = 1 << 4 # Allows management and editing of the guild MANAGE_GUILD = 1 << 5 # Allows for adding new reactions to messages. # This permission does not apply to reacting with an existing reaction on a message. ADD_REACTIONS = 1 << 6 # Allows for viewing of audit logs VIEW_AUDIT_LOG = 1 << 7 # Allows for using priority speaker in a voice channel PRIORITY_SPEAKER = 1 << 8 # Allows the user to go live STREAM = 1 << 9 # Allows guild members to view a channel, # which includes reading messages in text channels and joining voice channels VIEW_CHANNEL = 1 << 10 # Allows for sending messages in a channel and creating threads in a forum # (does not allow sending messages in threads) SEND_MESSAGES = 1 << 11 # Allows for sending of /tts messages SEND_TTS_MESSAGES = 1 << 12 # Allows for deletion of other users messages MANAGE_MESSAGES = 1 << 13 # Links sent by users with this permission will be auto-embedded EMBED_LINKS = 1 << 14 # Allows for uploading images and files ATTACH_FILES = 1 << 15 # Allows for reading of message history READ_MESSAGE_HISTORY = 1 << 16 # Allows for using the @everyone tag to notify all users in a channel, # and the @here tag to notify all online users in a channel MENTION_EVERYONE = 1 << 17 # Allows the usage of custom emojis from other servers USE_EXTERNAL_EMOJIS = 1 << 18 # Allows for viewing guild insights VIEW_GUILD_INSIGHTS = 1 << 19 # Allows for joining of a voice channel CONNECT = 1 << 20 # Allows for speaking in a voice channel SPEAK = 1 << 21 # Allows for muting members in a voice channel MUTE_MEMBERS = 1 << 22 # Allows for deafening of members in a voice channel DEAFEN_MEMBERS = 1 << 23 # Allows for moving of members between voice channels MOVE_MEMBERS = 1 << 24 # Allows for using voice-activity-detection in a voice channel USE_VAD = 1 << 25 # Allows for modification of own nickname CHANGE_NICKNAME = 1 << 26 # Allows for modification of other users nicknames MANAGE_NICKNAMES = 1 << 27 # Allows management and editing of roles MANAGE_ROLES = 1 << 28 # Allows management and editing of webhooks MANAGE_WEBHOOKS = 1 << 29 # Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users MANAGE_GUILD_EXPRESSIONS = 1 << 30 # Allows members to use application commands, including slash commands and context menu commands. USE_APPLICATION_COMMANDS = 1 << 31 # Allows for requesting to speak in stage channels. (This permission is under active development # and may be changed or removed.) REQUEST_TO_SPEAK = 1 << 32 # Allows for editing and deleting scheduled events created by all users MANAGE_EVENTS = 1 << 33 # Allows for deleting and archiving threads, and viewing all private threads MANAGE_THREADS = 1 << 34 # Allows for creating public and announcement threads CREATE_PUBLIC_THREADS = 1 << 35 # Allows for creating private threads CREATE_PRIVATE_THREADS = 1 << 36 # Allows the usage of custom stickers from other servers USE_EXTERNAL_STICKERS = 1 << 37 # Allows for sending messages in threads SEND_MESSAGES_IN_THREADS = 1 << 38 # Allows for using Activities (applications with the EMBEDDED flag) USE_EMBEDDED_ACTIVITIES = 1 << 39 # Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, # and from speaking in voice and stage channels MODERATE_MEMBERS = 1 << 40 # Allows for viewing role subscription insights VIEW_CREATOR_MONETIZATION_ANALYTICS = 1 << 41 # Allows for using soundboard in a voice channel USE_SOUNDBOARD = 1 << 42 # Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created # by the current user. Not yet available to developers, see changelog. CREATE_GUILD_EXPRESSIONS = 1 << 43 # Allows for creating scheduled events, and editing and deleting those created by the current user. # Not yet available to developers, see changelog. CREATE_EVENTS = 1 << 44 # Allows the usage of custom soundboard sounds from other servers USE_EXTERNAL_SOUNDS = 1 << 45 # Allows sending voice messages SEND_VOICE_MESSAGES = 1 << 46 # Allows sending polls SEND_POLLS = 1 << 49 # Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps # but the responses will be ephemeral. This only applies to apps not also installed to the server. USE_EXTERNAL_APPS = 1 << 50 # Allows pinning and unpinning messages PIN_MESSAGES = 1 << 51 @dataclass class Overwrite: id: int type: OverwriteType allow: Permissions deny: Permissions @staticmethod def from_dict(info: dict) -> Overwrite: return Overwrite( id=int(info['id']), type=OverwriteType(info['type']), allow=Permissions(int(info['allow'])), deny=Permissions(int(info['deny']))) @dataclass class ChannelCategory: id: int guild_id: int position: int permission_overwrites: list[Overwrite] name: str | None parent_id: int | None flags: ChannelFlags @staticmethod def from_dict(info: dict) -> ChannelCategory: parent_id: str | None = info.get('parent_id') return ChannelCategory( id=int(info['id']), guild_id=int(info['guild_id']), position=int(info['position']), permission_overwrites=[Overwrite.from_dict(o) for o in info['permission_overwrites']], name=info.get('name'), parent_id=int(parent_id) if parent_id is not None else None, flags=ChannelFlags(info['flags'])) @dataclass class TextChannel: id: int guild_id: int position: int permission_overwrites: list[Overwrite] name: str | None topic: str | None nsfw: bool last_message_id: int | None rate_limit_per_user: int parent_id: int | None last_pin_timestamp: datetime | None flags: ChannelFlags @staticmethod def from_dict(info: dict) -> TextChannel: parent_id: str | None = info.get('parent_id') last_message_id: str | None = info.get('last_message_id') last_pin_timestamp: str | None = info.get('last_pin_timestamp') return TextChannel( id=int(info['id']), guild_id=int(info['guild_id']), position=int(info['position']), permission_overwrites=[Overwrite.from_dict(o) for o in info['permission_overwrites']], name=info.get('name'), topic=info.get('topic'), nsfw=info['nsfw'], last_message_id=int(last_message_id) if last_message_id is not None else None, rate_limit_per_user=int(info['rate_limit_per_user']), parent_id=int(parent_id) if parent_id is not None else None, last_pin_timestamp=(datetime.fromisoformat(last_pin_timestamp) if last_pin_timestamp is not None else None), flags=ChannelFlags(info['flags'])) @dataclass class User: # TODO : complete attributes id: int username: str discriminator: str global_name: str | None @staticmethod def from_dict(info: dict) -> User: return User( id=int(info['id']), username=info['username'], discriminator=info['discriminator'], global_name=info.get('global_name')) @dataclass class Message: # TODO : complete attributes id: int channel_id: int author: User content: str timestamp: datetime edited_timestamp: datetime | None @staticmethod def from_dict(info: dict) -> Message: edited_timestamp: str | None = info.get('edited_timestamp') return Message( id=int(info['id']), channel_id=int(info['channel_id']), author=(User.from_dict(info['author']) if info.get('webhook_id') is None else User( id=info['webhook_id'], username='webhook', discriminator='webhook', global_name=None)), content=info['content'], timestamp=datetime.fromisoformat(info['timestamp']), edited_timestamp=datetime.fromisoformat(edited_timestamp) if edited_timestamp is not None else None) @dataclass class RoleColors: primary_color: int seconday_color: int | None tertiary_color: int | None @staticmethod def from_dict(info: dict) -> RoleColors: seconday_color = info.get('secondary_color') tertiary_color = info.get('tertiary_color') return RoleColors( primary_color=int(info['primary_color']), seconday_color=int(seconday_color) if seconday_color is not None else None, tertiary_color=int(tertiary_color) if tertiary_color is not None else None) class RoleFlags(IntFlag): NONE = 0 # role can be selected by members in an onboarding prompt IN_PROMPT = 1 @dataclass class RoleTags: bot_id: int | None intergration_id: int | None premium_subscriber: bool subcription_listing_id: int | None available_for_purchase: bool guild_connections: bool @staticmethod def from_dict(info: dict) -> RoleTags: bot_id = info.get('bot_id') intergration_id = info.get('intergration_id') subcription_listing_id = info.get('subcription_listing_id') return RoleTags( bot_id=int(bot_id) if bot_id is not None else None, intergration_id=int(intergration_id) if intergration_id is not None else None, premium_subscriber='premium_subscriber' in info, subcription_listing_id=int(subcription_listing_id) if subcription_listing_id is not None else None, available_for_purchase='available_for_purchase' in info, guild_connections='guild_connections' in info) @dataclass class Role: id: int # role id name: str # role name color: int # Deprecated integer representation of hexadecimal color code colors: RoleColors # the role's colors hoist: bool # if this role is pinned in the user listing icon: str | None # role icon hash unicode_emoji: str | None # role unicode emoji position: int # position of this role (roles with the same position are sorted by id) permissions: Permissions # permission bit set managed: bool # whether this role is managed by an integration mentionable: bool # whether this role is mentionable tags: RoleTags | None # the tags this role has flags: int # role flags combined as a bitfield @staticmethod def from_dict(info: dict) -> Role: tags = info.get('tags') return Role( id=int(info['id']), name=info['name'], color=int(info['color']), colors=RoleColors.from_dict(info['colors']), hoist=info['hoist'], icon=info.get('icon'), unicode_emoji=info.get('unicode_emoji'), position=int(info['position']), permissions=Permissions(int(info['permissions'])), managed=info['managed'], mentionable=info['mentionable'], tags=RoleTags.from_dict(tags) if tags is not None else None, flags=RoleFlags(int(info['flags'])) )