Source code for melisa.rest

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

import datetime
from typing import Union, Optional, List, Dict, Any, AsyncIterator

from aiohttp import FormData

from .models.interactions import ApplicationCommandType
from .models.interactions.commands import (
    SlashCommandOption,
    SlashCommand,
    PartialApplicationCommand,
    _choose_command_type,
)
from .models.interactions.i18n import LocalizedField
from .models.interactions.interactions import Interaction, InteractionResponse
from .models.message import Embed, File, AllowedMentions, Message
from .exceptions import EmbedFieldError
from .core.http import HTTPClient
from .utils import json, UNDEFINED
from .utils.snowflake import Snowflake
from .models.guild.guild import Guild
from .models.user.user import User
from .models.guild.emoji import Emoji
from .models.guild.channel import _choose_channel_type, Channel


def create_form(files: List[File]):
    """
    Creates an aiohttp payload from an array of File objects.
    """
    form = FormData()

    for index, file in enumerate(files):
        form.add_field(
            "file",
            file.filepath,
            filename=file.filename,
            content_type="application/octet-stream",
        )

    return form


def _build_message_data(
    *,
    content: str = None,
    tts: bool = False,
    embed: Embed = None,
    embeds: List[Embed] = None,
    file: File = None,
    files: List[File] = None,
    allowed_mentions: AllowedMentions = None,
    _client_allowed_mentions: AllowedMentions = None,
):
    if embeds is None:
        embeds = [embed] if embed is not None else []
    if files is None:
        files = [file] if file is not None else []

    payload = {
        "content": str(content) if content is not None else None,
        "embeds": [],
    }

    for _embed in embeds:
        if _embed.total_length() > 6000:
            raise EmbedFieldError.characters_from_desc(
                "Embed", embed.total_length(), 6000
            )
        payload["embeds"].append(_embed.to_dict())

    payload["tts"] = tts

    if allowed_mentions is not None:
        payload["allowed_mentions"] = allowed_mentions.to_dict()
    elif _client_allowed_mentions is not None:
        payload["allowed_mentions"] = _client_allowed_mentions.to_dict()

    if len(files) > 0:
        form_builder = create_form(files)
        return payload, form_builder

    return payload, None


[docs]class RESTApp: """ This instance may be used to send http requests to the Discord REST API. **It will not cache anything.** Parameters ---------- token: :class:`str` The token to authorize (you can found it in the developer portal) default_image_format: :class:`str` Default image format Attributes ----------- cdn: :class:`~melisa.rest.CDNBuilder` CDN Builder to build images """ def __init__(self, token: str, default_image_format: str = None): self._http: HTTPClient = HTTPClient(token) self.cdn = CDNBuilder(default_image_format)
[docs] async def fetch_user(self, user_id: Union[Snowflake, int, str]) -> User: """|coro| [**REST API**] Fetch User from the Discord API (by id). Parameters ---------- user_id: Union[:class:`~melisa.utils.snowflake.Snowflake`, str, int] Id of user to fetch """ data = await self._http.get(f"users/{user_id}") return User.from_dict(data)
[docs] async def fetch_guild(self, guild_id: Union[Snowflake, int, str]) -> Guild: """|coro| [**REST API**] Fetch Guild from the Discord API (by id). Parameters ---------- guild_id : Union[:class:`~melisa.utils.snowflake.Snowflake`, str, int] Id of guild to fetch """ data = await self._http.get(f"guilds/{guild_id}") return Guild.from_dict(data)
[docs] async def fetch_channel(self, channel_id: Union[Snowflake, str, int]) -> Channel: """|coro| [**REST API**] Fetch Channel from the Discord API (by id). Parameters ---------- channel_id : Union[:class:`~melisa.utils.snowflake.Snowflake`, str, int] Id of channel to fetch """ data = await self._http.get(f"channels/{channel_id}") return _choose_channel_type(data)
[docs] async def get_original_interaction_response( self, application_id: Union[Snowflake, str, int], interaction_token: str ) -> Message: """|coro| [**REST API**] Fetch Original Interaction Response from the Discord API. Parameters ---------- application_id : Union[:class:`~melisa.utils.snowflake.Snowflake`, str, int] Id of interaction to fetch interaction_token: str Interaction token """ data = await self._http.get( f"/webhooks/{application_id}/{interaction_token}/messages/@original" ) return Message.from_dict(data)
[docs] async def delete_original_interaction_response( self, application_id: Union[Snowflake, str, int], interaction_token: str ) -> Message: """|coro| [**REST API**] Delete Original Interaction Response. Parameters ---------- application_id : Union[:class:`~melisa.utils.snowflake.Snowflake`, str, int] Id of interaction to fetch interaction_token: str Interaction token """ await self._http.delete( f"/webhooks/{application_id}/{interaction_token}/messages/@original" )
[docs] async def delete_message( self, channel_id: Union[Snowflake, str, int], message_id: Union[Snowflake, str, int], *, reason: Optional[str] = None, ): """|coro| [**REST API**] Deletes only one specified message. Parameters ---------- channel_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of channel, where message should be deleted message_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of message to delete. reason: Optional[:class:`str`] The reason of the message delete operation. 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. (You must have ``MANAGE_MESSAGES`` permission) """ await self._http.delete( f"channels/{channel_id}/messages/{message_id}", headers={"X-Audit-Log-Reason": reason}, )
[docs] async def create_message( self, channel_id: Union[Snowflake, str, int], content: str = None, *, tts: bool = False, embed: Embed = None, embeds: List[Embed] = None, file: File = None, files: List[File] = None, allowed_mentions: AllowedMentions = None, delete_after: int = None, _client_allowed_mentions: AllowedMentions = None, ) -> Message: """|coro| [**REST API**] Create message. Sends a message to the destination with the content given. The content must be a type that can convert to a string through str(content). Parameters ---------- channel_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of channel where message should be sent content: Optional[:class:`str`] The content of the message to send. tts: Optional[:class:`bool`] Whether the message should be sent using text-to-speech. embed: Optional[:class:`~melisa.models.message.embed.Embed`] Embed embeds: Optional[List[:class:`~melisa.models.message.embed.Embed`]] List of embeds file: Optional[:class:`~melisa.models.message.file.File`] File files: Optional[List[:class:`~melisa.models.message.file.File`]] List of files allowed_mentions: Optional[:class:`~melisa.models.message.message.AllowedMentions`] Controls the mentions being processed in this message. delete_after: Optional[:class:`int`] Provided value must be an int. if provided, deletes message after some seconds. May raise ``ForbiddenError`` or ``NotFoundError``. Raises ------- HTTPException The request to perform the action failed with other http exception. ForbiddenError You do not have the proper permissions to send the message. BadRequestError Some of specified parameters is invalid. """ # ToDo: Add other parameters # ToDo: add file checks body, form_builder = _build_message_data( content=content, file=file, files=files, embed=embed, embeds=embeds, tts=tts, allowed_mentions=allowed_mentions, _client_allowed_mentions=_client_allowed_mentions, ) if form_builder is not None: form_builder.add_field("payload_json", json.dumps(body)) form = form_builder() message_data = Message.from_dict( await self._http.post( f"/channels/{channel_id}/messages", data=form, headers={"Content-Type": form.headers["Content-Type"]}, ) ) else: message_data = Message.from_dict( await self._http.post( f"/channels/{channel_id}/messages", json=body, headers={"Content-Type": "application/json"}, ) ) if delete_after: await message_data.delete(delay=delete_after) return message_data
[docs] async def get_channel_messages_history( self, channel_id: Union[Snowflake, str, int], limit: int = 50, *, before: Optional[Snowflake] = None, after: Optional[Snowflake] = None, around: Optional[Snowflake] = None, ) -> AsyncIterator[Message]: """|coro| [**REST API**] Fetch messages history. Returns a list of messages in this channel. Examples --------- Flattening messages into a list: :: messages = [message async for message in channel.history(limit=111)] All parameters are optional. Parameters ---------- channel_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of channel where messages should be fetched. limit : Optional[:class:`~.melisa.utils.snowflake.Snowflake`] Max number of messages to return (1-100). around : Optional[:class:`~.melisa.utils.snowflake.Snowflake`] Get messages around this message ID. before : Optional[:class:`~.melisa.utils.snowflake.Snowflake`] Get messages before this message ID. after : Optional[:class:`~.melisa.utils.snowflake.Snowflake`] Get messages after this message ID. 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. Returns ------- AsyncIterator[:class:`~melisa.models.message.message.Message`] An iterator of messages. """ # ToDo: Add check parameter if limit is None: limit = 100 while limit > 0: search_limit = min(limit, 100) raw_messages = await self._http.get( f"/channels/{channel_id}/messages", params={ "limit": search_limit, "before": before, "after": after, "around": around, }, ) if not raw_messages: break for message_data in raw_messages: yield Message.from_dict(message_data) before = raw_messages[-1]["id"] limit -= search_limit
[docs] async def fetch_message( self, channel_id: Union[Snowflake, int, str], message_id: Union[Snowflake, int, str], ) -> Message: """|coro| [**REST API**] Fetch message. Returns a specific message in the channel. Parameters ---------- message_id : Union[:class:`~.melisa.utils.snowflake.Snowflake`] Id of message to fetch. channel_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of channel where message should be fetched. 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. Returns ------- :class:`~melisa.models.message.message.Message` Message object. """ message = await self._http.get( f"/channels/{channel_id}/messages/{message_id}", ) return Message.from_dict(message)
[docs] async def fetch_channel_pins( self, channel_id: Union[Snowflake, int, str] ) -> AsyncIterator[Message]: """|coro| Retrieves all messages that are currently pinned in the channel. Parameters ---------- channel_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of channel where messages should be fetched. Raises ------- HTTPException The request to perform the action failed with other http exception. Returns ------- AsyncIterator[:class:`~melisa.models.message.message.Message`] AsyncIterator of Message objects. """ messages = await self._http.get( f"/channels/{channel_id}/pins", ) for message in messages: yield Message.from_dict(message)
[docs] async def modify_guild_member( self, guild_id: Union[Snowflake, str, int], user_id: Union[Snowflake, str, int], *, nick: Optional[str] = UNDEFINED, roles: Optional[List[Snowflake]] = UNDEFINED, is_mute: Optional[bool] = UNDEFINED, is_deaf: Optional[bool] = UNDEFINED, voice_channel_id: Optional[Snowflake] = UNDEFINED, communication_disabled_until: Optional[datetime.datetime] = UNDEFINED, reason: Optional[str] = None, ): """|coro| [**REST API**] Modify attributes of a guild member. Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of guild where we will modify member user_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of user to operate with. nick: Optional[:class:`str`] Value to set user's nickname to. **Required permissions:** ``MANAGE_NICKNAMES`` roles: Optional[List[:class:`~.melisa.utils.snowflake.Snowflake`]] List of role ids the member is assigned **Required permissions:** ``MANAGE_ROLES`` is_mute Whether the user is muted in voice channels. **Required permissions:** ``MUTE_MEMBERS`` is_deaf Whether the user is deafened in voice channels. **Required permissions:** ``DEAFEN_MEMBERS`` voice_channel_id: Optional[:class:`~.melisa.utils.snowflake.Snowflake`] Id of channel to move user to (if they are connected to voice) **Required permissions:** ``MOVE_MEMBERS`` 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 (up to 28 days in the future), set to ``None`` to remove timeout. Will throw a 403 error if the user has the ``ADMINISTRATOR`` permission or is the owner of the guild **Required permissions:** ``MODERATE_MEMBERS`` 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 type of argument, or you set ``is_deaf``, ``is_mute`` when user is not in the channel """ data = {} if nick is not UNDEFINED: data["nick"] = nick if roles is not UNDEFINED: data["roles"] = roles if is_mute is not UNDEFINED: data["mute"] = is_mute if is_deaf is not UNDEFINED: data["deaf"] = is_deaf if voice_channel_id is not UNDEFINED: data["channel_id"] = voice_channel_id if communication_disabled_until is not UNDEFINED: data[ "communication_disabled_until" ] = communication_disabled_until.isoformat() await self._http.patch( f"guilds/{guild_id}/members/{user_id}", data=data, headers={"X-Audit-Log-Reason": reason}, )
[docs] async def remove_guild_member( self, guild_id: Union[Snowflake, str, int], user_id: Union[Snowflake, str, int], *, reason: Optional[str] = None, ): """|coro| [**REST API**] Remove a member from a guild. **Required permissions:** ``KICK_MEMBERS`` Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of guild where we will remove member user_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of user to operate with. 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._http.delete( f"guilds/{guild_id}/members/{user_id}", headers={"X-Audit-Log-Reason": reason}, )
[docs] async def create_guild_ban( self, guild_id: Union[Snowflake, str, int], user_id: Union[Snowflake, str, int], *, delete_message_days: Optional[int] = 0, reason: Optional[str] = None, ): """|coro| [**REST API**] Create a guild ban, and optionally delete previous messages sent by the banned user. **Required permissions:** ``BAN_MEMBERS`` Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of guild where we will ban member user_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of user to operate with. 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._http.put( f"guilds/{guild_id}/bans/{user_id}", data={"delete_message_days": delete_message_days}, headers={"X-Audit-Log-Reason": reason}, )
[docs] async def remove_guild_ban( self, guild_id: Union[Snowflake, str, int], user_id: Union[Snowflake, str, int], *, reason: Optional[str] = None, ): """|coro| [**REST API**] Remove the ban for a user. **Required permissions:** ``BAN_MEMBERS`` Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of guild where we will remove ban for member user_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of user to operate with. 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 Or if the user is not banned """ await self._http.delete( f"guilds/{guild_id}/bans/{user_id}", headers={"X-Audit-Log-Reason": reason}, )
[docs] async def add_guild_member_role( self, guild_id: Union[Snowflake, str, int], user_id: Union[Snowflake, str, int], role_id: Union[Snowflake, str, int], *, reason: Optional[str] = None, ): """|coro| [**REST API**] Adds a role to a guild member. **Required permissions:** ``MANAGE_ROLES`` Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of guild where we will give member role user_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of user to operate with. role_id: Optional[:class:`int`] Id of role to give. 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._http.put( f"guilds/{guild_id}/members/{user_id}/roles/{role_id}", headers={"X-Audit-Log-Reason": reason}, )
[docs] async def remove_guild_member_role( self, guild_id: Union[Snowflake, str, int], user_id: Union[Snowflake, str, int], role_id: Union[Snowflake, str, int], *, reason: Optional[str] = None, ): """|coro| [**REST API**] Removes a role from a guild member. **Required permissions:** ``MANAGE_ROLES`` Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of guild where we will remove member role user_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Id of user to operate with. 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._http.delete( f"guilds/{guild_id}/members/{user_id}/roles/{role_id}", headers={"X-Audit-Log-Reason": reason}, )
[docs] async def list_guild_emojis( self, guild_id: Union[Snowflake, str, int], ): """|coro| [**REST API**] Getting all emojis from guild Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] ID of the guild in which we will get the list of emojis 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 """ return [ Emoji.from_dict(emoji) for emoji in await self._http.get(f"/guilds/{guild_id}/emojis") ]
[docs] async def get_guild_emoji( self, guild_id: Union[Snowflake, str, int], emoji_id: Union[Snowflake, str, int] ): """|coro| [**REST API**] Get emoji from guild Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] The ID of the guild in which we will receive emoji emoji_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] The ID of the emoji that we will get 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 and emoji """ await self._http.get(f"/guilds/{guild_id}/emojis/{emoji_id}")
[docs] async def create_guild_emoji( self, guild_id: Union[int, str, Snowflake], emoji_name: str, emoji_image: Any, *, reason: Optional[str] = None, role_id: Union[int, str, Snowflake] = None, ): # FIXME: emoji_image != str, it works another way """|coro| [**REST API**] Create a new emoji for the guild. **Required permissions:** ``MANAGE_EMOJIS_AND_STICKERS``. Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] ID of the guild in which we will create emoji emoji_name: Optional[:class:`str`] Name of the emoji emoji_image: Optional[:class:`str`] The 128x128 emoji image reason: Optional[:class:`str`] The reason of the action role_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Roles allowed to use this emoji 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 """ data = {"name": emoji_name, "image": emoji_image, "roles": role_id} return Emoji.from_dict( await self._http.post( f"/guilds/{guild_id}/emojis", json=data, headers={"X-Audit-Log-Reason": reason}, ) )
[docs] async def modify_guild_emoji( self, guild_id: Union[int, str, Snowflake], emoji_id: Union[int, str, Snowflake], emoji_name: Optional[str], *, reason: Optional[str] = None, role_id: Union[int, str, Snowflake] = None, ): """|coro| [**REST API**] Modify the given emoji. **Required permissions:** ``MANAGE_EMOJIS_AND_STICKERS``. Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] ID of the guild in which we will modify emoji emoji_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] The ID of the emoji that we will modify emoji_name: Optional[:class:`str`] Name of the emoji reason: Optional[:class:`str`] The reason of the action role_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] Roles allowed to use this emoji 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 and emoji """ data = {"name": emoji_name, "roles": role_id} return Emoji.from_dict( await self._http.patch( f"/guilds/{guild_id}/emojis/{emoji_id}", json=data, headers={"X-Audit-Log-Reason": reason}, ) )
[docs] async def delete_guild_emoji( self, guild_id: Union[int, str, Snowflake], emoji_id: Union[int, str, Snowflake], *, reason: Optional[str] = None, ): """|coro| [**REST API**] Delete the given emoji **Required permissions:** ``MANAGE_EMOJIS_AND_STICKERS``. Parameters ---------- guild_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] ID of the guild in which we will delete emoji emoji_id: Union[:class:`int`, :class:`str`, :class:`~.melisa.utils.snowflake.Snowflake`] The ID of the emoji that we will delete 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 and emoji """ await self._http.delete( f"/guilds/{guild_id}/emojis/{emoji_id}", headers={"X-Audit-Log-Reason": reason}, )
[docs] async def get_global_application_commands( self, application_id: Union[int, str, Snowflake], *, with_localizations: Optional[bool] = False, ) -> List[PartialApplicationCommand]: """|coro| [**REST API**] Fetch all of the global commands for your application. Parameters ---------- application_id: :class:`~melisa.utils.snowflake.Snowflake` ID of the parent application with_localizations: Optional[bool] Whether to include full localization dictionaries (``name_localizations`` and ``description_localizations``) in the returned objects, instead of the ``name_localized` and ``description_localized fields``. Default ``False``. 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 arguments """ return [ _choose_command_type(x) for x in await self._http.get( f"/applications/{application_id}/commands?with_localizations={with_localizations}" ) ]
[docs] async def create_global_application_command( self, application_id: Union[int, str, Snowflake], command_type: ApplicationCommandType, name: LocalizedField, description: LocalizedField = None, *, options: Optional[List[SlashCommandOption]] = None, default_member_permissions: Optional[str] = None, dm_permission: Optional[bool] = None, default_permission: Optional[bool] = None, ) -> PartialApplicationCommand: """|coro| [**REST API**] Create a new global command. Parameters ---------- application_id: :class:`~melisa.utils.snowflake.Snowflake` ID of the parent application command_type: Optional[:class:`~melisa.interactions.commands.ApplicationCommandType`] Type of command, defaults to ``1`` name: :class:`~melisa.models.interactions.i18n.LocalizedField` Name of command, 1-32 characters description: Optional[:class:`~melisa.models.interactions.i18n.LocalizedField`] Description for ``CHAT_INPUT`` commands, 1-100 characters. Empty string for ``USER`` and ``MESSAGE`` commands options: Optional[List[:class:`~melisa.models.interactions.commands.SlashCommandOption`]] Parameters for the command, max of 25. Only available for ``CHAT_INPUT`` command type. default_member_permissions: Optional[str] Set of permissions represented as a bit set dm_permission: Optional[bool] Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. default_permission: Optional[bool] Not recommended for use as field will soon be deprecated. Indicates whether the command is enabled by default when the app is added to a guild, defaults to ``True`` 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 arguments """ data = { "name": name.original, "type": int(command_type), } if name.localizations is not None: data["name_localizations"] = name.localizations if description.original is not None: data["description"] = description.original if description.localizations is not None: data["description_localizations"] = description.localizations if default_member_permissions is not None: data["default_member_permissions"] = default_member_permissions if options is not None: for option in options: option_data = option.to_dict() option_data["name"] = option.name.original option_data["description"] = option.description.original if option.name.localizations is not None: option_data["name_localizations"] = option.name.localizations if option.description.localizations is not None: option_data[ "description_localizations" ] = option.description.localizations if dm_permission is not None: data["dm_permission"] = dm_permission if default_permission is not None: data["default_permission"] = default_permission return _choose_command_type( await self._http.post(f"/applications/{application_id}/commands", json=data) )
[docs] async def get_global_application_command( self, application_id: Union[int, str, Snowflake], command_id: Union[int, str, Snowflake], ) -> PartialApplicationCommand: """|coro| [**REST API**] Fetch a global command for your application. Parameters ---------- application_id: :class:`~melisa.utils.snowflake.Snowflake` ID of the parent application command_id: Optional[bool] ID of command to fetch. 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 arguments """ return _choose_command_type( await self._http.get( f"/applications/{application_id}/commands/{command_id}" ) )
[docs] async def edit_global_application_command( self, application_id: Union[int, str, Snowflake], command_id: Union[int, str, Snowflake], *, name: Optional[LocalizedField] = None, description: Optional[LocalizedField] = None, options: Optional[List[SlashCommandOption]] = None, default_member_permissions: Optional[str] = None, dm_permission: Optional[bool] = None, default_permission: Optional[bool] = None, ) -> PartialApplicationCommand: """|coro| All parameters are optional, but any parameters provided will entirely overwrite the existing values of those parameters. [**REST API**] Edit a global command. Parameters ---------- application_id: :class:`~melisa.utils.snowflake.Snowflake` ID of the parent application command_id: Optional[bool] ID of command to edit. name: Optional[:class:`~melisa.models.interactions.i18n.LocalizedField`] Name of command, 1-32 characters description: Optional[:class:`~melisa.models.interactions.i18n.LocalizedField`] Description for ``CHAT_INPUT`` commands, 1-100 characters. Empty string for ``USER`` and ``MESSAGE`` commands options: Optional[List[:class:`~melisa.models.interactions.commands.ApplicationCommandOption`]] Parameters for the command, max of 25. Only available for ``CHAT_INPUT`` command type. default_member_permissions: Optional[str] Set of permissions represented as a bit set dm_permission: Optional[bool] Indicates whether the command is available in DMs with the app, only for globally-scoped commands. By default, commands are visible. default_permission: Optional[bool] Not recommended for use as field will soon be deprecated. Indicates whether the command is enabled by default when the app is added to a guild, defaults to true 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 arguments """ data = {} if name.original is not None: data["name"] = name.original if description.original is not None: data["description"] = description.original if name.localizations is not None: data["name_localizations"] = name.localizations if description.localizations is not None: data["description_localizations"] = description.localizations if default_member_permissions is not None: data["default_member_permissions"] = default_member_permissions data["options"] = [] if options is not None: for option in options: option_data = option.to_dict() option_data["name"] = option.name.original option_data["description"] = option.description.original if option.name.localizations is not None: option_data["name_localizations"] = option.name.localizations if option.description.localizations is not None: option_data[ "description_localizations" ] = option.description.localizations data["options"].append(option_data) if dm_permission is not None: data["dm_permission"] = dm_permission if default_permission is not None: data["default_permission"] = default_permission return _choose_command_type( await self._http.patch( f"/applications/{application_id}/commands/{command_id}", json=data ) )
[docs] async def delete_global_application_command( self, application_id: Union[int, str, Snowflake], command_id: Union[int, str, Snowflake], ) -> None: """|coro| [**REST API**] Delete a global command. Parameters ---------- application_id: :class:`~melisa.utils.snowflake.Snowflake` ID of the parent application command_id: Optional[bool] ID of command to delete. 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 arguments """ await self._http.delete(f"/applications/{application_id}/commands/{command_id}") return None
[docs] async def bulk_overwrite_global_application_commands( self, application_id: Union[int, str, Snowflake], commands: List[Union[SlashCommand, PartialApplicationCommand]], ) -> List[Union[SlashCommand, PartialApplicationCommand]]: """|coro| [**REST API**] Overwrites all existing global commands. Parameters ---------- application_id: :class:`~melisa.utils.snowflake.Snowflake` ID of the parent application commands: List[Union[:class:`~melisa.models.interactions.commands.SlashCommand`, :class:`~melisa.models.interactions.commands.PartialApplicationCommand`]] 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 arguments """ better_commands = [] for command in commands: command_data = { "name": command.name.original, "type": int(command.type), } if command.name.localizations is not None: command_data["name_localizations"] = command.name.localizations if command.default_member_permissions is not None: command_data[ "default_member_permissions" ] = command.default_member_permissions if command.dm_permission is not None: command_data["dm_permission"] = command.dm_permission if isinstance(command, SlashCommand): if command.description is not None: command_data["description"] = command.description.original if command.description.localizations is not None: command_data[ "description_localizations" ] = command.description.localizations command_data["options"] = [] if command.options is not None: for option in command.options: option_data = option.to_dict() option_data["name"] = option.name.original option_data["description"] = option.description.original if option.name.localizations is not None: option_data[ "name_localizations" ] = option.name.localizations if option.description.localizations is not None: option_data[ "description_localizations" ] = option.description.localizations command_data["options"].append(option_data) better_commands.append(command_data) return [ _choose_command_type(x) for x in await self._http.put( f"/applications/{application_id}/commands", json=better_commands ) ]
[docs] async def interaction_respond( self, interaction: Interaction, interaction_response: InteractionResponse, ): """|coro| [**REST API**] Respond to an interaciton Parameters ---------- interaction: :class:`~melisa.models.interactions.interactions.Interaction` Interaction to respond to interaction_response: :class:`~melisa.models.interactions.interactions.InteractionResponse` InteractionResponse`e`` 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 arguments """ return await self._http.post( f"/interactions/{interaction.id}/{interaction.token}/callback", json=interaction_response.to_dict(), )
class CDNBuilder: """Can be used to build images Parameters ---------- default_image_format: :class:`str` Default image format """ # ToDo: Add docstrings BASE_URL = "https://cdn.discordapp.com" def __init__(self, default_image_format: str = None): self.dif = default_image_format if default_image_format is not None else "png" def avatar_url( self, user_id: str, _hash: str, *, size: int = 1024, image_format: str = None ): return "{}/avatars/{}/{}.{}?size={}".format( self.BASE_URL, user_id, _hash, image_format if image_format is not None else self.dif, size, ) def guild_icon_url( self, guild_id: str, _hash: str, *, size: int = 1024, image_format: str = None ): return "{}/icons/{}/{}.{}?size={}".format( self.BASE_URL, guild_id, _hash, image_format if image_format is not None else self.dif, size, ) def default_avatar_url(self, discriminator: str): return "{}/embed/avatars/{}.png".format(self.BASE_URL, int(discriminator) % 5) def guild_member_avatar_url( self, guild_id: str, user_id: str, _hash: str, *, size: int = 1024, image_format: str = None, ): return "{}/guilds/{}/users/{}/avatars/{}.{}?size={}".format( self.BASE_URL, guild_id, user_id, _hash, image_format if image_format is not None else self.dif, size, ) def role_icon_url( self, role_id: str, _hash: str, *, size: int = 1024, image_format: str = None, ): return "{}/role-icons/{}/{}.{}?size={}".format( self.BASE_URL, role_id, _hash, image_format if image_format is not None else self.dif, size, )