From 2b79405d6afbcf406beadb571a7574b211125a84 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 28 Feb 2022 10:51:26 +0100 Subject: [PATCH 01/47] fix!: fix EmbedImageStruct serialization --- interactions/api/models/message.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/interactions/api/models/message.py b/interactions/api/models/message.py index 5c0bba76a..c1652b008 100644 --- a/interactions/api/models/message.py +++ b/interactions/api/models/message.py @@ -901,3 +901,12 @@ def __init__(self, **kwargs): if self.footer: self._json.update({"footer": self.footer._json}) + + if self.video: + self._json.update({"video": self.video._json}) + + if self.image: + self._json.update({"image": self.image._json}) + + if self.thumbnail: + self._json.update({"thumbnail": self.thumbnail._json}) From bf79b5d3ebc169e3fcbeedc831f57a4138b07af9 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 28 Feb 2022 11:34:37 +0100 Subject: [PATCH 02/47] fix!: Button emoji serialization --- interactions/models/component.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interactions/models/component.py b/interactions/models/component.py index 640635707..9bafe9547 100644 --- a/interactions/models/component.py +++ b/interactions/models/component.py @@ -140,6 +140,8 @@ def __init__(self, **kwargs) -> None: self.type = ComponentType.BUTTON self.style = ButtonStyle(self.style) self._json.update({"type": self.type.value, "style": self.style.value}) + if self.emoji: + self._json.update({"emoji": self.emoji._json}) class Component(DictSerializerMixin): From a429ffe0432e8380a7e8d783a00f4f36216845f7 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 28 Feb 2022 21:56:43 +0100 Subject: [PATCH 03/47] fix!: message serialization in context --- interactions/api/http.py | 2 +- interactions/context.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interactions/api/http.py b/interactions/api/http.py index 015f1ece2..0dcfcf58f 100644 --- a/interactions/api/http.py +++ b/interactions/api/http.py @@ -2301,7 +2301,7 @@ async def delete_interaction_response( webhook_id=int(application_id), webhook_token=token, message_id=message_id ) - async def _post_followup(self, data: dict, token: str, application_id: str) -> None: + async def _post_followup(self, data: dict, token: str, application_id: str) -> dict: """ Send a followup to an interaction. diff --git a/interactions/context.py b/interactions/context.py index 47a06afc0..821706dea 100644 --- a/interactions/context.py +++ b/interactions/context.py @@ -453,13 +453,13 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: application_id=str(self.application_id), ) self.responded = True - self.message = msg = Message(**res, _client=self.client) else: - await self.client._post_followup( + res = await self.client._post_followup( data=payload._json, token=self.token, application_id=str(self.application_id), ) + self.message = msg = Message(**res, _client=self.client) else: await self.client.create_interaction_response( token=self.token, @@ -633,13 +633,14 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: application_id=str(self.application_id), ) self.responded = True - self.message = msg = Message(**res, _client=self.client) else: - await self.client._post_followup( + res = await self.client._post_followup( data=payload._json, token=self.token, application_id=str(self.application_id), ) + self.message = msg = Message(**res, _client=self.client) + else: await self.client.create_interaction_response( token=self.token, From 0b8ba6907ea910610a0e232511d611592e3cea27 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Tue, 1 Mar 2022 19:29:08 +0100 Subject: [PATCH 04/47] refactor: refactor return typehints and payload naming to be consistent --- interactions/api/http.py | 111 +++++++++++++---------------- interactions/api/models/channel.py | 105 ++++++++++++++++++++++++++- interactions/api/models/guild.py | 6 +- interactions/api/models/role.py | 2 +- 4 files changed, 156 insertions(+), 68 deletions(-) diff --git a/interactions/api/http.py b/interactions/api/http.py index 0dcfcf58f..105ba6e1d 100644 --- a/interactions/api/http.py +++ b/interactions/api/http.py @@ -16,22 +16,7 @@ from ..api.cache import Cache, Item from ..api.error import HTTPException -from ..api.models import ( - Channel, - Embed, - Emoji, - Guild, - GuildPreview, - GuildTemplate, - Invite, - Member, - Message, - Role, - Snowflake, - StageInstance, - User, - WelcomeScreen, -) +from ..api.models import Channel, Embed, Emoji, Guild, Member, Message, Role, Snowflake, User log: Logger = get_logger("http") @@ -436,7 +421,7 @@ async def modify_self(self, payload: dict) -> dict: """ return await self._req.request(Route("PATCH", "/users/@me"), json=payload) - async def modify_self_nick_in_guild(self, guild_id: int, nickname: Optional[str]): + async def modify_self_nick_in_guild(self, guild_id: int, nickname: Optional[str]) -> dict: """ Changes a nickname of the current bot user in a guild. @@ -476,7 +461,7 @@ async def send_message( nonce: Union[int, str] = None, allowed_mentions=None, # don't know type message_reference: Optional[Message] = None, - ): + ) -> dict: """ A higher level implementation of :meth:`create_message()` that handles the payload dict internally. Does not integrate components into the function, and is a port from v3.0.0 @@ -623,7 +608,7 @@ async def publish_message(self, channel_id: int, message_id: int) -> dict: # Guild endpoint - async def get_self_guilds(self) -> list: + async def get_self_guilds(self) -> List[dict]: """ Gets all guild objects associated with the current bot user. @@ -637,7 +622,7 @@ async def get_self_guilds(self) -> list: return request - async def get_guild(self, guild_id: int): + async def get_guild(self, guild_id: int) -> Optional[dict]: """ Requests an individual guild from the API. @@ -649,7 +634,7 @@ async def get_guild(self, guild_id: int): return request - async def get_guild_preview(self, guild_id: int) -> GuildPreview: + async def get_guild_preview(self, guild_id: int) -> dict: """ Get a guild's preview. @@ -736,7 +721,7 @@ async def modify_guild_widget(self, guild_id: int, payload: dict) -> dict: """ return await self._req.request(Route("PATCH", f"/guilds/{guild_id}/widget"), json=payload) - async def get_guild_invites(self, guild_id: int) -> List[Invite]: + async def get_guild_invites(self, guild_id: int) -> List[dict]: """ Retrieves a list of invite objects with their own metadata. @@ -745,7 +730,7 @@ async def get_guild_invites(self, guild_id: int) -> List[Invite]: """ return await self._req.request(Route("GET", f"/guilds/{guild_id}/invites")) - async def get_guild_welcome_screen(self, guild_id: int) -> WelcomeScreen: + async def get_guild_welcome_screen(self, guild_id: int) -> dict: """ Retrieves from the API a welcome screen associated with the guild. @@ -756,7 +741,7 @@ async def get_guild_welcome_screen(self, guild_id: int) -> WelcomeScreen: async def modify_guild_welcome_screen( self, guild_id: int, enabled: bool, welcome_channels: List[int], description: str - ) -> WelcomeScreen: + ) -> dict: """ Modify the guild's welcome screen. @@ -816,7 +801,7 @@ async def modify_current_user_voice_state( channel_id: int, suppress: Optional[bool] = None, request_to_speak_timestamp: Optional[str] = None, - ) -> None: + ) -> dict: """ Update the current user voice state. @@ -840,7 +825,7 @@ async def modify_current_user_voice_state( async def modify_user_voice_state( self, guild_id: int, user_id: int, channel_id: int, suppress: Optional[bool] = None - ) -> None: + ) -> dict: """ Modify the voice state of a user. @@ -860,7 +845,7 @@ async def modify_user_voice_state( async def create_guild_from_guild_template( self, template_code: str, name: str, icon: Optional[str] = None - ) -> Guild: + ) -> dict: """ Create a new guild based on a template. @@ -881,7 +866,7 @@ async def create_guild_from_guild_template( Route("POST", f"/guilds/templates/{template_code}", json=payload) ) - async def get_guild_templates(self, guild_id: int) -> List[GuildTemplate]: + async def get_guild_templates(self, guild_id: int) -> List[dict]: """ Returns an array of guild templates. @@ -892,7 +877,7 @@ async def get_guild_templates(self, guild_id: int) -> List[GuildTemplate]: async def create_guild_template( self, guild_id: int, name: str, description: Optional[str] = None - ) -> GuildTemplate: + ) -> dict: """ Create a guild template for the guild. @@ -908,7 +893,7 @@ async def create_guild_template( }, ) - async def sync_guild_template(self, guild_id: int, template_code: str) -> GuildTemplate: + async def sync_guild_template(self, guild_id: int, template_code: str) -> dict: """ Sync the template to the guild's current state. @@ -926,7 +911,7 @@ async def modify_guild_template( template_code: str, name: Optional[str] = None, description: Optional[str] = None, - ) -> GuildTemplate: + ) -> dict: """ Modify a guild template. @@ -943,7 +928,7 @@ async def modify_guild_template( }, ) - async def delete_guild_template(self, guild_id: int, template_code: str) -> GuildTemplate: + async def delete_guild_template(self, guild_id: int, template_code: str) -> dict: """ Delete the guild template. @@ -991,18 +976,18 @@ async def get_all_roles(self, guild_id: int) -> List[dict]: return request async def create_guild_role( - self, guild_id: int, data: dict, reason: Optional[str] = None - ) -> Role: + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: """ Create a new role for the guild. :param guild_id: Guild ID snowflake. - :param data: A dict containing metadata for the role. + :param payload: A dict containing metadata for the role. :param reason: The reason for this action, if given. :return: Role object """ request = await self._req.request( - Route("POST", f"/guilds/{guild_id}/roles"), json=data, reason=reason + Route("POST", f"/guilds/{guild_id}/roles"), json=payload, reason=reason ) if request.get("id"): self.cache.roles.add(Item(id=request["id"], value=Role(**request))) @@ -1011,7 +996,7 @@ async def create_guild_role( async def modify_guild_role_position( self, guild_id: int, role_id: int, position: int, reason: Optional[str] = None - ) -> List[Role]: + ) -> List[dict]: """ Modify the position of a role in the guild. @@ -1028,19 +1013,19 @@ async def modify_guild_role_position( ) async def modify_guild_role( - self, guild_id: int, role_id: int, data: dict, reason: Optional[str] = None - ) -> Role: + self, guild_id: int, role_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: """ Modify a given role for the guild. :param guild_id: Guild ID snowflake. :param role_id: Role ID snowflake. - :param data: A dict containing updated metadata for the role. + :param payload: A dict containing updated metadata for the role. :param reason: The reason for this action, if given. :return: Updated role object. """ return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/roles/{role_id}"), json=data, reason=reason + Route("PATCH", f"/guilds/{guild_id}/roles/{role_id}"), json=payload, reason=reason ) async def delete_guild_role(self, guild_id: int, role_id: int, reason: str = None) -> None: @@ -1236,7 +1221,7 @@ async def get_guild_auditlog( # Guild (Member) endpoint - async def get_member(self, guild_id: int, member_id: int) -> Optional[Member]: + async def get_member(self, guild_id: int, member_id: int) -> Optional[dict]: """ Uses the API to fetch a member from a guild. @@ -1255,7 +1240,7 @@ async def get_member(self, guild_id: int, member_id: int) -> Optional[Member]: async def get_list_of_members( self, guild_id: int, limit: int = 1, after: Optional[int] = None - ) -> List[Member]: + ) -> List[dict]: """ Lists the members of a guild. @@ -1270,7 +1255,7 @@ async def get_list_of_members( return await self._req.request(Route("GET", f"/guilds/{guild_id}/members"), params=payload) - async def search_guild_members(self, guild_id: int, query: str, limit: int = 1) -> List[Member]: + async def search_guild_members(self, guild_id: int, query: str, limit: int = 1) -> List[dict]: """ Search a guild for members whose username or nickname starts with provided string. @@ -1330,7 +1315,7 @@ async def remove_member_role( async def modify_member( self, user_id: int, guild_id: int, payload: dict, reason: Optional[str] = None - ): + ) -> dict: """ Edits a member. This can nick them, change their roles, mute/deafen (and its contrary), and moving them across channels and/or disconnect them. @@ -1381,7 +1366,7 @@ async def get_channel_messages( around: Optional[int] = None, before: Optional[int] = None, after: Optional[int] = None, - ) -> List[Message]: + ) -> List[dict]: """ Get messages from a channel. @@ -1454,7 +1439,7 @@ async def move_channel( parent_id: Optional[int], lock_perms: bool = False, reason: Optional[str] = None, - ): + ) -> dict: """ Moves a channel to a new position. @@ -1475,21 +1460,21 @@ async def move_channel( ) async def modify_channel( - self, channel_id: int, data: dict, reason: Optional[str] = None - ) -> Channel: + self, channel_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: """ Update a channel's settings. :param channel_id: Channel ID snowflake. - :param data: Data representing updated settings. + :param payload: Data representing updated settings. :param reason: Reason, if any. :return: Channel with updated attributes, if successful. """ return await self._req.request( - Route("PATCH", f"/channels/{channel_id}"), json=data, reason=reason + Route("PATCH", f"/channels/{channel_id}"), json=payload, reason=reason ) - async def get_channel_invites(self, channel_id: int) -> List[Invite]: + async def get_channel_invites(self, channel_id: int) -> List[dict]: """ Get the invites for the channel. @@ -1499,8 +1484,8 @@ async def get_channel_invites(self, channel_id: int) -> List[Invite]: return await self._req.request(Route("GET", f"/channels/{channel_id}/invites")) async def create_channel_invite( - self, channel_id: int, data: dict, reason: Optional[str] = None - ) -> Invite: + self, channel_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: """ Creates an invite for the given channel. @@ -1513,7 +1498,7 @@ async def create_channel_invite( :return: An invite object. """ return await self._req.request( - Route("POST", f"/channels/{channel_id}/invites"), json=data, reason=reason + Route("POST", f"/channels/{channel_id}/invites"), json=payload, reason=reason ) async def delete_invite(self, invite_code: str, reason: Optional[str] = None) -> dict: @@ -1576,7 +1561,7 @@ async def trigger_typing(self, channel_id: int) -> None: """ return await self._req.request(Route("POST", f"/channels/{channel_id}/typing")) - async def get_pinned_messages(self, channel_id: int) -> List[Message]: + async def get_pinned_messages(self, channel_id: int) -> List[dict]: """ Get all pinned messages from a channel. @@ -1587,7 +1572,7 @@ async def get_pinned_messages(self, channel_id: int) -> List[Message]: async def create_stage_instance( self, channel_id: int, topic: str, privacy_level: int = 1, reason: Optional[str] = None - ) -> StageInstance: + ) -> dict: """ Create a new stage instance. @@ -1607,7 +1592,7 @@ async def create_stage_instance( reason=reason, ) - async def get_stage_instance(self, channel_id: int) -> StageInstance: + async def get_stage_instance(self, channel_id: int) -> dict: """ Get the stage instance associated with a given channel, if it exists. @@ -1622,7 +1607,7 @@ async def modify_stage_instance( topic: Optional[str] = None, privacy_level: Optional[int] = None, reason: Optional[str] = None, - ) -> StageInstance: + ) -> dict: """ Update the fields of a given stage instance. @@ -1928,7 +1913,7 @@ async def remove_all_reactions_of_emoji( async def get_reactions_of_emoji( self, channel_id: int, message_id: int, emoji: str - ) -> List[User]: + ) -> List[dict]: """ Gets the users who reacted to the emoji. @@ -1958,7 +1943,7 @@ async def get_sticker(self, sticker_id: int) -> dict: """ return await self._req.request(Route("GET", f"/stickers/{sticker_id}")) - async def list_nitro_sticker_packs(self) -> list: + async def list_nitro_sticker_packs(self) -> List[dict]: """ Gets the list of sticker packs available to Nitro subscribers. @@ -1987,7 +1972,7 @@ async def get_guild_sticker(self, guild_id: int, sticker_id: int) -> dict: async def create_guild_sticker( self, payload: FormData, guild_id: int, reason: Optional[str] = None - ): + ) -> dict: """ Create a new sticker for the guild. Requires the MANAGE_EMOJIS_AND_STICKERS permission. @@ -2002,7 +1987,7 @@ async def create_guild_sticker( async def modify_guild_sticker( self, payload: dict, guild_id: int, sticker_id: int, reason: Optional[str] = None - ): + ) -> dict: """ Modify the given sticker. Requires the MANAGE_EMOJIS_AND_STICKERS permission. diff --git a/interactions/api/models/channel.py b/interactions/api/models/channel.py index 53dae9a50..02ca3ce22 100644 --- a/interactions/api/models/channel.py +++ b/interactions/api/models/channel.py @@ -335,7 +335,7 @@ async def modify( res = await self._client.modify_channel( channel_id=int(self.id), reason=reason, - data=payload._json, + payload=payload._json, ) return Channel(**res, _client=self._client) @@ -846,6 +846,109 @@ async def create_thread( return Channel(**res, _client=self._client) + @classmethod + async def get( + cls, + channel: Union[int, str], + client: "HTTPClient", # noqa + ) -> "Channel": + """ + Gets a channel based of its URL or its id. + + :param channel: The URL to the channel or the id of the channel + :type channel: Union[int, str] + :param client: The HTTPClient of your bot. Set as ``bot._http`` + :type client: HTTPClient + """ + + channel_id = channel if isinstance(channel, int) else int(channel.split(sep="/")[-1]) + + res = await client.get_channel(channel_id) + return cls(**res, _client=client) + + @property + def url(self) -> str: + return f"https://discord.com/channels/{self.guild_id}/{self.id}" if self.guild_id else None + + async def create_invite( + self, + max_age: Optional[int] = 86400, + max_uses: Optional[int] = 0, + temporary: Optional[bool] = False, + unique: Optional[bool] = False, + target_type: Optional["InviteTargetType"] = MISSING, # noqa + target_user_id: Optional[int] = MISSING, + target_application_id: Optional[int] = MISSING, + reason: Optional[str] = None, + ) -> "Invite": # noqa + """ + Creates an invite for the channel + + :param max_age?: Duration of invite in seconds before expiry, or 0 for never. between 0 and 604800 (7 days). Default 86400 (24h) + :type max_age: Optional[int] + :param max_uses?: Max number of uses or 0 for unlimited. between 0 and 100. Default 0 + :type max_uses: Optional[int] + :param temporary?: Whether this invite only grants temporary membership. Default False + :type temporary: Optional[bool] + :param unique?: If true, don't try to reuse a similar invite (useful for creating many unique one time use invites). Default False + :type unique: Optional[bool] + :param target_type?: The type of target for this voice channel invite + :type target_type: Optional["InviteTargetType"] + :param target_user_id?: The id of the user whose stream to display for this invite, required if target_type is STREAM, the user must be streaming in the channel + :type target_user_id: Optional[int] + :param target_application_id?: The id of the embedded application to open for this invite, required if target_type is EMBEDDED_APPLICATION, the application must have the EMBEDDED flag + :type target_application_id: Optional[int] + :param reason?: The reason for the creation of the invite + :type reason: Optional[str] + """ + + if not self._client: + raise AttributeError("HTTPClient not found!") + + payload = { + "max_age": max_age, + "max_uses": max_uses, + "temporary": temporary, + "unique": unique, + } + + if (target_user_id is not MISSING and target_user_id) and ( + target_application_id is not MISSING and target_application_id + ): + raise ValueError( + "target user id and target application are mutually exclusive!" + ) # TODO: move to custom error formatter + + elif ( + (target_user_id is not MISSING and target_user_id) + or (target_application_id is not MISSING and target_application_id) + ) and not target_type: + raise ValueError( + "you have to specify a target_type if you specify target_user-/target_application_id" + ) + + if target_user_id is not MISSING: + payload["target_type"] = ( + target_type if isinstance(target_type, int) else target_type.value + ) + payload["target_user_id"] = target_user_id + + if target_application_id is not MISSING: + payload["target_type"] = ( + target_type if isinstance(target_type, int) else target_type.value + ) + payload["target_application_id"] = target_application_id + + res = await self._client.create_channel_invite( + channel_id=int(self.id), + payload=payload, + reason=reason, + ) + + from .guild import Invite + + return Invite(**res, _client=self._client) + class Thread(Channel): """An object representing a thread. diff --git a/interactions/api/models/guild.py b/interactions/api/models/guild.py index 52a9ed666..5ecf154e0 100644 --- a/interactions/api/models/guild.py +++ b/interactions/api/models/guild.py @@ -499,7 +499,7 @@ async def create_role( res = await self._client.create_guild_role( guild_id=int(self.id), reason=reason, - data=payload._json, + payload=payload._json, ) return Role(**res, _client=self._client) @@ -605,7 +605,7 @@ async def modify_role( res = await self._client.modify_guild_role( guild_id=int(self.id), role_id=role_id, - data=payload._json, + payload=payload._json, reason=reason, ) return Role(**res, _client=self._client) @@ -822,7 +822,7 @@ async def modify_channel( res = await self._client.modify_channel( channel_id=channel_id, reason=reason, - data=payload._json, + payload=payload._json, ) return Channel(**res, _client=self._client) diff --git a/interactions/api/models/role.py b/interactions/api/models/role.py index f34d1ba51..682da5309 100644 --- a/interactions/api/models/role.py +++ b/interactions/api/models/role.py @@ -134,7 +134,7 @@ async def modify( res = await self._client.modify_guild_role( guild_id=guild_id, role_id=int(self.id), - data=payload._json, + payload=payload._json, reason=reason, ) return Role(**res, _client=self._client) From 483930c4ce609c7e52c9a4a9190e9d211e03a04b Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Tue, 1 Mar 2022 19:35:51 +0100 Subject: [PATCH 05/47] refactor: change naming of arguments --- interactions/api/http.py | 30 +++++++++++++++--------------- interactions/api/models/guild.py | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/interactions/api/http.py b/interactions/api/http.py index 105ba6e1d..661a65436 100644 --- a/interactions/api/http.py +++ b/interactions/api/http.py @@ -2535,34 +2535,34 @@ async def get_guild_emoji(self, guild_id: int, emoji_id: int) -> Emoji: return await self._req.request(Route("GET", f"/guilds/{guild_id}/emojis/{emoji_id}")) async def create_guild_emoji( - self, guild_id: int, data: dict, reason: Optional[str] = None + self, guild_id: int, payload: dict, reason: Optional[str] = None ) -> Emoji: """ Creates an emoji. :param guild_id: Guild ID snowflake. - :param data: Emoji parameters. + :param payload: Emoji parameters. :param reason: Optionally, give a reason. :return: An emoji object with the included parameters. """ return await self._req.request( - Route("POST", f"/guilds/{guild_id}/emojis"), json=data, reason=reason + Route("POST", f"/guilds/{guild_id}/emojis"), json=payload, reason=reason ) async def modify_guild_emoji( - self, guild_id: int, emoji_id: int, data: dict, reason: Optional[str] = None + self, guild_id: int, emoji_id: int, payload: dict, reason: Optional[str] = None ) -> Emoji: """ Modifies an emoji. :param guild_id: Guild ID snowflake. :param emoji_id: Emoji ID snowflake - :param data: Emoji parameters with updated attributes + :param payload: Emoji parameters with updated attributes :param reason: Optionally, give a reason. :return: An emoji object with updated attributes. """ return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/emojis/{emoji_id}"), json=data, reason=reason + Route("PATCH", f"/guilds/{guild_id}/emojis/{emoji_id}"), json=payload, reason=reason ) async def delete_guild_emoji( @@ -2581,12 +2581,12 @@ async def delete_guild_emoji( # Guild Scheduled Events endpoints - async def create_scheduled_event(self, guild_id: Snowflake, data: dict) -> dict: + async def create_scheduled_event(self, guild_id: Snowflake, payload: dict) -> dict: """ Creates a scheduled event. :param guild_id: Guild ID snowflake. - :param data: The dictionary containing the parameters and values to edit the associated event. + :param payload: The dictionary containing the parameters and values to edit the associated event. :return A dictionary containing the new guild scheduled event object on success. """ guild_id = int(guild_id) @@ -2600,11 +2600,11 @@ async def create_scheduled_event(self, guild_id: Snowflake, data: dict) -> dict: "description", "entity_type", ) - payload = {k: v for k, v in data.items() if k in valid_keys} + data = {k: v for k, v in payload.items() if k in valid_keys} return await self._req.request( Route("POST", "/guilds/{guild_id}/scheduled-events", guild_id=int(guild_id)), - json=payload, + json=data, ) async def get_scheduled_event( @@ -2651,14 +2651,14 @@ async def get_scheduled_events(self, guild_id: Snowflake, with_user_count: bool) ) async def modify_scheduled_event( - self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, data: dict + self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, payload: dict ) -> dict: """ Modifies a scheduled event. :param guild_id: Guild ID snowflake. :param guild_scheduled_event_id: Guild Scheduled Event ID snowflake. - :param data: The dictionary containing the parameters and values to edit the associated event. + :param payload: The dictionary containing the parameters and values to edit the associated event. :return A dictionary containing the updated guild scheduled event object on success. """ guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) @@ -2672,7 +2672,7 @@ async def modify_scheduled_event( "description", "entity_type", ) - payload = {k: v for k, v in data.items() if k in valid_keys} + data = {k: v for k, v in payload.items() if k in valid_keys} return await self._req.request( Route( "PATCH", @@ -2680,7 +2680,7 @@ async def modify_scheduled_event( guild_id=guild_id, event_id=event_id, ), - json=payload, + json=data, ) async def delete_scheduled_event( @@ -2712,7 +2712,7 @@ async def get_scheduled_event_users( with_member: bool = False, before: Snowflake = None, after: Snowflake = None, - ) -> dict: + ) -> List[dict]: """ Get the registered users of a scheduled event. diff --git a/interactions/api/models/guild.py b/interactions/api/models/guild.py index 5ecf154e0..5ae3d7ea2 100644 --- a/interactions/api/models/guild.py +++ b/interactions/api/models/guild.py @@ -1302,7 +1302,7 @@ async def create_scheduled_event( res = await self._client.create_scheduled_event( guild_id=self.id, - data=payload, + payload=payload, ) return ScheduledEvents(**res) @@ -1376,7 +1376,7 @@ async def modify_scheduled_event( res = await self._client.modify_scheduled_event( guild_id=self.id, guild_scheduled_event_id=Snowflake(event_id), - data=payload, + payload=payload, ) return ScheduledEvents(**res) From afe26c9a762f467b39a89ada764049d3efc001cb Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Tue, 1 Mar 2022 20:23:45 +0100 Subject: [PATCH 06/47] refactor: http to folder --- interactions/api/http/Limiter.py | 42 ++++++ interactions/api/http/Limiter.pyi | 13 ++ interactions/api/http/Request.py | 213 ++++++++++++++++++++++++++++++ interactions/api/http/Request.pyi | 22 +++ interactions/api/http/Route.py | 62 +++++++++ interactions/api/http/Route.pyi | 14 ++ 6 files changed, 366 insertions(+) create mode 100644 interactions/api/http/Limiter.py create mode 100644 interactions/api/http/Limiter.pyi create mode 100644 interactions/api/http/Request.py create mode 100644 interactions/api/http/Request.pyi create mode 100644 interactions/api/http/Route.py create mode 100644 interactions/api/http/Route.pyi diff --git a/interactions/api/http/Limiter.py b/interactions/api/http/Limiter.py new file mode 100644 index 000000000..50849386b --- /dev/null +++ b/interactions/api/http/Limiter.py @@ -0,0 +1,42 @@ +from asyncio import Lock +from typing import Optional + +from interactions.api.models.misc import MISSING + + +class Limiter: + """ + A class representing a limitation for an HTTP request. + + :ivar Lock lock: The "lock" or controller of the request. + :ivar float reset_after: The remaining time before the request can be ran. + """ + + lock: Lock + reset_after: float + + def __init__(self, *, lock: Lock, reset_after: Optional[float] = MISSING) -> None: + """ + :param lock: The asynchronous lock to control limits for. + :type lock: Lock + :param reset_after: The remaining time to run the limited lock on. Defaults to ``0``. + :type reset_after: Optional[float] + """ + self.lock = lock + self.reset_after = 0 if reset_after is MISSING else reset_after + + async def __aenter__(self) -> "Limiter": + await self.lock.acquire() + return self + + async def __aexit__(self, exc_type, exc_val, exc_tb) -> None: + return self.lock.release() + + def release_lock(self): + # Releases the lock if its locked, overriding the traditional release() method. + # Useful for per-route, not needed? for globals. + + # See #428. + + if self.lock.locked(): + self.lock.release() diff --git a/interactions/api/http/Limiter.pyi b/interactions/api/http/Limiter.pyi new file mode 100644 index 000000000..f7e2ffd5b --- /dev/null +++ b/interactions/api/http/Limiter.pyi @@ -0,0 +1,13 @@ +from asyncio import Lock +from typing import Optional +from interactions.api.models.misc import MISSING + +class Limiter: + + lock: Lock + reset_after: float + + def __init__(self, *, lock: Lock, reset_after: Optional[float] = MISSING) -> None: ... + async def __aenter__(self) -> "Limiter": ... + async def __aexit__(self, exc_type, exc_val, exc_tb) -> None: ... + def release_lock(self): ... diff --git a/interactions/api/http/Request.py b/interactions/api/http/Request.py new file mode 100644 index 000000000..f563b37c1 --- /dev/null +++ b/interactions/api/http/Request.py @@ -0,0 +1,213 @@ +import asyncio +import traceback +from asyncio import AbstractEventLoop, Lock, get_event_loop, get_running_loop, new_event_loop +from json import dumps +from logging import Logger +from sys import version_info +from typing import Any, Dict, Optional +from urllib.parse import quote + +from aiohttp import ClientSession +from aiohttp import __version__ as http_version + +from interactions.base import __version__, get_logger + +from ...api.error import HTTPException +from .Limiter import Limiter +from .Route import Route + +log: Logger = get_logger("http") +_session: ClientSession = ClientSession() + + +class Request: + """ + A class representing how HTTP requests are sent/read. + + :ivar str token: The current application token. + :ivar AbstractEventLoop _loop: The current coroutine event loop. + :ivar Dict[str, Limiter] ratelimits: The current per-route rate limiters from the API. + :ivar Dict[str, str] buckets: The current endpoint to shared_bucket cache from the API. + :ivar dict _headers: The current headers for an HTTP request. + :ivar ClientSession _session: The current session for making requests. + :ivar Limiter _global_lock: The global rate limiter. + """ + + __slots__ = ( + "token", + "_loop", + "ratelimits", + "buckets", + "_headers", + "_session", + "_global_lock", + ) + token: str + _loop: AbstractEventLoop + ratelimits: Dict[str, Limiter] # bucket: Limiter + buckets: Dict[str, str] # endpoint: shared_bucket + _headers: dict + _session: ClientSession + _global_lock: Limiter + + def __init__(self, token: str) -> None: + """ + :param token: The application token used for authorizing. + :type token: str + """ + self.token = token + try: + self._loop = get_event_loop() if version_info < (3, 10) else get_running_loop() + except RuntimeError: + self._loop = new_event_loop() + self.ratelimits = {} + self.buckets = {} + self._headers = { + "Authorization": f"Bot {self.token}", + "User-Agent": f"DiscordBot (https://github.com/interactions-py/library {__version__}) " + f"Python/{version_info[0]}.{version_info[1]} " + f"aiohttp/{http_version}", + } + self._session = _session + self._global_lock = ( + Limiter(lock=Lock(loop=self._loop)) if version_info < (3, 10) else Limiter(lock=Lock()) + ) + + def _check_session(self) -> None: + """Ensures that we have a valid connection session.""" + if self._session.closed: + self._session = ClientSession() + + async def _check_lock(self) -> None: + """Checks the global lock for its current state.""" + if self._global_lock.lock.locked(): + log.warning("The HTTP client is still globally locked, waiting for it to clear.") + await self._global_lock.lock.acquire() + self._global_lock.reset_after = 0 + + async def request(self, route: Route, **kwargs) -> Optional[Any]: + r""" + Sends a request to the Discord API. + + :param route: The HTTP route to request. + :type route: Route + :param \**kwargs?: Optional keyword-only arguments to pass as information in the request. + :type \**kwargs: dict + :return: The contents of the request if any. + :rtype: Optional[Any] + """ + + kwargs["headers"] = {**self._headers, **kwargs.get("headers", {})} + kwargs["headers"]["Content-Type"] = "application/json" + + reason = kwargs.pop("reason", None) + if reason: + kwargs["headers"]["X-Audit-Log-Reason"] = quote(reason, safe="/ ") + + # Huge credit and thanks to LordOfPolls for the lock/retry logic. + + bucket = route.get_bucket( + self.buckets.get(route.endpoint) + ) # string returning path OR prioritised hash bucket metadata. + + # The idea is that its regulated by the priority of Discord's bucket header and not just self-computation. + + if self.ratelimits.get(bucket): + _limiter: Limiter = self.ratelimits.get(bucket) + if _limiter.lock.locked(): + if ( + _limiter.reset_after != 0 + ): # Just saying 0 seconds isn't helpful, so this is suppressed. + log.warning( + f"The current bucket is still under a rate limit. Calling later in {_limiter.reset_after} seconds." + ) + self._loop.call_later(_limiter.reset_after, _limiter.release_lock) + _limiter.reset_after = 0 + else: + self.ratelimits[bucket] = ( + Limiter(lock=Lock(loop=self._loop)) + if version_info < (3, 10) + else Limiter(lock=Lock()) + ) + _limiter: Limiter = self.ratelimits.get(bucket) + + await _limiter.lock.acquire() # _limiter is the per shared bucket/route endpoint + + # Implement retry logic. The common seems to be 5, so this is hardcoded, for the most part. + + for tries in range(5): # 3, 5? 5 seems to be common + try: + self._check_session() + await self._check_lock() + + async with self._session.request( + route.method, route.__api__ + route.path, **kwargs + ) as response: + + data = await response.json(content_type=None) + reset_after: float = float( + response.headers.get("X-RateLimit-Reset-After", "0.0") + ) + remaining: str = response.headers.get("X-RateLimit-Remaining") + _bucket: str = response.headers.get("X-RateLimit-Bucket") + is_global: bool = response.headers.get("X-RateLimit-Global", False) + + log.debug(f"{route.method}: {route.__api__ + route.path}: {kwargs}") + + if _bucket is not None: + self.buckets[route.endpoint] = _bucket + # real-time replacement/update/add if needed. + + if isinstance(data, dict) and data.get("errors"): + log.debug( + f"RETURN {response.status}: {dumps(data, indent=4, sort_keys=True)}" + ) + # This "redundant" debug line is for debug use and tracing back the error codes. + + raise HTTPException(data["code"], message=data["message"]) + elif remaining and not int(remaining): + if response.status == 429: + log.warning( + f"The HTTP client has encountered a per-route ratelimit. Locking down future requests for {reset_after} seconds." + ) + _limiter.reset_after = reset_after + await asyncio.sleep(_limiter.reset_after) + continue + elif is_global: + log.warning( + f"The HTTP client has encountered a global ratelimit. Locking down future requests for {reset_after} seconds." + ) + self._global_lock.reset_after = reset_after + self._loop.call_later( + self._global_lock.reset_after, self._global_lock.lock.release + ) + + log.debug(f"RETURN {response.status}: {dumps(data, indent=4, sort_keys=True)}") + + _limiter.release_lock() # checks if its locked, then releases upon success. + + return data + + # These account for general/specific exceptions. (Windows...) + except OSError as e: + if tries < 4 and e.errno in (54, 10054): + await asyncio.sleep(2 * tries + 1) + continue + try: + _limiter.lock.release() + except RuntimeError: + pass + raise + + # For generic exceptions we give a traceback for debug reasons. + except Exception as e: + try: + _limiter.lock.release() + except RuntimeError: + pass + log.error("".join(traceback.format_exception(type(e), e, e.__traceback__))) + break + + async def close(self) -> None: + """Closes the current session.""" + await self.session.close() diff --git a/interactions/api/http/Request.pyi b/interactions/api/http/Request.pyi new file mode 100644 index 000000000..8eca0551c --- /dev/null +++ b/interactions/api/http/Request.pyi @@ -0,0 +1,22 @@ +from asyncio import AbstractEventLoop +from typing import Any, Dict, Optional +from aiohttp import ClientSession +from aiohttp import __version__ as http_version +from .Limiter import Limiter +from .Route import Route + +class Request: + + token: str + _loop: AbstractEventLoop + ratelimits: Dict[str, Limiter] + buckets: Dict[str, str] + _headers: dict + _session: ClientSession + _global_lock: Limiter + + def __init__(self, token: str) -> None: ... + def _check_session(self) -> None: ... + async def _check_lock(self) -> None: ... + async def request(self, route: Route, **kwargs) -> Optional[Any]: ... + async def close(self) -> None: ... diff --git a/interactions/api/http/Route.py b/interactions/api/http/Route.py new file mode 100644 index 000000000..52884993c --- /dev/null +++ b/interactions/api/http/Route.py @@ -0,0 +1,62 @@ +from typing import ClassVar, Optional + + +class Route: + """ + A class representing how an HTTP route is structured. + + :ivar ClassVar[str] __api__: The HTTP route path. + :ivar str method: The HTTP method. + :ivar str path: The URL path. + :ivar Optional[str] channel_id: The channel ID from the bucket if given. + :ivar Optional[str] guild_id: The guild ID from the bucket if given. + """ + + __slots__ = ("__api__", "method", "path", "channel_id", "guild_id") + __api__: ClassVar[str] + method: str + path: str + channel_id: Optional[str] + guild_id: Optional[str] + + def __init__(self, method: str, path: str, **kwargs) -> None: + r""" + :param method: The HTTP request method. + :type method: str + :param path: The path of the HTTP/URL. + :type path: str + :param \**kwargs?: Optional keyword-only arguments to pass as information in the route. + :type \**kwargs: dict + """ + self.__api__ = "https://discord.com/api/v10" + self.method = method + self.path = path.format(**kwargs) + self.channel_id = kwargs.get("channel_id") + self.guild_id = kwargs.get("guild_id") + + def get_bucket(self, shared_bucket: Optional[str] = None) -> str: + """ + Returns the route's bucket. If shared_bucket is None, returns the path with major parameters. + Otherwise, it relies on Discord's given bucket. + + :param shared_bucket: The bucket that Discord provides, if available. + :type shared_bucket: Optional[str] + + :return: The route bucket. + :rtype: str + """ + return ( + f"{self.channel_id}:{self.guild_id}:{self.path}" + if shared_bucket is None + else f"{self.channel_id}:{self.guild_id}:{shared_bucket}" + ) + + @property + def endpoint(self) -> str: + """ + Returns the route's endpoint. + + :return: The route endpoint. + :rtype: str + """ + return f"{self.method}:{self.path}" diff --git a/interactions/api/http/Route.pyi b/interactions/api/http/Route.pyi new file mode 100644 index 000000000..eabd89f90 --- /dev/null +++ b/interactions/api/http/Route.pyi @@ -0,0 +1,14 @@ +from typing import ClassVar, Optional + +class Route: + + __api__: ClassVar[str] + method: str + path: str + channel_id: Optional[str] + guild_id: Optional[str] + + def __init__(self, method: str, path: str, **kwargs) -> None: ... + def get_bucket(self, shared_bucket: Optional[str] = None) -> str: ... + @property + def endpoint(self) -> str: ... From 19638165c94a28fb99cf51ca4dc603bb05282616 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Tue, 1 Mar 2022 20:25:18 +0100 Subject: [PATCH 07/47] Delete http.py --- interactions/api/http.py | 2745 -------------------------------------- 1 file changed, 2745 deletions(-) delete mode 100644 interactions/api/http.py diff --git a/interactions/api/http.py b/interactions/api/http.py deleted file mode 100644 index 661a65436..000000000 --- a/interactions/api/http.py +++ /dev/null @@ -1,2745 +0,0 @@ -import asyncio -import traceback -from asyncio import AbstractEventLoop, Lock, get_event_loop, get_running_loop, new_event_loop -from json import dumps -from logging import Logger -from sys import version_info -from typing import Any, ClassVar, Dict, List, Optional, Tuple, Union -from urllib.parse import quote - -from aiohttp import ClientSession, FormData -from aiohttp import __version__ as http_version - -import interactions.api.cache -from interactions.api.models.misc import MISSING -from interactions.base import __version__, get_logger - -from ..api.cache import Cache, Item -from ..api.error import HTTPException -from ..api.models import Channel, Embed, Emoji, Guild, Member, Message, Role, Snowflake, User - -log: Logger = get_logger("http") - -__all__ = ("Route", "Request", "HTTPClient") -_session: ClientSession = ClientSession() - - -class Route: - """ - A class representing how an HTTP route is structured. - - :ivar ClassVar[str] __api__: The HTTP route path. - :ivar str method: The HTTP method. - :ivar str path: The URL path. - :ivar Optional[str] channel_id: The channel ID from the bucket if given. - :ivar Optional[str] guild_id: The guild ID from the bucket if given. - """ - - __slots__ = ("__api__", "method", "path", "channel_id", "guild_id") - __api__: ClassVar[str] - method: str - path: str - channel_id: Optional[str] - guild_id: Optional[str] - - def __init__(self, method: str, path: str, **kwargs) -> None: - r""" - :param method: The HTTP request method. - :type method: str - :param path: The path of the HTTP/URL. - :type path: str - :param \**kwargs?: Optional keyword-only arguments to pass as information in the route. - :type \**kwargs: dict - """ - self.__api__ = "https://discord.com/api/v10" - self.method = method - self.path = path.format(**kwargs) - self.channel_id = kwargs.get("channel_id") - self.guild_id = kwargs.get("guild_id") - - def get_bucket(self, shared_bucket: Optional[str] = None) -> str: - """ - Returns the route's bucket. If shared_bucket is None, returns the path with major parameters. - Otherwise, it relies on Discord's given bucket. - - :param shared_bucket: The bucket that Discord provides, if available. - :type shared_bucket: Optional[str] - - :return: The route bucket. - :rtype: str - """ - return ( - f"{self.channel_id}:{self.guild_id}:{self.path}" - if shared_bucket is None - else f"{self.channel_id}:{self.guild_id}:{shared_bucket}" - ) - - @property - def endpoint(self) -> str: - """ - Returns the route's endpoint. - - :return: The route endpoint. - :rtype: str - """ - return f"{self.method}:{self.path}" - - -class Limiter: - """ - A class representing a limitation for an HTTP request. - - :ivar Lock lock: The "lock" or controller of the request. - :ivar float reset_after: The remaining time before the request can be ran. - """ - - lock: Lock - reset_after: float - - def __init__(self, *, lock: Lock, reset_after: Optional[float] = MISSING) -> None: - """ - :param lock: The asynchronous lock to control limits for. - :type lock: Lock - :param reset_after: The remaining time to run the limited lock on. Defaults to ``0``. - :type reset_after: Optional[float] - """ - self.lock = lock - self.reset_after = 0 if reset_after is MISSING else reset_after - - async def __aenter__(self) -> "Limiter": - await self.lock.acquire() - return self - - async def __aexit__(self, exc_type, exc_val, exc_tb) -> None: - return self.lock.release() - - def release_lock(self): - # Releases the lock if its locked, overriding the traditional release() method. - # Useful for per-route, not needed? for globals. - - # See #428. - - if self.lock.locked(): - self.lock.release() - - -class Request: - """ - A class representing how HTTP requests are sent/read. - - :ivar str token: The current application token. - :ivar AbstractEventLoop _loop: The current coroutine event loop. - :ivar Dict[str, Limiter] ratelimits: The current per-route rate limiters from the API. - :ivar Dict[str, str] buckets: The current endpoint to shared_bucket cache from the API. - :ivar dict _headers: The current headers for an HTTP request. - :ivar ClientSession _session: The current session for making requests. - :ivar Limiter _global_lock: The global rate limiter. - """ - - __slots__ = ( - "token", - "_loop", - "ratelimits", - "buckets", - "_headers", - "_session", - "_global_lock", - ) - token: str - _loop: AbstractEventLoop - ratelimits: Dict[str, Limiter] # bucket: Limiter - buckets: Dict[str, str] # endpoint: shared_bucket - _headers: dict - _session: ClientSession - _global_lock: Limiter - - def __init__(self, token: str) -> None: - """ - :param token: The application token used for authorizing. - :type token: str - """ - self.token = token - try: - self._loop = get_event_loop() if version_info < (3, 10) else get_running_loop() - except RuntimeError: - self._loop = new_event_loop() - self.ratelimits = {} - self.buckets = {} - self._headers = { - "Authorization": f"Bot {self.token}", - "User-Agent": f"DiscordBot (https://github.com/interactions-py/library {__version__}) " - f"Python/{version_info[0]}.{version_info[1]} " - f"aiohttp/{http_version}", - } - self._session = _session - self._global_lock = ( - Limiter(lock=Lock(loop=self._loop)) if version_info < (3, 10) else Limiter(lock=Lock()) - ) - - def _check_session(self) -> None: - """Ensures that we have a valid connection session.""" - if self._session.closed: - self._session = ClientSession() - - async def _check_lock(self) -> None: - """Checks the global lock for its current state.""" - if self._global_lock.lock.locked(): - log.warning("The HTTP client is still globally locked, waiting for it to clear.") - await self._global_lock.lock.acquire() - self._global_lock.reset_after = 0 - - async def request(self, route: Route, **kwargs) -> Optional[Any]: - r""" - Sends a request to the Discord API. - - :param route: The HTTP route to request. - :type route: Route - :param \**kwargs?: Optional keyword-only arguments to pass as information in the request. - :type \**kwargs: dict - :return: The contents of the request if any. - :rtype: Optional[Any] - """ - - kwargs["headers"] = {**self._headers, **kwargs.get("headers", {})} - kwargs["headers"]["Content-Type"] = "application/json" - - reason = kwargs.pop("reason", None) - if reason: - kwargs["headers"]["X-Audit-Log-Reason"] = quote(reason, safe="/ ") - - # Huge credit and thanks to LordOfPolls for the lock/retry logic. - - bucket = route.get_bucket( - self.buckets.get(route.endpoint) - ) # string returning path OR prioritised hash bucket metadata. - - # The idea is that its regulated by the priority of Discord's bucket header and not just self-computation. - - if self.ratelimits.get(bucket): - _limiter: Limiter = self.ratelimits.get(bucket) - if _limiter.lock.locked(): - if ( - _limiter.reset_after != 0 - ): # Just saying 0 seconds isn't helpful, so this is suppressed. - log.warning( - f"The current bucket is still under a rate limit. Calling later in {_limiter.reset_after} seconds." - ) - self._loop.call_later(_limiter.reset_after, _limiter.release_lock) - _limiter.reset_after = 0 - else: - self.ratelimits[bucket] = ( - Limiter(lock=Lock(loop=self._loop)) - if version_info < (3, 10) - else Limiter(lock=Lock()) - ) - _limiter: Limiter = self.ratelimits.get(bucket) - - await _limiter.lock.acquire() # _limiter is the per shared bucket/route endpoint - - # Implement retry logic. The common seems to be 5, so this is hardcoded, for the most part. - - for tries in range(5): # 3, 5? 5 seems to be common - try: - self._check_session() - await self._check_lock() - - async with self._session.request( - route.method, route.__api__ + route.path, **kwargs - ) as response: - - data = await response.json(content_type=None) - reset_after: float = float( - response.headers.get("X-RateLimit-Reset-After", "0.0") - ) - remaining: str = response.headers.get("X-RateLimit-Remaining") - _bucket: str = response.headers.get("X-RateLimit-Bucket") - is_global: bool = response.headers.get("X-RateLimit-Global", False) - - log.debug(f"{route.method}: {route.__api__ + route.path}: {kwargs}") - - if _bucket is not None: - self.buckets[route.endpoint] = _bucket - # real-time replacement/update/add if needed. - - if isinstance(data, dict) and data.get("errors"): - log.debug( - f"RETURN {response.status}: {dumps(data, indent=4, sort_keys=True)}" - ) - # This "redundant" debug line is for debug use and tracing back the error codes. - - raise HTTPException(data["code"], message=data["message"]) - elif remaining and not int(remaining): - if response.status == 429: - log.warning( - f"The HTTP client has encountered a per-route ratelimit. Locking down future requests for {reset_after} seconds." - ) - _limiter.reset_after = reset_after - await asyncio.sleep(_limiter.reset_after) - continue - elif is_global: - log.warning( - f"The HTTP client has encountered a global ratelimit. Locking down future requests for {reset_after} seconds." - ) - self._global_lock.reset_after = reset_after - self._loop.call_later( - self._global_lock.reset_after, self._global_lock.lock.release - ) - - log.debug(f"RETURN {response.status}: {dumps(data, indent=4, sort_keys=True)}") - - _limiter.release_lock() # checks if its locked, then releases upon success. - - return data - - # These account for general/specific exceptions. (Windows...) - except OSError as e: - if tries < 4 and e.errno in (54, 10054): - await asyncio.sleep(2 * tries + 1) - continue - try: - _limiter.lock.release() - except RuntimeError: - pass - raise - - # For generic exceptions we give a traceback for debug reasons. - except Exception as e: - try: - _limiter.lock.release() - except RuntimeError: - pass - log.error("".join(traceback.format_exception(type(e), e, e.__traceback__))) - break - - async def close(self) -> None: - """Closes the current session.""" - await self.session.close() - - -class HTTPClient: - """ - The user-facing client of the Web API for individual endpoints. - - :ivar str token: The token of the application. - :ivar Request _req: The requesting interface for endpoints. - :ivar Cache cache: The referenced cache. - """ - - token: str - _req: Request - cache: Cache - - def __init__(self, token: str): - self.token = token - self._req = Request(self.token) - self.cache = interactions.api.cache.ref_cache - - # An ideology is that this client does every single HTTP call, which reduces multiple ClientSessions in theory - # because of how they are constructed/closed. This includes Gateway - - async def get_gateway(self) -> str: - """This calls the Gateway endpoint and returns a v9 gateway link with JSON encoding.""" - - url: Any = await self._req.request( - Route("GET", "/gateway") - ) # typehinting Any because pycharm yells - return f'{url["url"]}?v=10&encoding=json' - - async def get_bot_gateway(self) -> Tuple[int, str]: - """ - This calls the BOT Gateway endpoint. - - :return: A tuple denoting (shard, gateway_url), url from API v9 and JSON encoding - """ - - data: Any = await self._req.request(Route("GET", "/gateway/bot")) - return data["shards"], f'{data["url"]}?v=9&encoding=json' - - async def login(self) -> Optional[dict]: - """ - This 'logins' to the gateway, which makes it available to use any other endpoint. - """ - - return await self._req.request( - Route("GET", "/users/@me") - ) # Internally raises any Exception. - - async def logout(self) -> None: - """This 'log outs' the session.""" - - await self._req.request(Route("POST", "/auth/logout")) - - @property - def req(self): - return self._req - - # ---- Oauth2 endpoint - - async def get_current_bot_information(self) -> dict: - """ - Returns the bot user application object without flags. - """ - return await self._req.request(Route("GET", "/oauth2/applications/@me")) - - async def get_current_authorisation_information(self) -> dict: - """ - Returns info about the current authorization of the bot user - """ - return await self._req.request(Route("GET", "/oauth2/@me")) - - # ---- User endpoint - - async def get_self(self) -> dict: - """ - An alias to `get_user`, but only gets the current bot user. - - :return: A partial User object of the current bot user in the form of a dictionary. - """ - return await self.get_user() - - async def get_user(self, user_id: Optional[int] = None) -> dict: - """ - Gets a user object for a given user ID. - - :param user_id: A user snowflake ID. If omitted, this defaults to the current bot user. - :return: A partial User object in the form of a dictionary. - """ - - if user_id is None: - user_id = "@me" - - request = await self._req.request(Route("GET", f"/users/{user_id}")) - self.cache.users.add(Item(id=user_id, value=User(**request))) - - return request - - async def modify_self(self, payload: dict) -> dict: - """ - Modify the bot user account settings. - - :param payload: The data to send. - """ - return await self._req.request(Route("PATCH", "/users/@me"), json=payload) - - async def modify_self_nick_in_guild(self, guild_id: int, nickname: Optional[str]) -> dict: - """ - Changes a nickname of the current bot user in a guild. - - :param guild_id: Guild snowflake ID. - :param nickname: The new nickname, if any. - :return: Nothing needed to be yielded. - """ - return await self._req.request( - Route("PATCH", "/guilds/{guild_id}/members/@me/nick", guild_id=guild_id), - json={"nick": nickname}, - ) - - async def create_dm(self, recipient_id: int) -> dict: - """ - Creates a new DM channel with a user. - - :param recipient_id: User snowflake ID. - :return: Returns a dictionary representing a DM Channel object. - """ - # only named recipient_id because of api mirroring - - request = await self._req.request( - Route("POST", "/users/@me/channels"), json={"recipient_id": recipient_id} - ) - self.cache.dms.add(Item(id=str(recipient_id), value=Channel(**request))) - - return request - - # Message endpoint - - async def send_message( - self, - channel_id: Union[int, Snowflake], - content: str, - tts: bool = False, - embeds: Optional[List[Embed]] = None, - nonce: Union[int, str] = None, - allowed_mentions=None, # don't know type - message_reference: Optional[Message] = None, - ) -> dict: - """ - A higher level implementation of :meth:`create_message()` that handles the payload dict internally. - Does not integrate components into the function, and is a port from v3.0.0 - """ - payload = {} - - if content: - payload["content"] = content - - if tts: - payload["tts"] = True - - if embeds: - payload["embeds"] = embeds - - if nonce: - payload["nonce"] = nonce - - if allowed_mentions: - payload["allowed_mentions"] = allowed_mentions - - if message_reference: - payload["message_reference"] = message_reference - - # TODO: post-v4. add attachments to payload. - - if isinstance(channel_id, Snowflake): - channel_id = int(channel_id) - - return await self.create_message(payload, channel_id) - - async def create_message(self, payload: dict, channel_id: int) -> dict: - """ - Send a message to the specified channel. - - :param payload: Dictionary contents of a message. (i.e. message payload) - :param channel_id: Channel snowflake ID. - :return dict: Dictionary representing a message (?) - """ - request = await self._req.request( - Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id), json=payload - ) - if request.get("id"): - self.cache.messages.add(Item(id=request["id"], value=Message(**request))) - - return request - - async def get_message(self, channel_id: int, message_id: int) -> Optional[dict]: - """ - Get a specific message in the channel. - - :param channel_id: the channel this message belongs to - :param message_id: the id of the message - :return: message if it exists. - """ - return await self._req.request( - Route("GET", f"/channels/{channel_id}/messages/{message_id}") - ) - - async def delete_message( - self, channel_id: int, message_id: int, reason: Optional[str] = None - ) -> None: - """ - Deletes a message from a specified channel. - - :param channel_id: Channel snowflake ID. - :param message_id: Message snowflake ID. - :param reason: Optional reason to show up in the audit log. Defaults to `None`. - """ - r = Route( - "DELETE", - "/channels/{channel_id}/messages/{message_id}", - channel_id=channel_id, - message_id=message_id, - ) - return await self._req.request(r, reason=reason) - - async def delete_messages( - self, channel_id: int, message_ids: List[int], reason: Optional[str] = None - ) -> None: - """ - Deletes messages from a specified channel. - - :param channel_id: Channel snowflake ID. - :param message_ids: An array of message snowflake IDs. - :param reason: Optional reason to show up in the audit log. Defaults to `None`. - """ - r = Route("POST", "/channels/{channel_id}/messages/bulk-delete", channel_id=channel_id) - payload = { - "messages": message_ids, - } - - return await self._req.request(r, json=payload, reason=reason) - - async def edit_message(self, channel_id: int, message_id: int, payload: dict) -> dict: - """ - Edits a message that already exists. - - :param channel_id: Channel snowflake ID. - :param message_id: Message snowflake ID. - :param payload: Any new data that needs to be changed. - :type payload: dict - :return: A message object with edited attributes. - """ - return await self._req.request( - Route( - "PATCH", - "/channels/{channel_id}/messages/{message_id}", - channel_id=channel_id, - message_id=message_id, - ), - json=payload, - ) - - async def pin_message(self, channel_id: int, message_id: int) -> None: - """ - Pin a message to a channel. - - :param channel_id: Channel ID snowflake. - :param message_id: Message ID snowflake. - """ - return await self._req.request(Route("PUT", f"/channels/{channel_id}/pins/{message_id}")) - - async def unpin_message(self, channel_id: int, message_id: int) -> None: - """ - Unpin a message to a channel. - - :param channel_id: Channel ID snowflake. - :param message_id: Message ID snowflake. - """ - return await self._req.request(Route("DELETE", f"/channels/{channel_id}/pins/{message_id}")) - - async def publish_message(self, channel_id: int, message_id: int) -> dict: - """ - Publishes (API calls it crossposts) a message in a News channel to any that is followed by. - - :param channel_id: Channel the message is in - :param message_id: The id of the message to publish - :return: message object - """ - return await self._req.request( - Route("POST", f"/channels/{channel_id}/messages/{message_id}/crosspost") - ) - - # Guild endpoint - - async def get_self_guilds(self) -> List[dict]: - """ - Gets all guild objects associated with the current bot user. - - :return a list of partial guild objects the current bot user is a part of. - """ - request = await self._req.request(Route("GET", "/users/@me/guilds")) - - for guild in request: - if guild.get("id"): - self.cache.self_guilds.add(Item(id=guild["id"], value=Guild(**guild))) - - return request - - async def get_guild(self, guild_id: int) -> Optional[dict]: - """ - Requests an individual guild from the API. - - :param guild_id: The guild snowflake ID associated. - :return: The guild object associated, if any. - """ - request = await self._req.request(Route("GET", "/guilds/{guild_id}", guild_id=guild_id)) - self.cache.guilds.add(Item(id=str(guild_id), value=Guild(**request))) - - return request - - async def get_guild_preview(self, guild_id: int) -> dict: - """ - Get a guild's preview. - - :param guild_id: Guild ID snowflake. - :return: Guild Preview object associated with the snowflake - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/preview")) - - async def modify_guild( - self, guild_id: int, payload: dict, reason: Optional[str] = None - ) -> dict: - """ - Modifies a guild's attributes. - - :param guild_id: Guild ID snowflake. - :param payload: The parameters to change. - :param reason: Reason to send to the audit log, if given. - :return: The modified guild object as a dictionary - :rtype: dict - """ - - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}"), json=payload, reason=reason - ) - - async def leave_guild(self, guild_id: int) -> None: - """ - Leaves a guild. - - :param guild_id: The guild snowflake ID associated. - :return: None - """ - return await self._req.request( - Route("DELETE", f"/users/@me/guilds/{guild_id}", guild_id=guild_id) - ) - - async def delete_guild(self, guild_id: int) -> None: - """ - Deletes a guild. - - :param guild_id: Guild ID snowflake. - """ - return await self._req.request(Route("DELETE", f"/guilds/{guild_id}")) - - async def get_guild_widget(self, guild_id: int) -> dict: - """ - Returns the widget for the guild. - - :param guild_id: Guild ID snowflake. - :return: Guild Widget contents as a dict: {"enabled":bool, "channel_id": str} - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/widget.json")) - - async def get_guild_widget_settings(self, guild_id: int) -> dict: - """ - Get guild widget settings. - - :param guild_id: Guild ID snowflake. - :return: Guild Widget contents as a dict: {"enabled":bool, "channel_id": str} - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}")) - - async def get_guild_widget_image(self, guild_id: int, style: Optional[str] = None) -> str: - """ - Get an url representing a png image widget for the guild. - - ..note:: - See _ for list of styles. - - :param guild_id: Guild ID snowflake. - :param style: The style of widget required, if given. - :return: A url pointing to this image - """ - route = Route("GET", f"/guilds/{guild_id}/widget.png{f'?style={style}' if style else ''}") - return route.path - - async def modify_guild_widget(self, guild_id: int, payload: dict) -> dict: - """ - Modify a guild widget. - - :param guild_id: Guild ID snowflake. - :param payload: Payload containing new widget attributes. - :return: Updated widget attributes. - """ - return await self._req.request(Route("PATCH", f"/guilds/{guild_id}/widget"), json=payload) - - async def get_guild_invites(self, guild_id: int) -> List[dict]: - """ - Retrieves a list of invite objects with their own metadata. - - :param guild_id: Guild ID snowflake. - :return: A list of invite objects - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/invites")) - - async def get_guild_welcome_screen(self, guild_id: int) -> dict: - """ - Retrieves from the API a welcome screen associated with the guild. - - :param guild_id: Guild ID snowflake. - :return: Welcome Screen object - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/welcome-screen")) - - async def modify_guild_welcome_screen( - self, guild_id: int, enabled: bool, welcome_channels: List[int], description: str - ) -> dict: - """ - Modify the guild's welcome screen. - - :param guild_id: Guild ID snowflake. - :param enabled: Whether the welcome screen is enabled or not. - :param welcome_channels: The new channels (by their ID) linked in the welcome screen and their display options - :param description: The new server description to show in the welcome screen - :return: Updated Welcome screen object. - """ - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/welcome-screen"), - json={ - "enabled": enabled, - "welcome_channels": welcome_channels, - "description": description, - }, - ) - - async def get_vanity_code(self, guild_id: int) -> dict: - return await self._req.request( - Route("GET", "/guilds/{guild_id}/vanity-url", guild_id=guild_id) - ) - - async def modify_vanity_code( - self, guild_id: int, code: str, reason: Optional[str] = None - ) -> None: - payload: Dict[str, Any] = {"code": code} - return await self._req.request( - Route("PATCH", "/guilds/{guild_id}/vanity-url", guild_id=guild_id), - json=payload, - reason=reason, - ) - - async def get_guild_integrations(self, guild_id: int) -> List[dict]: - """ - Gets a list of integration objects associated with the Guild from the API. - - :param guild_id: Guild ID snowflake. - :return: An array of integration objects - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/integrations")) - - async def delete_guild_integration(self, guild_id: int, integration_id: int) -> None: - """ - Deletes an integration from the guild. - - :param guild_id: Guild ID snowflake. - :param integration_id: Integration ID snowflake. - """ - return await self._req.request( - Route("DELETE", f"/guilds/{guild_id}/integrations/{integration_id}") - ) - - async def modify_current_user_voice_state( - self, - guild_id: int, - channel_id: int, - suppress: Optional[bool] = None, - request_to_speak_timestamp: Optional[str] = None, - ) -> dict: - """ - Update the current user voice state. - - :param guild_id: Guild ID snowflake. - :param channel_id: Voice channel ID snowflake. - :param suppress: Toggle the user's suppress state, if given. - :param request_to_speak_timestamp: Sets the user's request to speak, if given. - """ - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/voice-states/@me"), - json={ - k: v - for k, v in { - "channel_id": channel_id, - "suppress": suppress, - "request_to_speak_timestamp": request_to_speak_timestamp, - }.items() - if v is not None - }, - ) - - async def modify_user_voice_state( - self, guild_id: int, user_id: int, channel_id: int, suppress: Optional[bool] = None - ) -> dict: - """ - Modify the voice state of a user. - - :param guild_id: Guild ID snowflake. - :param user_id: User ID snowflake. - :param channel_id: Voice channel ID snowflake. - :param suppress: Toggles the user's suppress state, if given. - """ - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/voice-states/{user_id}"), - json={ - k: v - for k, v in {"channel_id": channel_id, "suppress": suppress}.items() - if v is not None - }, - ) - - async def create_guild_from_guild_template( - self, template_code: str, name: str, icon: Optional[str] = None - ) -> dict: - """ - Create a new guild based on a template. - - ..note:: - This endpoint can only be used by bots in less than 10 guilds. - - :param template_code: The code of the template to use. - :param name: The name of the guild (2-100 characters) - :param icon: Guild icon URI, if given. - :return: The newly created guild object. - """ - payload = { - "name": name, - } - if icon: - payload["icon"] = icon - return await self._req.request( - Route("POST", f"/guilds/templates/{template_code}", json=payload) - ) - - async def get_guild_templates(self, guild_id: int) -> List[dict]: - """ - Returns an array of guild templates. - - :param guild_id: Guild ID snowflake. - :return: An array of guild templates - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/templates")) - - async def create_guild_template( - self, guild_id: int, name: str, description: Optional[str] = None - ) -> dict: - """ - Create a guild template for the guild. - - :param guild_id: Guild ID snowflake. - :param name: The name of the template - :param description: The description of the template, if given. - :return: The created guild template - """ - return await self._req.request( - Route("POST", f"/guilds/{guild_id}/templates"), - json={ - k: v for k, v in {"name": name, "description": description}.items() if v is not None - }, - ) - - async def sync_guild_template(self, guild_id: int, template_code: str) -> dict: - """ - Sync the template to the guild's current state. - - :param guild_id: Guild ID snowflake. - :param template_code: The code for the template to sync - :return: The updated guild template. - """ - return await self._req.request( - Route("PUT", f"/guilds/{guild_id}/templates/{template_code}") - ) - - async def modify_guild_template( - self, - guild_id: int, - template_code: str, - name: Optional[str] = None, - description: Optional[str] = None, - ) -> dict: - """ - Modify a guild template. - - :param guild_id: Guild ID snowflake. - :param template_code: Template ID. - :param name: The name of the template - :param description: The description of the template - :return: The updated guild template - """ - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/templates/{template_code}"), - json={ - k: v for k, v in {"name": name, "description": description}.items() if v is not None - }, - ) - - async def delete_guild_template(self, guild_id: int, template_code: str) -> dict: - """ - Delete the guild template. - - :param guild_id: Guild ID snowflake. - :param template_code: Template ID. - :return: The deleted template object - """ - # According to Polls, this returns the object. Why, I don't know. - return await self._req.request( - Route("DELETE", f"/guilds/{guild_id}/templates/{template_code}") - ) - - async def get_all_channels(self, guild_id: int) -> List[dict]: - """ - Requests from the API to get all channels in the guild. - - :param guild_id: Guild Snowflake ID - :return: A list of channels. - """ - request = await self._req.request( - Route("GET", "/guilds/{guild_id}/channels", guild_id=guild_id) - ) - - for channel in request: - if channel.get("id"): - self.cache.channels.add(Item(id=channel["id"], value=Channel(**channel))) - - return request - - async def get_all_roles(self, guild_id: int) -> List[dict]: - """ - Gets all roles from a Guild. - - :param guild_id: Guild ID snowflake - :return: An array of Role objects as dictionaries. - """ - request = await self._req.request( - Route("GET", "/guilds/{guild_id}/roles", guild_id=guild_id) - ) - - for role in request: - if role.get("id"): - self.cache.roles.add(Item(id=role["id"], value=Role(**role))) - - return request - - async def create_guild_role( - self, guild_id: int, payload: dict, reason: Optional[str] = None - ) -> dict: - """ - Create a new role for the guild. - - :param guild_id: Guild ID snowflake. - :param payload: A dict containing metadata for the role. - :param reason: The reason for this action, if given. - :return: Role object - """ - request = await self._req.request( - Route("POST", f"/guilds/{guild_id}/roles"), json=payload, reason=reason - ) - if request.get("id"): - self.cache.roles.add(Item(id=request["id"], value=Role(**request))) - - return request - - async def modify_guild_role_position( - self, guild_id: int, role_id: int, position: int, reason: Optional[str] = None - ) -> List[dict]: - """ - Modify the position of a role in the guild. - - :param guild_id: Guild ID snowflake. - :param role_id: Role ID snowflake. - :param position: The new position of the associated role. - :param reason: The reason for this action, if given. - :return: List of guild roles with updated hierarchy. - """ - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/roles"), - json={"id": role_id, "position": position}, - reason=reason, - ) - - async def modify_guild_role( - self, guild_id: int, role_id: int, payload: dict, reason: Optional[str] = None - ) -> dict: - """ - Modify a given role for the guild. - - :param guild_id: Guild ID snowflake. - :param role_id: Role ID snowflake. - :param payload: A dict containing updated metadata for the role. - :param reason: The reason for this action, if given. - :return: Updated role object. - """ - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/roles/{role_id}"), json=payload, reason=reason - ) - - async def delete_guild_role(self, guild_id: int, role_id: int, reason: str = None) -> None: - """ - Delete a guild role. - - :param guild_id: Guild ID snowflake. - :param role_id: Role ID snowflake. - :param reason: The reason for this action, if any. - """ - return await self._req.request( - Route("DELETE", f"/guilds/{guild_id}/roles/{role_id}"), reason=reason - ) - - async def create_guild_kick( - self, guild_id: int, user_id: int, reason: Optional[str] = None - ) -> None: - """ - Kicks a person from the guild. - - :param guild_id: Guild ID snowflake - :param user_id: User ID snowflake - :param reason: Optional Reason argument. - """ - r = Route( - "DELETE", "/guilds/{guild_id}/members/{user_id}", guild_id=guild_id, user_id=user_id - ) - if reason: # apparently, its an aiohttp thing? - r.path += f"?reason={quote(reason)}" - - await self._req.request(r) - - async def create_guild_ban( - self, - guild_id: int, - user_id: int, - delete_message_days: Optional[int] = 0, - reason: Optional[str] = None, - ) -> None: - """ - Bans a person from the guild, and optionally deletes previous messages sent by them. - - :param guild_id: Guild ID snowflake - :param user_id: User ID snowflake - :param delete_message_days: Number of days to delete messages, from 0 to 7. Defaults to 0 - :param reason: Optional reason to ban. - """ - - return await self._req.request( - Route("PUT", f"/guilds/{guild_id}/bans/{user_id}"), - json={"delete_message_days": delete_message_days}, - reason=reason, - ) - - async def remove_guild_ban( - self, guild_id: int, user_id: int, reason: Optional[str] = None - ) -> None: - """ - Unbans someone using the API. - - :param guild_id: Guild ID snowflake - :param user_id: User ID snowflake - :param reason: Optional reason to unban. - """ - - return await self._req.request( - Route("DELETE", f"/guilds/{guild_id}/bans/{user_id}"), - json={}, - reason=reason, - ) - - async def get_guild_bans(self, guild_id: int) -> List[dict]: - """ - Gets a list of banned users. - - :param guild_id: Guild ID snowflake. - :return: A list of banned users. - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/bans")) - - async def get_user_ban(self, guild_id: int, user_id: int) -> Optional[dict]: - """ - Gets an object pertaining to the user, if it exists. Returns a 404 if it doesn't. - - :param guild_id: Guild ID snowflake - :param user_id: User ID snowflake. - :return: Ban object if it exists. - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/bans/{user_id}")) - - async def add_guild_member( - self, - guild_id: int, - user_id: int, - access_token: str, - nick: Optional[str] = None, - roles: Optional[List[Role]] = None, - mute: bool = None, - deaf: bool = None, - ) -> dict: - """ - A low level method of adding a user to a guild with pre-defined attributes. - - :param guild_id: Guild ID snowflake. - :param user_id: User ID snowflake. - :param access_token: User access token. - :param nick: User's nickname on join. - :param roles: An array of roles that the user is assigned. - :param mute: Whether the user is mute in voice channels. - :param deaf: Whether the user is deafened in voice channels. - :return: Guild member object as dictionary - """ - request = await self._req.request( - Route("PUT", f"/guilds/{guild_id}/members/{user_id}"), - json={ - k: v - for k, v in { - "access_token": access_token, - "nick": nick, - "roles": roles, - "mute": mute, - "deaf": deaf, - }.items() - if v is not None - }, - ) - - self.cache.members.add(Item(id=str(user_id), value=Member(**request))) - - return request - - async def remove_guild_member( - self, guild_id: int, user_id: int, reason: Optional[str] = None - ) -> None: - """ - A low level method of removing a member from a guild. This is different from banning them. - - :param guild_id: Guild ID snowflake. - :param user_id: User ID snowflake. - :param reason: Reason to send to audit log, if any. - """ - return await self._req.request( - Route("DELETE", f"/guilds/{guild_id}/members/{user_id}"), reason=reason - ) - - async def get_guild_prune_count( - self, guild_id: int, days: int = 7, include_roles: Optional[List[int]] = None - ) -> dict: - """ - Retrieves a dict from an API that results in how many members would be pruned given the amount of days. - - :param guild_id: Guild ID snowflake. - :param days: Number of days to count. Defaults to ``7``. - :param include_roles: Role IDs to include, if given. - :return: A dict denoting `{"pruned": int}` - """ - payload = {"days": days} - if include_roles: - payload["include_roles"] = ", ".join( - str(x) for x in include_roles - ) # would still iterate - - return await self._req.request(Route("GET", f"/guilds/{guild_id}/prune"), params=payload) - - async def get_guild_auditlog( - self, - guild_id: int, - user_id: Optional[int] = None, - action_type: Optional[int] = None, - before: Optional[int] = None, - limit: int = 50, - ) -> dict: - """ - Returns an audit log object for the guild. Requires the 'VIEW_AUDIT_LOG' permission. - :param guild_id: Guild ID snowflake. - :param user_id: User ID snowflake. filter the log for actions made by a user. - :param action_type: the type ID of audit log event. - :param before: filter the log before a certain entry id. - :param limit: how many entries are returned (default 50, minimum 1, maximum 100) - """ - - payload = {"limit": limit} - if user_id: - payload["user_id"] = user_id - if action_type: - payload["action_type"] = action_type - if before: - payload["before"] = before - - return await self._req.request( - Route("GET", f"/guilds/{guild_id}/audit-logs"), params=payload - ) - - # Guild (Member) endpoint - - async def get_member(self, guild_id: int, member_id: int) -> Optional[dict]: - """ - Uses the API to fetch a member from a guild. - - :param guild_id: Guild ID snowflake. - :param member_id: Member ID snowflake. - :return: A member object, if any. - """ - return await self._req.request( - Route( - "GET", - "/guilds/{guild_id}/members/{member_id}", - guild_id=guild_id, - member_id=member_id, - ) - ) - - async def get_list_of_members( - self, guild_id: int, limit: int = 1, after: Optional[int] = None - ) -> List[dict]: - """ - Lists the members of a guild. - - :param guild_id: Guild ID snowflake - :param limit: How many members to get from the API. Max is 1000. Defaults to 1. - :param after: Get Member IDs after this snowflake. Defaults to None. - :return: An array of Member objects. - """ - payload = {"limit": limit} - if after: - payload["after"] = after - - return await self._req.request(Route("GET", f"/guilds/{guild_id}/members"), params=payload) - - async def search_guild_members(self, guild_id: int, query: str, limit: int = 1) -> List[dict]: - """ - Search a guild for members whose username or nickname starts with provided string. - - :param guild_id: Guild ID snowflake. - :param query: The string to search for - :param limit: The number of members to return. Defaults to 1. - """ - - return await self._req.request( - Route("GET", f"/guilds/{guild_id}/members/search"), - params={"query": query, "limit": limit}, - ) - - async def add_member_role( - self, guild_id: int, user_id: int, role_id: int, reason: Optional[str] = None - ) -> None: - """ - Adds a role to a guild member. - - :param guild_id: The ID of the guild - :param user_id: The ID of the user - :param role_id: The ID of the role to add - :param reason: The reason for this action. Defaults to None. - """ - return await self._req.request( - Route( - "PUT", - "/guilds/{guild_id}/members/{user_id}/roles/{role_id}", - guild_id=guild_id, - user_id=user_id, - role_id=role_id, - ), - reason=reason, - ) - - async def remove_member_role( - self, guild_id: int, user_id: int, role_id: int, reason: Optional[str] = None - ) -> None: - """ - Removes a role to a guild member. - - :param guild_id: The ID of the guild - :param user_id: The ID of the user - :param role_id: The ID of the role to add - :param reason: The reason for this action. Defaults to None. - """ - return await self._req.request( - Route( - "DELETE", - "/guilds/{guild_id}/members/{user_id}/roles/{role_id}", - guild_id=guild_id, - user_id=user_id, - role_id=role_id, - ), - reason=reason, - ) - - async def modify_member( - self, user_id: int, guild_id: int, payload: dict, reason: Optional[str] = None - ) -> dict: - """ - Edits a member. - This can nick them, change their roles, mute/deafen (and its contrary), and moving them across channels and/or disconnect them. - - :param user_id: Member ID snowflake. - :param guild_id: Guild ID snowflake. - :param payload: Payload representing parameters (nick, roles, mute, deaf, channel_id) - :param reason: The reason for this action. Defaults to None. - :return: Modified member object. - """ - - return await self._req.request( - Route( - "PATCH", "/guilds/{guild_id}/members/{user_id}", guild_id=guild_id, user_id=user_id - ), - json=payload, - reason=reason, - ) - - # Channel endpoint. - - async def get_channel(self, channel_id: int) -> dict: - """ - Gets a channel by ID. If the channel is a thread, it also includes thread members (and other thread attributes). - - :param channel_id: Channel ID snowflake. - :return: Dictionary of the channel object. - """ - request = await self._req.request(Route("GET", f"/channels/{channel_id}")) - self.cache.channels.add(Item(id=str(channel_id), value=Channel(**request))) - - return request - - async def delete_channel(self, channel_id: int) -> None: - """ - Deletes a channel. - - :param channel_id: Channel ID snowflake - """ - return await self._req.request( - Route("DELETE", "/channels/{channel_id}", channel_id=channel_id) - ) - - async def get_channel_messages( - self, - channel_id: int, - limit: int = 50, - around: Optional[int] = None, - before: Optional[int] = None, - after: Optional[int] = None, - ) -> List[dict]: - """ - Get messages from a channel. - - ..note:: - around, before, and after arguments are mutually exclusive. - - :param channel_id: Channel ID snowflake. - :param limit: How many messages to get. Defaults to 50, the max is 100. - :param around: Get messages around this snowflake ID. - :param before: Get messages before this snowflake ID. - :param after: Get messages after this snowflake ID. - :return: An array of Message objects. - """ - params: Dict[str, Union[int, str]] = {"limit": limit} - - params_used = 0 - - if before: - params_used += 1 - params["before"] = before - if after: - params_used += 1 - params["after"] = after - if around: - params_used += 1 - params["around"] = around - - if params_used > 1: - raise ValueError( - "`before`, `after` and `around` are mutually exclusive. Please pass only one of them." - ) - - request = await self._req.request( - Route("GET", f"/channels/{channel_id}/messages"), params=params - ) - - for message in request: - if message.get("id"): - self.cache.messages.add(Item(id=message["id"], value=Message(**message))) - - return request - - async def create_channel( - self, guild_id: int, payload: dict, reason: Optional[str] = None - ) -> dict: - """ - Creates a channel within a guild. - - ..note:: - This does not handle payload in this method. Tread carefully. - - :param guild_id: Guild ID snowflake. - :param payload: Payload data. - :param reason: Reason to show in audit log, if needed. - :return: Channel object as dictionary. - """ - request = await self._req.request( - Route("POST", f"/guilds/{guild_id}/channels"), json=payload, reason=reason - ) - if request.get("id"): - self.cache.channels.add(Item(id=request["id"], value=Channel(**request))) - - return request - - async def move_channel( - self, - guild_id: int, - channel_id: int, - new_pos: int, - parent_id: Optional[int], - lock_perms: bool = False, - reason: Optional[str] = None, - ) -> dict: - """ - Moves a channel to a new position. - - :param guild_id: Guild ID snowflake. - :param channel_id: Channel ID snowflake. - :param new_pos: The new channel position. - :param parent_id: The category parent ID, if needed. - :param lock_perms: Sync permissions with the parent associated with parent_id. Defaults to False. - :param reason: Reason to display to the audit log, if any. - :return: ? - """ - payload = {"id": channel_id, "position": new_pos, "lock_permissions": lock_perms} - if parent_id: - payload["parent_id"] = parent_id - - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/channels"), json=payload, reason=reason - ) - - async def modify_channel( - self, channel_id: int, payload: dict, reason: Optional[str] = None - ) -> dict: - """ - Update a channel's settings. - - :param channel_id: Channel ID snowflake. - :param payload: Data representing updated settings. - :param reason: Reason, if any. - :return: Channel with updated attributes, if successful. - """ - return await self._req.request( - Route("PATCH", f"/channels/{channel_id}"), json=payload, reason=reason - ) - - async def get_channel_invites(self, channel_id: int) -> List[dict]: - """ - Get the invites for the channel. - - :param channel_id: Channel ID snowflake. - :return: List of invite objects - """ - return await self._req.request(Route("GET", f"/channels/{channel_id}/invites")) - - async def create_channel_invite( - self, channel_id: int, payload: dict, reason: Optional[str] = None - ) -> dict: - """ - Creates an invite for the given channel. - - ..note:: - This method does not handle payload. It just sends it. - - :param channel_id: Channel ID snowflake. - :param data: Data representing the payload/invite attributes. - :param reason: Reason to show in the audit log, if any. - :return: An invite object. - """ - return await self._req.request( - Route("POST", f"/channels/{channel_id}/invites"), json=payload, reason=reason - ) - - async def delete_invite(self, invite_code: str, reason: Optional[str] = None) -> dict: - """ - Delete an invite. - - :param invite_code: The code of the invite to delete - :param reason: Reason to show in the audit log, if any. - :return: The deleted invite object - """ - return await self._req.request(Route("DELETE", f"/invites/{invite_code}"), reason=reason) - - async def edit_channel_permission( - self, - channel_id: int, - overwrite_id: int, - allow: str, - deny: str, - perm_type: int, - reason: Optional[str] = None, - ) -> None: - """ - Edits the channel's permission overwrites for a user or role in a given channel. - - :param channel_id: Channel ID snowflake. - :param overwrite_id: The ID of the overridden object. - :param allow: the bitwise value of all allowed permissions - :param deny: the bitwise value of all disallowed permissions - :param perm_type: 0 for a role or 1 for a member - :param reason: Reason to display in the Audit Log, if given. - """ - return await self._req.request( - Route("PUT", f"/channels/{channel_id}/permissions/{overwrite_id}"), - json={"allow": allow, "deny": deny, "type": perm_type}, - reason=reason, - ) - - async def delete_channel_permission( - self, channel_id: int, overwrite_id: int, reason: Optional[str] = None - ) -> None: - """ - Deletes a channel permission overwrite for a user or role in a channel. - - :param channel_id: Channel ID snowflake. - :param overwrite_id: The ID of the overridden object. - :param reason: Reason to display in the Audit Log, if given. - """ - return await self._req.request( - Route("DELETE", f"/channels/{channel_id}/{overwrite_id}"), reason=reason - ) - - async def trigger_typing(self, channel_id: int) -> None: - """ - Posts "... is typing" in a given channel. - - ..note: - By default, this lib doesn't use this endpoint, however, this is listed for third-party implementation. - - :param channel_id: Channel ID snowflake. - """ - return await self._req.request(Route("POST", f"/channels/{channel_id}/typing")) - - async def get_pinned_messages(self, channel_id: int) -> List[dict]: - """ - Get all pinned messages from a channel. - - :param channel_id: Channel ID snowflake. - :return: A list of pinned message objects. - """ - return await self._req.request(Route("GET", f"/channels/{channel_id}/pins")) - - async def create_stage_instance( - self, channel_id: int, topic: str, privacy_level: int = 1, reason: Optional[str] = None - ) -> dict: - """ - Create a new stage instance. - - :param channel_id: Channel ID snowflake. - :param topic: The topic of the stage instance. Limited to 1-120 characters. - :param privacy_level: The privacy_level of the stage instance (defaults to guild-only "1"). - :param reason: The reason for the creating the stage instance, if any. - :return: The new stage instance - """ - return await self._req.request( - Route("POST", "/stage-instances"), - json={ - "channel_id": channel_id, - "topic": topic, - "privacy_level": privacy_level, - }, - reason=reason, - ) - - async def get_stage_instance(self, channel_id: int) -> dict: - """ - Get the stage instance associated with a given channel, if it exists. - - :param channel_id: Channel ID snowflake. - :return: A stage instance. - """ - return await self._req.request(Route("GET", f"/stage-instances/{channel_id}")) - - async def modify_stage_instance( - self, - channel_id: int, - topic: Optional[str] = None, - privacy_level: Optional[int] = None, - reason: Optional[str] = None, - ) -> dict: - """ - Update the fields of a given stage instance. - - :param channel_id: Channel ID snowflake. - :param topic: The new topic of the stage instance, if given. Limited to 1-120 characters. - :param privacy_level: The new privacy_level of the stage instance. - :param reason: The reason for the creating the stage instance, if any. - :return: The updated stage instance. - """ - return await self._req.request( - Route("PATCH", f"/stage-instances/{channel_id}"), - json={ - k: v - for k, v in {"topic": topic, "privacy_level": privacy_level}.items() - if v is not None - }, - reason=reason, - ) - - async def delete_stage_instance(self, channel_id: int, reason: Optional[str] = None) -> None: - """ - Delete a stage instance. - - :param channel_id: Channel ID snowflake. - :param reason: The reason for the creating the stage instance, if any. - """ - return await self._req.request( - Route("DELETE", f"/stage-instances/{channel_id}"), reason=reason - ) - - # Thread endpoint - - async def join_thread(self, thread_id: int) -> None: - """ - Have the bot user join a thread. - - :param thread_id: The thread to join. - """ - return await self._req.request(Route("PUT", f"/channels/{thread_id}/thread-members/@me")) - - async def leave_thread(self, thread_id: int) -> None: - """ - Have the bot user leave a thread. - - :param thread_id: The thread to leave. - """ - return await self._req.request(Route("DELETE", f"/channels/{thread_id}/thread-members/@me")) - - async def add_member_to_thread(self, thread_id: int, user_id: int) -> None: - """ - Add another user to a thread. - - :param thread_id: The ID of the thread - :param user_id: The ID of the user to add - """ - return await self._req.request( - Route("PUT", f"/channels/{thread_id}/thread-members/{user_id}") - ) - - async def remove_member_from_thread(self, thread_id: int, user_id: int) -> None: - """ - Remove another user from a thread. - - :param thread_id: The ID of the thread - :param user_id: The ID of the user to remove - """ - return await self._req.request( - Route("DELETE", f"/channels/{thread_id}/thread-members/{user_id}") - ) - - async def get_member_from_thread(self, thread_id: int, user_id: int) -> dict: - """ - Get a member from a thread. - - :param thread_id: The ID of the thread - :param user_id: The ID of the user to find - :return: A thread member object, if they're in the thread. - """ - # Returns 404 if they don't - return await self._req.request( - Route("GET", f"/channels/{thread_id}/thread-members/{user_id}") - ) - - async def list_thread_members(self, thread_id: int) -> List[dict]: - """ - Get a list of members in the thread. - - :param thread_id: the id of the thread - :return: a list of thread member objects - """ - return await self._req.request(Route("GET", f"/channels/{thread_id}/thread-members")) - - async def list_public_archived_threads( - self, channel_id: int, limit: int = None, before: Optional[int] = None - ) -> List[dict]: - """ - Get a list of archived public threads in a given channel. - - :param channel_id: The channel to get threads from - :param limit: Optional limit of threads to - :param before: Get threads before this Thread snowflake ID - :return: a list of threads - """ - payload = {} - if limit: - payload["limit"] = limit - if before: - payload["before"] = before - return await self._req.request( - Route("GET", f"/channels/{channel_id}/threads/archived/public"), json=payload - ) - - async def list_private_archived_threads( - self, channel_id: int, limit: int = None, before: Optional[int] = None - ) -> List[dict]: - """ - Get a list of archived private threads in a channel. - - :param channel_id: The channel to get threads from - :param limit: Optional limit of threads to - :param before: Get threads before this Thread snowflake ID - :return: a list of threads - """ - payload = {} - if limit: - payload["limit"] = limit - if before: - payload["before"] = before - return await self._req.request( - Route("GET", f"/channels/{channel_id}/threads/archived/private"), json=payload - ) - - async def list_joined_private_archived_threads( - self, channel_id: int, limit: int = None, before: Optional[int] = None - ) -> List[dict]: - """ - Get a list of archived private threads in a channel that the bot has joined. - - :param channel_id: The channel to get threads from - :param limit: Optional limit of threads to - :param before: Get threads before this snowflake ID - :return: a list of threads - """ - payload = {} - if limit: - payload["limit"] = limit - if before: - payload["before"] = before - return await self._req.request( - Route("GET", f"/channels/{channel_id}/users/@me/threads/archived/private"), json=payload - ) - - async def list_active_threads(self, guild_id: int) -> List[dict]: - """ - List active threads within a guild. - - :param guild_id: the guild id to get threads from - :return: A list of active threads - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/threads/active")) - - async def create_thread( - self, - channel_id: int, - name: str, - thread_type: int = None, - auto_archive_duration: Optional[int] = None, - invitable: Optional[bool] = None, - message_id: Optional[int] = None, - reason: Optional[str] = None, - ) -> dict: - """ - From a given channel, create a Thread with an optional message to start with.. - - :param channel_id: The ID of the channel to create this thread in - :param name: The name of the thread - :param auto_archive_duration: duration in minutes to automatically archive the thread after recent activity, - can be set to: 60, 1440, 4320, 10080 - :param thread_type: The type of thread, defaults to public. ignored if creating thread from a message - :param invitable: Boolean to display if the Thread is open to join or private. - :param message_id: An optional message to create a thread from. - :param reason: An optional reason for the audit log - :return: The created thread - """ - payload = {"name": name} - if auto_archive_duration: - payload["auto_archive_duration"] = auto_archive_duration - if message_id: - request = await self._req.request( - Route("POST", f"/channels/{channel_id}/messages/{message_id}/threads"), - json=payload, - reason=reason, - ) - if request.get("id"): - self.cache.channels.add(Item(id=request["id"], value=request)) - return request - - payload["type"] = thread_type - payload["invitable"] = invitable - request = await self._req.request( - Route("POST", f"/channels/{channel_id}/threads"), json=payload, reason=reason - ) - if request.get("id"): - self.cache.channels.add(Item(id=request["id"], value=request)) - - return request - - # Reaction endpoint - - async def create_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: - """ - Create a reaction for a message. - - :param channel_id: Channel snowflake ID. - :param message_id: Message snowflake ID. - :param emoji: The emoji to use (format: `name:id`) - """ - return await self._req.request( - Route( - "PUT", - "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me", - channel_id=channel_id, - message_id=message_id, - emoji=emoji, - ) - ) - - async def remove_self_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: - """ - Remove bot user's reaction from a message. - - :param channel_id: Channel snowflake ID. - :param message_id: Message snowflake ID. - :param emoji: The emoji to remove (format: `name:id`) - """ - return await self._req.request( - Route( - "DELETE", - "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me", - channel_id=channel_id, - message_id=message_id, - emoji=emoji, - ) - ) - - async def remove_user_reaction( - self, channel_id: int, message_id: int, emoji: str, user_id: int - ) -> None: - """ - Remove user's reaction from a message. - - :param channel_id: The channel this is taking place in - :param message_id: The message to remove the reaction on. - :param emoji: The emoji to remove. (format: `name:id`) - :param user_id: The user to remove reaction of. - """ - return await self._req.request( - Route( - "DELETE", - "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/{user_id}", - channel_id=channel_id, - message_id=message_id, - emoji=emoji, - user_id=user_id, - ) - ) - - async def remove_all_reactions(self, channel_id: int, message_id: int) -> None: - """ - Remove all reactions from a message. - - :param channel_id: The channel this is taking place in. - :param message_id: The message to clear reactions from. - """ - return await self._req.request( - Route( - "DELETE", - "/channels/{channel_id}/messages/{message_id}/reactions", - channel_id=channel_id, - message_id=message_id, - ) - ) - - async def remove_all_reactions_of_emoji( - self, channel_id: int, message_id: int, emoji: str - ) -> None: - """ - Remove all reactions of a certain emoji from a message. - - :param channel_id: Channel snowflake ID. - :param message_id: Message snowflake ID. - :param emoji: The emoji to remove (format: `name:id`) - """ - return await self._req.request( - Route( - "DELETE", - "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}", - channel_id=channel_id, - message_id=message_id, - emoji=emoji, - ) - ) - - async def get_reactions_of_emoji( - self, channel_id: int, message_id: int, emoji: str - ) -> List[dict]: - """ - Gets the users who reacted to the emoji. - - :param channel_id: Channel snowflake ID. - :param message_id: Message snowflake ID. - :param emoji: The emoji to get (format: `name:id`) - :return A list of users who sent that emoji. - """ - return await self._req.request( - Route( - "GET", - "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}", - channel_id=channel_id, - message_id=message_id, - emoji=emoji, - ) - ) - - # Sticker endpoint - - async def get_sticker(self, sticker_id: int) -> dict: - """ - Get a specific sticker. - - :param sticker_id: The id of the sticker - :return: Sticker or None - """ - return await self._req.request(Route("GET", f"/stickers/{sticker_id}")) - - async def list_nitro_sticker_packs(self) -> List[dict]: - """ - Gets the list of sticker packs available to Nitro subscribers. - - :return: List of sticker packs - """ - return await self._req.request(Route("GET", "/sticker-packs")) - - async def list_guild_stickers(self, guild_id: int) -> List[dict]: - """ - Get the stickers for a guild. - - :param guild_id: The guild to get stickers from - :return: List of Stickers or None - """ - return await self._req.request(Route("GET", f"/guild/{guild_id}/stickers")) - - async def get_guild_sticker(self, guild_id: int, sticker_id: int) -> dict: - """ - Get a sticker from a guild. - - :param guild_id: The guild to get stickers from - :param sticker_id: The sticker to get from the guild - :return: Sticker or None - """ - return await self._req.request(Route("GET", f"/guild/{guild_id}/stickers/{sticker_id}")) - - async def create_guild_sticker( - self, payload: FormData, guild_id: int, reason: Optional[str] = None - ) -> dict: - """ - Create a new sticker for the guild. Requires the MANAGE_EMOJIS_AND_STICKERS permission. - - :param payload: the payload to send. - :param guild_id: The guild to create sticker at. - :param reason: The reason for this action. - :return: The new sticker data on success. - """ - return await self._req.request( - Route("POST", f"/guild/{guild_id}/stickers"), json=payload, reason=reason - ) - - async def modify_guild_sticker( - self, payload: dict, guild_id: int, sticker_id: int, reason: Optional[str] = None - ) -> dict: - """ - Modify the given sticker. Requires the MANAGE_EMOJIS_AND_STICKERS permission. - - :param payload: the payload to send. - :param guild_id: The guild of the target sticker. - :param sticker_id: The sticker to modify. - :param reason: The reason for this action. - :return: The updated sticker data on success. - """ - return await self._req.request( - Route("PATCH", f"/guild/{guild_id}/stickers/{sticker_id}"), json=payload, reason=reason - ) - - async def delete_guild_sticker( - self, guild_id: int, sticker_id: int, reason: Optional[str] = None - ) -> None: - """ - Delete the given sticker. Requires the MANAGE_EMOJIS_AND_STICKERS permission. - - :param guild_id: The guild of the target sticker. - :param sticker_id: The sticker to delete. - :param reason: The reason for this action. - :return: Returns 204 No Content on success. - """ - return await self._req.request( - Route("DELETE", f"/guild/{guild_id}/stickers/{sticker_id}"), reason=reason - ) - - # Interaction endpoint (Application commands) ** - - # TODO: Merge single and batch variants ? - - async def get_application_commands( - self, application_id: Union[int, Snowflake], guild_id: Optional[int] = None - ) -> List[dict]: - """ - Get all application commands from an application. - - :param application_id: Application ID snowflake - :param guild_id: Guild to get commands from, if specified. Defaults to global (None) - :return: A list of Application commands. - """ - application_id = int(application_id) - - if guild_id in (None, "None"): - return await self._req.request(Route("GET", f"/applications/{application_id}/commands")) - else: - return await self._req.request( - Route("GET", f"/applications/{application_id}/guilds/{guild_id}/commands") - ) - - async def create_application_command( - self, application_id: Union[int, Snowflake], data: dict, guild_id: Optional[int] = None - ): - """ - Registers to the Discord API an application command. - - :param application_id: Application ID snowflake - :param data: The dictionary that contains the command (name, description, etc) - :param guild_id: Guild ID snowflake to put them in, if applicable. - :return: An application command object. - """ - - application_id = int(application_id) - - url = ( - f"/applications/{application_id}/commands" - if guild_id in (None, "None") - else f"/applications/{application_id}/guilds/{guild_id}/commands" - ) - - return await self._req.request(Route("POST", url), json=data) - - async def overwrite_application_command( - self, application_id: int, data: List[dict], guild_id: Optional[int] = None - ) -> List[dict]: - """ - Overwrites application command(s) from a scope to the new, updated commands. - - ..note: - This applies to all forms of application commands (slash and context menus) - - :param application_id: Application ID snowflake - :param data: The dictionary that contains the command (name, description, etc) - :param guild_id: Guild ID snowflake to put them in, if applicable. - :return: An array of application command objects. - """ - url = ( - f"/applications/{application_id}/commands" - if not guild_id - else f"/applications/{application_id}/guilds/{guild_id}/commands" - ) - - return await self._req.request(Route("PUT", url), json=data) - - async def edit_application_command( - self, - application_id: Union[int, Snowflake], - data: dict, - command_id: Union[int, Snowflake], - guild_id: Optional[int] = None, - ) -> dict: - """ - Edits an application command. - - :param application_id: Application ID snowflake. - :param data: A dictionary containing updated attributes - :param command_id: The application command ID snowflake - :param guild_id: Guild ID snowflake, if given. Defaults to None/global. - :return: The updated application command object. - """ - application_id, command_id = int(application_id), int(command_id) - r = ( - Route( - "PATCH", - "/applications/{application_id}/commands/{command_id}", - application_id=application_id, - command_id=command_id, - ) - if guild_id in (None, "None") - else Route( - "PATCH", - "/applications/{application_id}/guilds/{guild_id}/commands/{command_id}", - application_id=application_id, - command_id=command_id, - guild_id=guild_id, - ) - ) - return await self._req.request(r, json=data) - - async def delete_application_command( - self, application_id: Union[int, Snowflake], command_id: int, guild_id: Optional[int] = None - ) -> None: - """ - Deletes an application command. - - :param application_id: Application ID snowflake. - :param command_id: Application command ID snowflake. - :param guild_id: Guild ID snowflake, if declared. Defaults to None (Global). - """ - - application_id = int(application_id) - - r = ( - Route( - "DELETE", - "/applications/{application_id}/guilds/{guild_id}/commands/{command_id}", - application_id=application_id, - command_id=command_id, - guild_id=guild_id, - ) - if guild_id not in (None, "None") - else Route( - "DELETE", - "/applications/{application_id}/commands/{command_id}", - application_id=application_id, - command_id=command_id, - ) - ) - return await self._req.request(r) - - async def edit_application_command_permissions( - self, application_id: int, guild_id: int, command_id: int, data: List[dict] - ) -> dict: - """ - Edits permissions for an application command. - - :param application_id: Application ID snowflake - :param guild_id: Guild ID snowflake - :param command_id: Application command ID snowflake - :param data: Permission data. - :return: Returns an updated Application Guild permission object. - """ - - return await self._req.request( - Route( - "PUT", - f"/applications/{application_id}/guilds/{guild_id}/commands/{command_id}/permissions", - ), - json=data, - ) - - async def batch_edit_application_command_permissions( - self, application_id: int, guild_id: int, data: List[dict] - ) -> List[dict]: - """ - Edits permissions for all Application Commands in a guild. - - :param application_id: Application ID snowflake - :param guild_id: Guild ID snowflake - :param data: An array of permission dictionaries. - :return: An updated array of application array permissions. - """ - return await self._req.request( - Route("PUT", f"/applications/{application_id}/guilds/{guild_id}/commands/permissions"), - json=data, - ) - - async def get_application_command_permissions( - self, application_id: int, guild_id: int, command_id: int - ) -> dict: - """ - Gets, from the Discord API, permissions from a specific Guild application command. - - :param application_id: Application ID snowflake - :param guild_id: Guild ID snowflake - :param command_id: Application Command ID snowflake - :return: a Guild Application Command permissions object - """ - return await self._req.request( - Route( - "GET", - f"/applications/{application_id}/guilds/{guild_id}/commands/{command_id}/permissions", - ) - ) - - async def get_all_application_command_permissions( - self, application_id: int, guild_id: int - ) -> List[dict]: - """ - Gets, from the Discord API, permissions from all Application commands at that Guild. - - :param application_id: Application ID snowflake - :param guild_id: Guild ID snowflake - :return: An array of Guild Application Command permissions - """ - return await self._req.request( - Route("GET", f"/applications/{application_id}/guilds/{guild_id}/commands/permissions") - ) - - async def create_interaction_response( - self, token: str, application_id: int, data: dict - ) -> None: - """ - Posts initial response to an interaction, but you need to add the token. - - :param token: Token. - :param application_id: Application ID snowflake - :param data: The data to send. - """ - return await self._req.request( - Route("POST", f"/interactions/{application_id}/{token}/callback"), json=data - ) - - # This is still Interactions, but this also applies to webhooks - # i.e. overlay - async def get_original_interaction_response( - self, token: str, application_id: str, message_id: int = "@original" - ) -> dict: - """ - Gets an existing interaction message. - - :param token: token - :param application_id: Application ID snowflake. - :param message_id: Message ID snowflake. Defaults to `@original` which represents the initial response msg. - :return: Message data. - """ - # ^ again, I don't know if python will let me - return await self._req.request( - Route("GET", f"/webhooks/{application_id}/{token}/messages/{message_id}") - ) - - async def edit_interaction_response( - self, data: dict, token: str, application_id: str, message_id: str = "@original" - ) -> dict: - """ - Edits an existing interaction message, but token needs to be manually called. - - :param data: A dictionary containing the new response. - :param token: the token of the interaction - :param application_id: Application ID snowflake. - :param message_id: Message ID snowflake. Defaults to `@original` which represents the initial response msg. - :return: Updated message data. - """ - # ^ again, I don't know if python will let me - return await self._req.request( - Route("PATCH", f"/webhooks/{application_id}/{token}/messages/{message_id}"), - json=data, - ) - - async def delete_interaction_response( - self, token: str, application_id: str, message_id: int = "original" - ) -> None: - """ - Deletes an existing interaction message. - - :param token: the token of the interaction - :param application_id: Application ID snowflake. - :param message_id: Message ID snowflake. Defaults to `@original` which represents the initial response msg. - """ - - # This is, basically, a helper method for the thing, - # because interactions are webhooks - - await self.delete_webhook_message( - webhook_id=int(application_id), webhook_token=token, message_id=message_id - ) - - async def _post_followup(self, data: dict, token: str, application_id: str) -> dict: - """ - Send a followup to an interaction. - - :param data: the payload to send - :param application_id: the id of the application - :param token: the token of the interaction - """ - - return await self._req.request( - Route("POST", f"/webhooks/{application_id}/{token}"), json=data - ) - - # Webhook endpoints. - # TODO: Not sure why, but there's no webhook models? Will rectify later. - # Also, todo: figure out what avatar is - - async def create_webhook(self, channel_id: int, name: str, avatar: Any = None) -> dict: - """ - Create a new webhook. - - :param channel_id: Channel ID snowflake. - :param name: Name of the webhook (1-80 characters) - :param avatar: The image for the default webhook avatar, if given. - - :return Webhook object - """ - return await self._req.request( - Route("POST", f"/channels/{channel_id}/webhooks"), json={"name": name, "avatar": avatar} - ) - - async def get_channel_webhooks(self, channel_id: int) -> List[dict]: - """ - Return a list of channel webhook objects. - - :param channel_id: Channel ID snowflake. - :return:List of webhook objects - """ - return await self._req.request(Route("GET", f"/channels/{channel_id}/webhooks")) - - async def get_guild_webhooks(self, guild_id: int) -> List[dict]: - """ - Return a list of guild webhook objects. - - :param guild_id: Guild ID snowflake - - :return: List of webhook objects - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/webhooks")) - - async def get_webhook(self, webhook_id: int, webhook_token: str = None) -> dict: - """ - Return the new webhook object for the given id. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: Webhook Token, if given. - - :return:Webhook object - """ - endpoint = f"/webhooks/{webhook_id}{f'/{webhook_token}' if webhook_token else ''}" - - return await self._req.request(Route("GET", endpoint)) - - async def modify_webhook( - self, - webhook_id: int, - name: str, - avatar: Any, - channel_id: int, - webhook_token: str = None, - ) -> dict: - """ - Modify a webhook. - - :param webhook_id: Webhook ID snowflake - :param name: the default name of the webhook - :param avatar: image for the default webhook avatar - :param channel_id: Channel ID snowflake of new destination - :param webhook_token: The token for the webhook, if given. - - :return: Modified webhook object. - """ - endpoint = f"/webhooks/{webhook_id}{f'/{webhook_token}' if webhook_token else ''}" - - return await self._req.request( - Route("PATCH", endpoint), - json={"name": name, "avatar": avatar, "channel_id": channel_id}, - ) - - async def delete_webhook(self, webhook_id: int, webhook_token: str = None): - """ - Delete a webhook. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: The token for the webhook, if given. - """ - - endpoint = f"/webhooks/{webhook_id}{f'/{webhook_token}' if webhook_token else ''}" - - return await self._req.request(Route("DELETE", endpoint)) - - async def execute_webhook( - self, - webhook_id: int, - webhook_token: str, - payload: dict, - wait: bool = False, - thread_id: Optional[int] = None, - ) -> Optional[Message]: - """ - Sends a message as a webhook. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: The token for the webhook. - :param payload: Payload consisting of the message. - :param wait: A bool that signifies waiting for server confirmation of a send before responding. - :param thread_id: Optional, sends a message to the specified thread. - :return: The message sent, if wait=True, else None. - """ - - return await self._req.request( - Route("POST", f"/webhooks/{webhook_id}/{webhook_token}"), - params={"wait": wait, "thread_id": thread_id}, - json=payload, - ) - - async def execute_slack_webhook( - self, webhook_id: int, webhook_token: str, payload: dict - ) -> None: - """ - Sends a message to a Slack-compatible webhook. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: The token for the webhook. - :param payload: Payload consisting of the message. - - :return: ? - - .. note:: - Payload structure is different than Discord's. See `here _` for more details. - """ - - return await self._req.request( - Route("POST", f"/webhooks/{webhook_id}/{webhook_token}/slack"), json=payload - ) - - async def execute_github_webhook( - self, webhook_id: int, webhook_token: str, payload: dict - ) -> None: - """ - Sends a message to a Github-compatible webhook. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: The token for the webhook. - :param payload: Payload consisting of the message. - - :return: ? - - .. note:: - Payload structure is different than Discord's. See `here _` for more details. - """ - - return await self._req.request( - Route("POST", f"/webhooks/{webhook_id}/{webhook_token}/slack"), json=payload - ) - - async def get_webhook_message( - self, webhook_id: int, webhook_token: str, message_id: int - ) -> Message: - """ - Retrieves a message sent from a Webhook. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: Webhook token. - :param message_id: Message ID snowflake, - :return: A Message object. - """ - - return await self._req.request( - Route("GET", f"/webhooks/{webhook_id}/{webhook_token}/messages/{message_id}") - ) - - async def edit_webhook_message( - self, webhook_id: int, webhook_token: str, message_id: int, data: dict - ) -> Message: - """ - Edits a message sent from a Webhook. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: Webhook token. - :param message_id: Message ID snowflake. - :param data: A payload consisting of new message attributes. - :return: An updated message object. - """ - - return await self._req.request( - Route("PATCH", f"/webhooks/{webhook_id}/{webhook_token}/messages/{message_id}"), - json=data, - ) - - async def delete_webhook_message( - self, webhook_id: int, webhook_token: str, message_id: int - ) -> None: - """ - Deletes a message object. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: Webhook token. - :param message_id: Message ID snowflake. - """ - - return await self._req.request( - Route("DELETE", f"/webhooks/{webhook_id}/{webhook_token}/messages/{message_id}") - ) - - async def delete_original_webhook_message(self, webhook_id: int, webhook_token: str) -> None: - """ - Deletes the original message object sent. - - :param webhook_id: Webhook ID snowflake. - :param webhook_token: Webhook token. - """ - - return await self._req.request( - Route("DELETE", f"/webhooks/{webhook_id}/{webhook_token}/messages/@original") - ) - - # Emoji endpoints, a subset of guild but it should get its own thing... - - async def get_all_emoji(self, guild_id: int) -> List[Emoji]: - """ - Gets all emojis from a guild. - - :param guild_id: Guild ID snowflake. - :return: A list of emojis. - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/emojis")) - - async def get_guild_emoji(self, guild_id: int, emoji_id: int) -> Emoji: - """ - Gets an emote from a guild. - - :param guild_id: Guild ID snowflake. - :param emoji_id: Emoji ID snowflake. - :return: Emoji object - """ - return await self._req.request(Route("GET", f"/guilds/{guild_id}/emojis/{emoji_id}")) - - async def create_guild_emoji( - self, guild_id: int, payload: dict, reason: Optional[str] = None - ) -> Emoji: - """ - Creates an emoji. - - :param guild_id: Guild ID snowflake. - :param payload: Emoji parameters. - :param reason: Optionally, give a reason. - :return: An emoji object with the included parameters. - """ - return await self._req.request( - Route("POST", f"/guilds/{guild_id}/emojis"), json=payload, reason=reason - ) - - async def modify_guild_emoji( - self, guild_id: int, emoji_id: int, payload: dict, reason: Optional[str] = None - ) -> Emoji: - """ - Modifies an emoji. - - :param guild_id: Guild ID snowflake. - :param emoji_id: Emoji ID snowflake - :param payload: Emoji parameters with updated attributes - :param reason: Optionally, give a reason. - :return: An emoji object with updated attributes. - """ - return await self._req.request( - Route("PATCH", f"/guilds/{guild_id}/emojis/{emoji_id}"), json=payload, reason=reason - ) - - async def delete_guild_emoji( - self, guild_id: int, emoji_id: int, reason: Optional[str] = None - ) -> None: - """ - Deletes an emoji. - - :param guild_id: Guild ID snowflake. - :param emoji_id: Emoji ID snowflake - :param reason: Optionally, give a reason. - """ - await self._req.request( - Route("DELETE", f"/guilds/{guild_id}/emojis/{emoji_id}"), reason=reason - ) - - # Guild Scheduled Events endpoints - - async def create_scheduled_event(self, guild_id: Snowflake, payload: dict) -> dict: - """ - Creates a scheduled event. - - :param guild_id: Guild ID snowflake. - :param payload: The dictionary containing the parameters and values to edit the associated event. - :return A dictionary containing the new guild scheduled event object on success. - """ - guild_id = int(guild_id) - valid_keys = ( - "channel_id", - "name", - "privacy_level", - "scheduled_start_time", - "scheduled_end_time", - "entity_metadata", - "description", - "entity_type", - ) - data = {k: v for k, v in payload.items() if k in valid_keys} - - return await self._req.request( - Route("POST", "/guilds/{guild_id}/scheduled-events", guild_id=int(guild_id)), - json=data, - ) - - async def get_scheduled_event( - self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, with_user_count: bool - ) -> dict: - """ - Gets a guild scheduled event. - - :param guild_id: Guild ID snowflake. - :param guild_scheduled_event_id: Guild Scheduled Event ID snowflake. - :param with_user_count: A boolean to include number of users subscribed to the associated event, if given. - :return A dictionary containing the guild scheduled event object on success. - """ - guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) - params = {} - if with_user_count: - params["with_user_count"] = with_user_count - - return await self._req.request( - Route( - "GET", - "/guilds/{guild_id}/scheduled-events/{event_id}", - guild_id=guild_id, - event_id=event_id, - ), - params=params, - ) - - async def get_scheduled_events(self, guild_id: Snowflake, with_user_count: bool) -> List[dict]: - """ - Gets all guild scheduled events in a guild. - - :param guild_id: Guild ID snowflake. - :param with_user_count: A boolean to include number of users subscribed to the associated event, if given. - :return A List of a dictionary containing the guild scheduled event objects on success. - """ - guild_id = int(guild_id) - params = {} - if with_user_count: - params["with_user_count"] = with_user_count - - return await self._req.request( - Route("GET", "/guilds/{guild_id}/scheduled-events", guild_id=guild_id), params=params - ) - - async def modify_scheduled_event( - self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, payload: dict - ) -> dict: - """ - Modifies a scheduled event. - - :param guild_id: Guild ID snowflake. - :param guild_scheduled_event_id: Guild Scheduled Event ID snowflake. - :param payload: The dictionary containing the parameters and values to edit the associated event. - :return A dictionary containing the updated guild scheduled event object on success. - """ - guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) - valid_keys = ( - "channel_id", - "name", - "privacy_level", - "scheduled_start_time", - "scheduled_end_time", - "entity_metadata", - "description", - "entity_type", - ) - data = {k: v for k, v in payload.items() if k in valid_keys} - return await self._req.request( - Route( - "PATCH", - "/guilds/{guild_id}/scheduled-events/{event_id}", - guild_id=guild_id, - event_id=event_id, - ), - json=data, - ) - - async def delete_scheduled_event( - self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake - ) -> None: - """ - Deletes a guild scheduled event. - - :param guild_id: Guild ID snowflake. - :param guild_scheduled_event_id: Guild Scheduled Event ID snowflake. - :return Nothing on success. - """ - guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) - - return await self._req.request( - Route( - "DELETE", - "/guilds/{guild_id}/scheduled-events/{event_id}", - guild_id=guild_id, - event_id=event_id, - ) - ) - - async def get_scheduled_event_users( - self, - guild_id: Snowflake, - guild_scheduled_event_id: Snowflake, - limit: int = 100, - with_member: bool = False, - before: Snowflake = None, - after: Snowflake = None, - ) -> List[dict]: - """ - Get the registered users of a scheduled event. - - :param guild_id: Guild ID snowflake. - :param guild_scheduled_event_id: Guild Scheduled Event snowflake. - :param limit: Limit of how many users to pull from the event. Defaults to 100. - :param with_member: Include guild member data if it exists. Defaults to False. - :param before: Considers only users before given user ID snowflake. Defaults to None. - :param after: Considers only users after given user ID snowflake. Defaults to None. - :return: Returns a list of guild scheduled event user objects on success. - """ - guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) - params = { - "limit": limit, - "with_member": with_member, - } - if before: - params["before"] = int(before) - if after: - params["after"] = int(after) - - return await self._req.request( - Route( - "GET", - "/guilds/{guild_id}/scheduled-events/{event_id}/users", - guild_id=guild_id, - event_id=event_id, - ), - params=params, - ) From 16d82fa01a0116e344b87800a37830a2f15469d9 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Tue, 1 Mar 2022 21:22:13 +0100 Subject: [PATCH 08/47] http still deleted :P --- interactions/api/gateway.py | 2 +- interactions/api/http/user.py | 78 +++++++++++++++++++++++++++++++++ interactions/api/http/user.pyi | 16 +++++++ interactions/api/models/user.py | 3 ++ interactions/client.py | 2 +- 5 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 interactions/api/http/user.py create mode 100644 interactions/api/http/user.pyi diff --git a/interactions/api/gateway.py b/interactions/api/gateway.py index 992ad353b..12c688125 100644 --- a/interactions/api/gateway.py +++ b/interactions/api/gateway.py @@ -25,7 +25,7 @@ from .dispatch import Listener from .enums import OpCodeType from .error import GatewayException -from .http import HTTPClient +from .http.HTTPClient import HTTPClient from .models.flags import Intents from .models.misc import MISSING from .models.presence import ClientPresence diff --git a/interactions/api/http/user.py b/interactions/api/http/user.py new file mode 100644 index 000000000..761aa05ba --- /dev/null +++ b/interactions/api/http/user.py @@ -0,0 +1,78 @@ +from typing import Optional + +from ...api.cache import Cache, Item +from ...api.models.channel import Channel +from ...api.models.user import User +from .Request import Request +from .Route import Route + + +class _HTTPUser: + + _req: Request + cache: Cache + + def __init__(self, _req, cache): + self._req = _req + self.cache = cache + + async def get_self(self) -> dict: + """ + An alias to `get_user`, but only gets the current bot user. + + :return: A partial User object of the current bot user in the form of a dictionary. + """ + return await self.get_user() + + async def get_user(self, user_id: Optional[int] = None) -> dict: + """ + Gets a user object for a given user ID. + + :param user_id: A user snowflake ID. If omitted, this defaults to the current bot user. + :return: A partial User object in the form of a dictionary. + """ + + if user_id is None: + user_id = "@me" + + request = await self._req.request(Route("GET", f"/users/{user_id}")) + self.cache.users.add(Item(id=user_id, value=User(**request))) + + return request + + async def modify_self(self, payload: dict) -> dict: + """ + Modify the bot user account settings. + + :param payload: The data to send. + """ + return await self._req.request(Route("PATCH", "/users/@me"), json=payload) + + async def modify_self_nick_in_guild(self, guild_id: int, nickname: Optional[str]) -> dict: + """ + Changes a nickname of the current bot user in a guild. + + :param guild_id: Guild snowflake ID. + :param nickname: The new nickname, if any. + :return: Nothing needed to be yielded. + """ + return await self._req.request( + Route("PATCH", "/guilds/{guild_id}/members/@me/nick", guild_id=guild_id), + json={"nick": nickname}, + ) + + async def create_dm(self, recipient_id: int) -> dict: + """ + Creates a new DM channel with a user. + + :param recipient_id: User snowflake ID. + :return: Returns a dictionary representing a DM Channel object. + """ + # only named recipient_id because of api mirroring + + request = await self._req.request( + Route("POST", "/users/@me/channels"), json={"recipient_id": recipient_id} + ) + self.cache.dms.add(Item(id=str(recipient_id), value=Channel(**request))) + + return request diff --git a/interactions/api/http/user.pyi b/interactions/api/http/user.pyi new file mode 100644 index 000000000..332ffbdf6 --- /dev/null +++ b/interactions/api/http/user.pyi @@ -0,0 +1,16 @@ +from typing import Optional + +from ...api.cache import Cache +from .Request import Request + +class _HTTPUser: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def get_self(self) -> dict: ... + async def get_user(self, user_id: Optional[int] = None) -> dict: ... + async def modify_self(self, payload: dict) -> dict: ... + async def modify_self_nick_in_guild(self, guild_id: int, nickname: Optional[str]) -> dict: ... + async def create_dm(self, recipient_id: int) -> dict: ... diff --git a/interactions/api/models/user.py b/interactions/api/models/user.py index 90fb4d1dc..55d0ed2c6 100644 --- a/interactions/api/models/user.py +++ b/interactions/api/models/user.py @@ -40,6 +40,9 @@ class User(DictSerializerMixin): "flags", "premium_type", "public_flags", + # TODO: document + "bio", + "banner_color", ) def __init__(self, **kwargs): diff --git a/interactions/client.py b/interactions/client.py index 146c619d6..b77c15618 100644 --- a/interactions/client.py +++ b/interactions/client.py @@ -13,7 +13,7 @@ from .api.cache import Item as Build from .api.error import InteractionException, JSONException from .api.gateway import WebSocketClient -from .api.http import HTTPClient +from .api.http.HTTPClient import HTTPClient from .api.models.flags import Intents from .api.models.guild import Guild from .api.models.misc import MISSING, Snowflake From bee7ac5c71b23dae5524717a1872af8074cae39c Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Tue, 1 Mar 2022 21:54:17 +0100 Subject: [PATCH 09/47] refactor: move HTTP into folder --- interactions/api/http/Message.py | 171 +++++++++++++++++++ interactions/api/http/Message.pyi | 38 +++++ interactions/api/http/{user.py => User.py} | 4 +- interactions/api/http/{user.pyi => User.pyi} | 0 4 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 interactions/api/http/Message.py create mode 100644 interactions/api/http/Message.pyi rename interactions/api/http/{user.py => User.py} (96%) rename interactions/api/http/{user.pyi => User.pyi} (100%) diff --git a/interactions/api/http/Message.py b/interactions/api/http/Message.py new file mode 100644 index 000000000..68965458b --- /dev/null +++ b/interactions/api/http/Message.py @@ -0,0 +1,171 @@ +from typing import List, Optional, Union + +from ...api.cache import Cache, Item +from ..models.message import Embed, Message +from ..models.misc import Snowflake +from .Request import Request +from .Route import Route + + +class _HTTPMessage: + + _req: Request + cache: Cache + + def __init__(self, _req, cache): + self._req = _req + self.cache = cache + + async def send_message( + self, + channel_id: Union[int, Snowflake], + content: str, + tts: bool = False, + embeds: Optional[List[Embed]] = None, + nonce: Union[int, str] = None, + allowed_mentions=None, # don't know type + message_reference: Optional[Message] = None, + ) -> dict: + """ + A higher level implementation of :meth:`create_message()` that handles the payload dict internally. + Does not integrate components into the function, and is a port from v3.0.0 + """ + payload = {} + + if content: + payload["content"] = content + + if tts: + payload["tts"] = True + + if embeds: + payload["embeds"] = embeds + + if nonce: + payload["nonce"] = nonce + + if allowed_mentions: + payload["allowed_mentions"] = allowed_mentions + + if message_reference: + payload["message_reference"] = message_reference + + # TODO: post-v4. add attachments to payload. + + if isinstance(channel_id, Snowflake): + channel_id = int(channel_id) + + return await self.create_message(payload, channel_id) + + async def create_message(self, payload: dict, channel_id: int) -> dict: + """ + Send a message to the specified channel. + + :param payload: Dictionary contents of a message. (i.e. message payload) + :param channel_id: Channel snowflake ID. + :return dict: Dictionary representing a message (?) + """ + request = await self._req.request( + Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id), json=payload + ) + if request.get("id"): + self.cache.messages.add(Item(id=request["id"], value=Message(**request))) + + return request + + async def get_message(self, channel_id: int, message_id: int) -> Optional[dict]: + """ + Get a specific message in the channel. + + :param channel_id: the channel this message belongs to + :param message_id: the id of the message + :return: message if it exists. + """ + return await self._req.request( + Route("GET", f"/channels/{channel_id}/messages/{message_id}") + ) + + async def delete_message( + self, channel_id: int, message_id: int, reason: Optional[str] = None + ) -> None: + """ + Deletes a message from a specified channel. + + :param channel_id: Channel snowflake ID. + :param message_id: Message snowflake ID. + :param reason: Optional reason to show up in the audit log. Defaults to `None`. + """ + r = Route( + "DELETE", + "/channels/{channel_id}/messages/{message_id}", + channel_id=channel_id, + message_id=message_id, + ) + return await self._req.request(r, reason=reason) + + async def delete_messages( + self, channel_id: int, message_ids: List[int], reason: Optional[str] = None + ) -> None: + """ + Deletes messages from a specified channel. + + :param channel_id: Channel snowflake ID. + :param message_ids: An array of message snowflake IDs. + :param reason: Optional reason to show up in the audit log. Defaults to `None`. + """ + r = Route("POST", "/channels/{channel_id}/messages/bulk-delete", channel_id=channel_id) + payload = { + "messages": message_ids, + } + + return await self._req.request(r, json=payload, reason=reason) + + async def edit_message(self, channel_id: int, message_id: int, payload: dict) -> dict: + """ + Edits a message that already exists. + + :param channel_id: Channel snowflake ID. + :param message_id: Message snowflake ID. + :param payload: Any new data that needs to be changed. + :type payload: dict + :return: A message object with edited attributes. + """ + return await self._req.request( + Route( + "PATCH", + "/channels/{channel_id}/messages/{message_id}", + channel_id=channel_id, + message_id=message_id, + ), + json=payload, + ) + + async def pin_message(self, channel_id: int, message_id: int) -> None: + """ + Pin a message to a channel. + + :param channel_id: Channel ID snowflake. + :param message_id: Message ID snowflake. + """ + return await self._req.request(Route("PUT", f"/channels/{channel_id}/pins/{message_id}")) + + async def unpin_message(self, channel_id: int, message_id: int) -> None: + """ + Unpin a message to a channel. + + :param channel_id: Channel ID snowflake. + :param message_id: Message ID snowflake. + """ + return await self._req.request(Route("DELETE", f"/channels/{channel_id}/pins/{message_id}")) + + async def publish_message(self, channel_id: int, message_id: int) -> dict: + """ + Publishes (API calls it crossposts) a message in a News channel to any that is followed by. + + :param channel_id: Channel the message is in + :param message_id: The id of the message to publish + :return: message object + """ + return await self._req.request( + Route("POST", f"/channels/{channel_id}/messages/{message_id}/crosspost") + ) diff --git a/interactions/api/http/Message.pyi b/interactions/api/http/Message.pyi new file mode 100644 index 000000000..d92122ec3 --- /dev/null +++ b/interactions/api/http/Message.pyi @@ -0,0 +1,38 @@ +from typing import List, Optional, Union + +from ...api.cache import Cache +from ..models.message import Embed, Message +from ..models.misc import Snowflake +from .Request import Request + + +class _HTTPMessage: + + _req: Request + cache: Cache + + def __init__(self, _req, cache): + self._req = _req + self.cache = cache + async def send_message( + self, + channel_id: Union[int, Snowflake], + content: str, + tts: bool = False, + embeds: Optional[List[Embed]] = None, + nonce: Union[int, str] = None, + allowed_mentions=None, # don't know type + message_reference: Optional[Message] = None, + ) -> dict: ... + async def create_message(self, payload: dict, channel_id: int) -> dict: ... + async def get_message(self, channel_id: int, message_id: int) -> Optional[dict]: ... + async def delete_message( + self, channel_id: int, message_id: int, reason: Optional[str] = None + ) -> None: ... + async def delete_messages( + self, channel_id: int, message_ids: List[int], reason: Optional[str] = None + ) -> None: ... + async def edit_message(self, channel_id: int, message_id: int, payload: dict) -> dict: ... + async def pin_message(self, channel_id: int, message_id: int) -> None: ... + async def unpin_message(self, channel_id: int, message_id: int) -> None: ... + async def publish_message(self, channel_id: int, message_id: int) -> dict: ... diff --git a/interactions/api/http/user.py b/interactions/api/http/User.py similarity index 96% rename from interactions/api/http/user.py rename to interactions/api/http/User.py index 761aa05ba..460bcad9c 100644 --- a/interactions/api/http/user.py +++ b/interactions/api/http/User.py @@ -1,8 +1,8 @@ from typing import Optional from ...api.cache import Cache, Item -from ...api.models.channel import Channel -from ...api.models.user import User +from ..models.channel import Channel +from ..models.user import User from .Request import Request from .Route import Route diff --git a/interactions/api/http/user.pyi b/interactions/api/http/User.pyi similarity index 100% rename from interactions/api/http/user.pyi rename to interactions/api/http/User.pyi From 17385bcad5d04893c6aa46df21af7ca909751efd Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 10:08:00 +0100 Subject: [PATCH 10/47] refactor: correct namings and imports --- interactions/api/gateway.pyi | 2 +- interactions/api/http/Message.py | 2 +- interactions/api/http/Message.pyi | 2 +- interactions/api/http/User.py | 2 +- interactions/api/http/User.pyi | 2 +- interactions/client.pyi | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interactions/api/gateway.pyi b/interactions/api/gateway.pyi index 6665c76b6..b7ed6baf5 100644 --- a/interactions/api/gateway.pyi +++ b/interactions/api/gateway.pyi @@ -12,7 +12,7 @@ from ..models import Option from ..api.models.misc import MISSING from ..api.models.presence import ClientPresence from .dispatch import Listener -from .http import HTTPClient +from .http.HTTPClient import HTTPClient from .models.flags import Intents log: Logger diff --git a/interactions/api/http/Message.py b/interactions/api/http/Message.py index 68965458b..c4329280d 100644 --- a/interactions/api/http/Message.py +++ b/interactions/api/http/Message.py @@ -7,7 +7,7 @@ from .Route import Route -class _HTTPMessage: +class HTTPMessage: _req: Request cache: Cache diff --git a/interactions/api/http/Message.pyi b/interactions/api/http/Message.pyi index d92122ec3..80cdcca11 100644 --- a/interactions/api/http/Message.pyi +++ b/interactions/api/http/Message.pyi @@ -6,7 +6,7 @@ from ..models.misc import Snowflake from .Request import Request -class _HTTPMessage: +class HTTPMessage: _req: Request cache: Cache diff --git a/interactions/api/http/User.py b/interactions/api/http/User.py index 460bcad9c..061cd1cd5 100644 --- a/interactions/api/http/User.py +++ b/interactions/api/http/User.py @@ -7,7 +7,7 @@ from .Route import Route -class _HTTPUser: +class HTTPUser: _req: Request cache: Cache diff --git a/interactions/api/http/User.pyi b/interactions/api/http/User.pyi index 332ffbdf6..d22e8063c 100644 --- a/interactions/api/http/User.pyi +++ b/interactions/api/http/User.pyi @@ -3,7 +3,7 @@ from typing import Optional from ...api.cache import Cache from .Request import Request -class _HTTPUser: +class HTTPUser: _req: Request cache: Cache diff --git a/interactions/client.pyi b/interactions/client.pyi index 11e22dd9f..1d65d78ba 100644 --- a/interactions/client.pyi +++ b/interactions/client.pyi @@ -4,7 +4,7 @@ from typing import Any, Callable, Coroutine, Dict, List, NoReturn, Optional, Tup from .api.cache import Cache from .api.gateway import WebSocketClient -from .api.http import HTTPClient +from .api.http.HTTPClient import HTTPClient from .api.models.flags import Intents from .api.models.guild import Guild from .api.models.misc import MISSING, Snowflake From 3da70b7cf9ce51c44491333efe25c9377c80acbd Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 10:23:59 +0100 Subject: [PATCH 11/47] refactor: add __init__, fix imports in other files --- interactions/api/http/Guild.py | 0 interactions/api/http/Guild.pyi | 0 interactions/api/http/__init__.py | 12 ++++++++++++ interactions/api/models/channel.pyi | 2 +- interactions/api/models/guild.pyi | 2 +- interactions/api/models/gw.pyi | 2 +- interactions/api/models/member.pyi | 2 +- interactions/api/models/message.pyi | 2 +- interactions/api/models/role.pyi | 2 +- 9 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 interactions/api/http/Guild.py create mode 100644 interactions/api/http/Guild.pyi create mode 100644 interactions/api/http/__init__.py diff --git a/interactions/api/http/Guild.py b/interactions/api/http/Guild.py new file mode 100644 index 000000000..e69de29bb diff --git a/interactions/api/http/Guild.pyi b/interactions/api/http/Guild.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py new file mode 100644 index 000000000..428ac7dfa --- /dev/null +++ b/interactions/api/http/__init__.py @@ -0,0 +1,12 @@ +""" +interactions.api.http + +Handles all HTTP-Requests of the library. +""" + +from .HTTPClient import * # noqa: F401 F403 +from .Limiter import * # noqa: F401 F403 +from .Message import * # noqa: F401 F403 +from .Request import * # noqa: F401 F403 +from .Route import * # noqa: F401 F403 +from .User import * # noqa: F401 F403 diff --git a/interactions/api/models/channel.pyi b/interactions/api/models/channel.pyi index fb71e7fd4..9b0184192 100644 --- a/interactions/api/models/channel.pyi +++ b/interactions/api/models/channel.pyi @@ -6,7 +6,7 @@ from .message import Message, Embed, MessageInteraction from ...models.component import ActionRow, Button, SelectMenu from .misc import DictSerializerMixin, Overwrite, Snowflake, MISSING from .user import User -from ..http import HTTPClient +from ..http.HTTPClient import HTTPClient class ChannelType(IntEnum): GUILD_TEXT: int diff --git a/interactions/api/models/guild.pyi b/interactions/api/models/guild.pyi index 03d2b15da..3a654b49c 100644 --- a/interactions/api/models/guild.pyi +++ b/interactions/api/models/guild.pyi @@ -9,7 +9,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .presence import PresenceActivity from .role import Role from .user import User -from ..http import HTTPClient +from ..http.HTTPClient import HTTPClient class VerificationLevel(IntEnum): NONE: int diff --git a/interactions/api/models/gw.pyi b/interactions/api/models/gw.pyi index e64b4abc3..84d7a39a5 100644 --- a/interactions/api/models/gw.pyi +++ b/interactions/api/models/gw.pyi @@ -9,7 +9,7 @@ from .presence import PresenceActivity from .role import Role from .user import User from .team import Application -from ..http import HTTPClient +from ..http.HTTPClient import HTTPClient from ...models.command import Permission class ApplicationCommandPermissions(DictSerializerMixin): diff --git a/interactions/api/models/member.pyi b/interactions/api/models/member.pyi index cbad061ab..02c8e5249 100644 --- a/interactions/api/models/member.pyi +++ b/interactions/api/models/member.pyi @@ -5,7 +5,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .role import Role from .user import User from .flags import Permissions -from ..http import HTTPClient +from ..http.HTTPClient import HTTPClient from .message import Message, Embed, MessageInteraction from ...models.component import ActionRow, Button, SelectMenu diff --git a/interactions/api/models/message.pyi b/interactions/api/models/message.pyi index eaa0845e6..7537fae9e 100644 --- a/interactions/api/models/message.pyi +++ b/interactions/api/models/message.pyi @@ -7,7 +7,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .role import Role from .team import Application from .user import User -from ..http import HTTPClient +from ..http.HTTPClient import HTTPClient from ...models.component import ActionRow, Button, SelectMenu from .guild import Guild diff --git a/interactions/api/models/role.pyi b/interactions/api/models/role.pyi index c04ee08ee..b78886290 100644 --- a/interactions/api/models/role.pyi +++ b/interactions/api/models/role.pyi @@ -1,7 +1,7 @@ from typing import Any, Optional, List from .misc import DictSerializerMixin, MISSING, Snowflake -from ..http import HTTPClient +from ..http.HTTPClient import HTTPClient class RoleTags(DictSerializerMixin): _json: dict From b1b9bd05c416377b93774f00413dea7b3ad574ce Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 11:31:15 +0100 Subject: [PATCH 12/47] refactor: move Guild endpoint into file; add slots --- interactions/api/http/Guild.py | 633 ++++++++++++++++++++++++++++++ interactions/api/http/Guild.pyi | 112 ++++++ interactions/api/http/Limiter.py | 2 + interactions/api/http/Message.py | 4 +- interactions/api/http/Message.pyi | 2 +- interactions/api/http/User.py | 4 +- interactions/api/http/__init__.py | 1 + 7 files changed, 755 insertions(+), 3 deletions(-) diff --git a/interactions/api/http/Guild.py b/interactions/api/http/Guild.py index e69de29bb..38eb85f2e 100644 --- a/interactions/api/http/Guild.py +++ b/interactions/api/http/Guild.py @@ -0,0 +1,633 @@ +from typing import Any, Dict, List, Optional +from urllib.parse import quote + +from ...api.cache import Cache, Item +from ..models.channel import Channel +from ..models.guild import Guild +from ..models.member import Member +from ..models.role import Role +from .Request import Request +from .Route import Route + + +class HTTPGuild: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def get_self_guilds(self) -> List[dict]: + """ + Gets all guild objects associated with the current bot user. + + :return a list of partial guild objects the current bot user is a part of. + """ + request = await self._req.request(Route("GET", "/users/@me/guilds")) + + for guild in request: + if guild.get("id"): + self.cache.self_guilds.add(Item(id=guild["id"], value=Guild(**guild))) + + return request + + async def get_guild(self, guild_id: int) -> dict: + """ + Requests an individual guild from the API. + + :param guild_id: The guild snowflake ID associated. + :return: The guild object associated, if any. + """ + request = await self._req.request(Route("GET", "/guilds/{guild_id}", guild_id=guild_id)) + self.cache.guilds.add(Item(id=str(guild_id), value=Guild(**request))) + + return request + + async def get_guild_preview(self, guild_id: int) -> dict: + """ + Get a guild's preview. + + :param guild_id: Guild ID snowflake. + :return: Guild Preview object associated with the snowflake + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/preview")) + + async def modify_guild( + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Modifies a guild's attributes. + + :param guild_id: Guild ID snowflake. + :param payload: The parameters to change. + :param reason: Reason to send to the audit log, if given. + :return: The modified guild object as a dictionary + :rtype: dict + """ + + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}"), json=payload, reason=reason + ) + + async def leave_guild(self, guild_id: int) -> None: + """ + Leaves a guild. + + :param guild_id: The guild snowflake ID associated. + :return: None + """ + return await self._req.request( + Route("DELETE", f"/users/@me/guilds/{guild_id}", guild_id=guild_id) + ) + + async def delete_guild(self, guild_id: int) -> None: + """ + Deletes a guild. + + :param guild_id: Guild ID snowflake. + """ + return await self._req.request(Route("DELETE", f"/guilds/{guild_id}")) + + async def get_guild_widget(self, guild_id: int) -> dict: + """ + Returns the widget for the guild. + + :param guild_id: Guild ID snowflake. + :return: Guild Widget contents as a dict: {"enabled":bool, "channel_id": str} + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/widget.json")) + + async def get_guild_widget_settings(self, guild_id: int) -> dict: + """ + Get guild widget settings. + + :param guild_id: Guild ID snowflake. + :return: Guild Widget contents as a dict: {"enabled":bool, "channel_id": str} + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}")) + + async def get_guild_widget_image(self, guild_id: int, style: Optional[str] = None) -> str: + """ + Get an url representing a png image widget for the guild. + + ..note:: + See _ for list of styles. + + :param guild_id: Guild ID snowflake. + :param style: The style of widget required, if given. + :return: A url pointing to this image + """ + route = Route("GET", f"/guilds/{guild_id}/widget.png{f'?style={style}' if style else ''}") + return route.path + + async def modify_guild_widget(self, guild_id: int, payload: dict) -> dict: + """ + Modify a guild widget. + + :param guild_id: Guild ID snowflake. + :param payload: Payload containing new widget attributes. + :return: Updated widget attributes. + """ + return await self._req.request(Route("PATCH", f"/guilds/{guild_id}/widget"), json=payload) + + async def get_guild_invites(self, guild_id: int) -> List[dict]: + """ + Retrieves a list of invite objects with their own metadata. + + :param guild_id: Guild ID snowflake. + :return: A list of invite objects + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/invites")) + + async def get_guild_welcome_screen(self, guild_id: int) -> dict: + """ + Retrieves from the API a welcome screen associated with the guild. + + :param guild_id: Guild ID snowflake. + :return: Welcome Screen object + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/welcome-screen")) + + async def modify_guild_welcome_screen( + self, guild_id: int, enabled: bool, welcome_channels: List[int], description: str + ) -> dict: + """ + Modify the guild's welcome screen. + + :param guild_id: Guild ID snowflake. + :param enabled: Whether the welcome screen is enabled or not. + :param welcome_channels: The new channels (by their ID) linked in the welcome screen and their display options + :param description: The new server description to show in the welcome screen + :return: Updated Welcome screen object. + """ + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}/welcome-screen"), + json={ + "enabled": enabled, + "welcome_channels": welcome_channels, + "description": description, + }, + ) + + async def get_vanity_code(self, guild_id: int) -> dict: + return await self._req.request( + Route("GET", "/guilds/{guild_id}/vanity-url", guild_id=guild_id) + ) + + async def modify_vanity_code( + self, guild_id: int, code: str, reason: Optional[str] = None + ) -> None: + payload: Dict[str, Any] = {"code": code} + return await self._req.request( + Route("PATCH", "/guilds/{guild_id}/vanity-url", guild_id=guild_id), + json=payload, + reason=reason, + ) + + async def get_guild_integrations(self, guild_id: int) -> List[dict]: + """ + Gets a list of integration objects associated with the Guild from the API. + + :param guild_id: Guild ID snowflake. + :return: An array of integration objects + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/integrations")) + + async def delete_guild_integration(self, guild_id: int, integration_id: int) -> None: + """ + Deletes an integration from the guild. + + :param guild_id: Guild ID snowflake. + :param integration_id: Integration ID snowflake. + """ + return await self._req.request( + Route("DELETE", f"/guilds/{guild_id}/integrations/{integration_id}") + ) + + async def modify_current_user_voice_state( + self, + guild_id: int, + channel_id: int, + suppress: Optional[bool] = None, + request_to_speak_timestamp: Optional[str] = None, + ) -> None: + """ + Update the current user voice state. + + :param guild_id: Guild ID snowflake. + :param channel_id: Voice channel ID snowflake. + :param suppress: Toggle the user's suppress state, if given. + :param request_to_speak_timestamp: Sets the user's request to speak, if given. + """ + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}/voice-states/@me"), + json={ + k: v + for k, v in { + "channel_id": channel_id, + "suppress": suppress, + "request_to_speak_timestamp": request_to_speak_timestamp, + }.items() + if v is not None + }, + ) + + async def modify_user_voice_state( + self, guild_id: int, user_id: int, channel_id: int, suppress: Optional[bool] = None + ) -> None: + """ + Modify the voice state of a user. + + :param guild_id: Guild ID snowflake. + :param user_id: User ID snowflake. + :param channel_id: Voice channel ID snowflake. + :param suppress: Toggles the user's suppress state, if given. + """ + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}/voice-states/{user_id}"), + json={ + k: v + for k, v in {"channel_id": channel_id, "suppress": suppress}.items() + if v is not None + }, + ) + + async def create_guild_from_guild_template( + self, template_code: str, name: str, icon: Optional[str] = None + ) -> dict: + """ + Create a new guild based on a template. + + ..note:: + This endpoint can only be used by bots in less than 10 guilds. + + :param template_code: The code of the template to use. + :param name: The name of the guild (2-100 characters) + :param icon: Guild icon URI, if given. + :return: The newly created guild object. + """ + payload = { + "name": name, + } + if icon: + payload["icon"] = icon + return await self._req.request( + Route("POST", f"/guilds/templates/{template_code}", json=payload) + ) + + async def get_guild_templates(self, guild_id: int) -> List[dict]: + """ + Returns an array of guild templates. + + :param guild_id: Guild ID snowflake. + :return: An array of guild templates + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/templates")) + + async def create_guild_template( + self, guild_id: int, name: str, description: Optional[str] = None + ) -> dict: + """ + Create a guild template for the guild. + + :param guild_id: Guild ID snowflake. + :param name: The name of the template + :param description: The description of the template, if given. + :return: The created guild template + """ + return await self._req.request( + Route("POST", f"/guilds/{guild_id}/templates"), + json={ + k: v for k, v in {"name": name, "description": description}.items() if v is not None + }, + ) + + async def sync_guild_template(self, guild_id: int, template_code: str) -> dict: + """ + Sync the template to the guild's current state. + + :param guild_id: Guild ID snowflake. + :param template_code: The code for the template to sync + :return: The updated guild template. + """ + return await self._req.request( + Route("PUT", f"/guilds/{guild_id}/templates/{template_code}") + ) + + async def modify_guild_template( + self, + guild_id: int, + template_code: str, + name: Optional[str] = None, + description: Optional[str] = None, + ) -> dict: + """ + Modify a guild template. + + :param guild_id: Guild ID snowflake. + :param template_code: Template ID. + :param name: The name of the template + :param description: The description of the template + :return: The updated guild template + """ + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}/templates/{template_code}"), + json={ + k: v for k, v in {"name": name, "description": description}.items() if v is not None + }, + ) + + async def delete_guild_template(self, guild_id: int, template_code: str) -> dict: + """ + Delete the guild template. + + :param guild_id: Guild ID snowflake. + :param template_code: Template ID. + :return: The deleted template object + """ + # According to Polls, this returns the object. Why, I don't know. + return await self._req.request( + Route("DELETE", f"/guilds/{guild_id}/templates/{template_code}") + ) + + async def get_all_channels(self, guild_id: int) -> List[dict]: + """ + Requests from the API to get all channels in the guild. + + :param guild_id: Guild Snowflake ID + :return: A list of channels. + """ + request = await self._req.request( + Route("GET", "/guilds/{guild_id}/channels", guild_id=guild_id) + ) + + for channel in request: + if channel.get("id"): + self.cache.channels.add(Item(id=channel["id"], value=Channel(**channel))) + + return request + + async def get_all_roles(self, guild_id: int) -> List[dict]: + """ + Gets all roles from a Guild. + + :param guild_id: Guild ID snowflake + :return: An array of Role objects as dictionaries. + """ + request = await self._req.request( + Route("GET", "/guilds/{guild_id}/roles", guild_id=guild_id) + ) + + for role in request: + if role.get("id"): + self.cache.roles.add(Item(id=role["id"], value=Role(**role))) + + return request + + async def create_guild_role( + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Create a new role for the guild. + + :param guild_id: Guild ID snowflake. + :param payload: A dict containing metadata for the role. + :param reason: The reason for this action, if given. + :return: Role object + """ + request = await self._req.request( + Route("POST", f"/guilds/{guild_id}/roles"), json=payload, reason=reason + ) + if request.get("id"): + self.cache.roles.add(Item(id=request["id"], value=Role(**request))) + + return request + + async def modify_guild_role_position( + self, guild_id: int, role_id: int, position: int, reason: Optional[str] = None + ) -> List[dict]: + """ + Modify the position of a role in the guild. + + :param guild_id: Guild ID snowflake. + :param role_id: Role ID snowflake. + :param position: The new position of the associated role. + :param reason: The reason for this action, if given. + :return: List of guild roles with updated hierarchy. + """ + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}/roles"), + json={"id": role_id, "position": position}, + reason=reason, + ) + + async def modify_guild_role( + self, guild_id: int, role_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Modify a given role for the guild. + + :param guild_id: Guild ID snowflake. + :param role_id: Role ID snowflake. + :param payload: A dict containing updated metadata for the role. + :param reason: The reason for this action, if given. + :return: Updated role object. + """ + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}/roles/{role_id}"), json=payload, reason=reason + ) + + async def delete_guild_role(self, guild_id: int, role_id: int, reason: str = None) -> None: + """ + Delete a guild role. + + :param guild_id: Guild ID snowflake. + :param role_id: Role ID snowflake. + :param reason: The reason for this action, if any. + """ + return await self._req.request( + Route("DELETE", f"/guilds/{guild_id}/roles/{role_id}"), reason=reason + ) + + async def create_guild_kick( + self, guild_id: int, user_id: int, reason: Optional[str] = None + ) -> None: + """ + Kicks a person from the guild. + + :param guild_id: Guild ID snowflake + :param user_id: User ID snowflake + :param reason: Optional Reason argument. + """ + r = Route( + "DELETE", "/guilds/{guild_id}/members/{user_id}", guild_id=guild_id, user_id=user_id + ) + if reason: # apparently, its an aiohttp thing? + r.path += f"?reason={quote(reason)}" + + await self._req.request(r) + + async def create_guild_ban( + self, + guild_id: int, + user_id: int, + delete_message_days: Optional[int] = 0, + reason: Optional[str] = None, + ) -> None: + """ + Bans a person from the guild, and optionally deletes previous messages sent by them. + + :param guild_id: Guild ID snowflake + :param user_id: User ID snowflake + :param delete_message_days: Number of days to delete messages, from 0 to 7. Defaults to 0 + :param reason: Optional reason to ban. + """ + + return await self._req.request( + Route("PUT", f"/guilds/{guild_id}/bans/{user_id}"), + json={"delete_message_days": delete_message_days}, + reason=reason, + ) + + async def remove_guild_ban( + self, guild_id: int, user_id: int, reason: Optional[str] = None + ) -> None: + """ + Unbans someone using the API. + + :param guild_id: Guild ID snowflake + :param user_id: User ID snowflake + :param reason: Optional reason to unban. + """ + + return await self._req.request( + Route("DELETE", f"/guilds/{guild_id}/bans/{user_id}"), + json={}, + reason=reason, + ) + + async def get_guild_bans(self, guild_id: int) -> List[dict]: + """ + Gets a list of banned users. + + :param guild_id: Guild ID snowflake. + :return: A list of banned users. + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/bans")) + + async def get_user_ban(self, guild_id: int, user_id: int) -> Optional[dict]: + """ + Gets an object pertaining to the user, if it exists. Returns a 404 if it doesn't. + + :param guild_id: Guild ID snowflake + :param user_id: User ID snowflake. + :return: Ban object if it exists. + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/bans/{user_id}")) + + async def add_guild_member( + self, + guild_id: int, + user_id: int, + access_token: str, + nick: Optional[str] = None, + roles: Optional[List[Role]] = None, + mute: bool = None, + deaf: bool = None, + ) -> dict: + """ + A low level method of adding a user to a guild with pre-defined attributes. + + :param guild_id: Guild ID snowflake. + :param user_id: User ID snowflake. + :param access_token: User access token. + :param nick: User's nickname on join. + :param roles: An array of roles that the user is assigned. + :param mute: Whether the user is mute in voice channels. + :param deaf: Whether the user is deafened in voice channels. + :return: Guild member object as dictionary + """ + request = await self._req.request( + Route("PUT", f"/guilds/{guild_id}/members/{user_id}"), + json={ + k: v + for k, v in { + "access_token": access_token, + "nick": nick, + "roles": roles, + "mute": mute, + "deaf": deaf, + }.items() + if v is not None + }, + ) + + self.cache.members.add(Item(id=str(user_id), value=Member(**request))) + + return request + + async def remove_guild_member( + self, guild_id: int, user_id: int, reason: Optional[str] = None + ) -> None: + """ + A low level method of removing a member from a guild. This is different from banning them. + + :param guild_id: Guild ID snowflake. + :param user_id: User ID snowflake. + :param reason: Reason to send to audit log, if any. + """ + return await self._req.request( + Route("DELETE", f"/guilds/{guild_id}/members/{user_id}"), reason=reason + ) + + async def get_guild_prune_count( + self, guild_id: int, days: int = 7, include_roles: Optional[List[int]] = None + ) -> dict: + """ + Retrieves a dict from an API that results in how many members would be pruned given the amount of days. + + :param guild_id: Guild ID snowflake. + :param days: Number of days to count. Defaults to ``7``. + :param include_roles: Role IDs to include, if given. + :return: A dict denoting `{"pruned": int}` + """ + payload = {"days": days} + if include_roles: + payload["include_roles"] = ", ".join( + str(x) for x in include_roles + ) # would still iterate + + return await self._req.request(Route("GET", f"/guilds/{guild_id}/prune"), params=payload) + + async def get_guild_auditlog( + self, + guild_id: int, + user_id: Optional[int] = None, + action_type: Optional[int] = None, + before: Optional[int] = None, + limit: int = 50, + ) -> dict: + """ + Returns an audit log object for the guild. Requires the 'VIEW_AUDIT_LOG' permission. + :param guild_id: Guild ID snowflake. + :param user_id: User ID snowflake. filter the log for actions made by a user. + :param action_type: the type ID of audit log event. + :param before: filter the log before a certain entry id. + :param limit: how many entries are returned (default 50, minimum 1, maximum 100) + """ + + payload = {"limit": limit} + if user_id: + payload["user_id"] = user_id + if action_type: + payload["action_type"] = action_type + if before: + payload["before"] = before + + return await self._req.request( + Route("GET", f"/guilds/{guild_id}/audit-logs"), params=payload + ) diff --git a/interactions/api/http/Guild.pyi b/interactions/api/http/Guild.pyi index e69de29bb..e359d722d 100644 --- a/interactions/api/http/Guild.pyi +++ b/interactions/api/http/Guild.pyi @@ -0,0 +1,112 @@ +from typing import List, Optional, Dict, Any +from ...api.cache import Cache +from ..models.role import Role +from .Request import Request + + +class HTTPGuild: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def get_self_guilds(self) -> List[dict]: ... + async def get_guild(self, guild_id: int) -> dict: ... + async def get_guild_preview(self, guild_id: int) -> dict: ... + async def modify_guild( + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... + async def leave_guild(self, guild_id: int) -> None: ... + async def delete_guild(self, guild_id: int) -> None: ... + async def get_guild_widget(self, guild_id: int) -> dict: ... + async def get_guild_widget_settings(self, guild_id: int) -> dict: ... + async def get_guild_widget_image(self, guild_id: int, style: Optional[str] = None) -> str: ... + async def modify_guild_widget(self, guild_id: int, payload: dict) -> dict: ... + async def get_guild_invites(self, guild_id: int) -> List[dict]: ... + async def get_guild_welcome_screen(self, guild_id: int) -> dict: ... + async def modify_guild_welcome_screen( + self, guild_id: int, enabled: bool, welcome_channels: List[int], description: str + ) -> dict: ... + async def get_vanity_code(self, guild_id: int) -> dict: ... + async def modify_vanity_code( + self, guild_id: int, code: str, reason: Optional[str] = None + ) -> None: ... + async def get_guild_integrations(self, guild_id: int) -> List[dict]: ... + async def delete_guild_integration(self, guild_id: int, integration_id: int) -> None: ... + async def modify_current_user_voice_state( + self, + guild_id: int, + channel_id: int, + suppress: Optional[bool] = None, + request_to_speak_timestamp: Optional[str] = None, + ) -> None: ... + async def modify_user_voice_state( + self, guild_id: int, user_id: int, channel_id: int, suppress: Optional[bool] = None + ) -> None: ... + async def create_guild_from_guild_template( + self, template_code: str, name: str, icon: Optional[str] = None + ) -> dict: ... + async def get_guild_templates(self, guild_id: int) -> List[dict]: ... + async def create_guild_template( + self, guild_id: int, name: str, description: Optional[str] = None + ) -> dict: ... + async def sync_guild_template(self, guild_id: int, template_code: str) -> dict: ... + async def modify_guild_template( + self, + guild_id: int, + template_code: str, + name: Optional[str] = None, + description: Optional[str] = None, + ) -> dict: ... + async def delete_guild_template(self, guild_id: int, template_code: str) -> dict: ... + async def get_all_channels(self, guild_id: int) -> List[dict]: ... + async def get_all_roles(self, guild_id: int) -> List[dict]: ... + async def create_guild_role( + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... + async def modify_guild_role_position( + self, guild_id: int, role_id: int, position: int, reason: Optional[str] = None + ) -> List[dict]: ... + async def modify_guild_role( + self, guild_id: int, role_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... + async def delete_guild_role(self, guild_id: int, role_id: int, reason: str = None) -> None: ... + async def create_guild_kick( + self, guild_id: int, user_id: int, reason: Optional[str] = None + ) -> None: ... + async def create_guild_ban( + self, + guild_id: int, + user_id: int, + delete_message_days: Optional[int] = 0, + reason: Optional[str] = None, + ) -> None: ... + async def remove_guild_ban( + self, guild_id: int, user_id: int, reason: Optional[str] = None + ) -> None: ... + async def get_guild_bans(self, guild_id: int) -> List[dict]: ... + async def get_user_ban(self, guild_id: int, user_id: int) -> Optional[dict]: ... + async def add_guild_member( + self, + guild_id: int, + user_id: int, + access_token: str, + nick: Optional[str] = None, + roles: Optional[List[Role]] = None, + mute: bool = None, + deaf: bool = None, + ) -> dict: ... + async def remove_guild_member( + self, guild_id: int, user_id: int, reason: Optional[str] = None + ) -> None: ... + async def get_guild_prune_count( + self, guild_id: int, days: int = 7, include_roles: Optional[List[int]] = None + ) -> dict: ... + async def get_guild_auditlog( + self, + guild_id: int, + user_id: Optional[int] = None, + action_type: Optional[int] = None, + before: Optional[int] = None, + limit: int = 50, + ) -> dict: ... diff --git a/interactions/api/http/Limiter.py b/interactions/api/http/Limiter.py index 50849386b..c22e6fc55 100644 --- a/interactions/api/http/Limiter.py +++ b/interactions/api/http/Limiter.py @@ -12,6 +12,8 @@ class Limiter: :ivar float reset_after: The remaining time before the request can be ran. """ + __slots__ = ("lock", "reset_after") + lock: Lock reset_after: float diff --git a/interactions/api/http/Message.py b/interactions/api/http/Message.py index c4329280d..c76291306 100644 --- a/interactions/api/http/Message.py +++ b/interactions/api/http/Message.py @@ -9,10 +9,12 @@ class HTTPMessage: + __slots__ = ("_req", "cache") + _req: Request cache: Cache - def __init__(self, _req, cache): + def __init__(self, _req, cache) -> None: self._req = _req self.cache = cache diff --git a/interactions/api/http/Message.pyi b/interactions/api/http/Message.pyi index 80cdcca11..f3db06787 100644 --- a/interactions/api/http/Message.pyi +++ b/interactions/api/http/Message.pyi @@ -11,7 +11,7 @@ class HTTPMessage: _req: Request cache: Cache - def __init__(self, _req, cache): + def __init__(self, _req, cache) -> None: self._req = _req self.cache = cache async def send_message( diff --git a/interactions/api/http/User.py b/interactions/api/http/User.py index 061cd1cd5..8351134d3 100644 --- a/interactions/api/http/User.py +++ b/interactions/api/http/User.py @@ -9,10 +9,12 @@ class HTTPUser: + __slots__ = ("_req", "cache") + _req: Request cache: Cache - def __init__(self, _req, cache): + def __init__(self, _req, cache) -> None: self._req = _req self.cache = cache diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index 428ac7dfa..f15497692 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -4,6 +4,7 @@ Handles all HTTP-Requests of the library. """ +from .Guild import * # noqa: F401 F403 from .HTTPClient import * # noqa: F401 F403 from .Limiter import * # noqa: F401 F403 from .Message import * # noqa: F401 F403 From 645df9838735233c49f7a2fb06b587c6dd623942 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 11:54:31 +0100 Subject: [PATCH 13/47] refactor: move Member endpoint into file --- interactions/api/http/Member.py | 131 ++++++++++++++++++++++++++++++ interactions/api/http/Member.pyi | 29 +++++++ interactions/api/http/__init__.py | 1 + 3 files changed, 161 insertions(+) create mode 100644 interactions/api/http/Member.py create mode 100644 interactions/api/http/Member.pyi diff --git a/interactions/api/http/Member.py b/interactions/api/http/Member.py new file mode 100644 index 000000000..31b4ee841 --- /dev/null +++ b/interactions/api/http/Member.py @@ -0,0 +1,131 @@ +from typing import List, Optional + +from ...api.cache import Cache +from .Request import Request +from .Route import Route + + +class HTTPMember: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def get_member(self, guild_id: int, member_id: int) -> Optional[dict]: + """ + Uses the API to fetch a member from a guild. + + :param guild_id: Guild ID snowflake. + :param member_id: Member ID snowflake. + :return: A member object, if any. + """ + return await self._req.request( + Route( + "GET", + "/guilds/{guild_id}/members/{member_id}", + guild_id=guild_id, + member_id=member_id, + ) + ) + + async def get_list_of_members( + self, guild_id: int, limit: int = 1, after: Optional[int] = None + ) -> List[dict]: + """ + Lists the members of a guild. + + :param guild_id: Guild ID snowflake + :param limit: How many members to get from the API. Max is 1000. Defaults to 1. + :param after: Get Member IDs after this snowflake. Defaults to None. + :return: An array of Member objects. + """ + payload = {"limit": limit} + if after: + payload["after"] = after + + return await self._req.request(Route("GET", f"/guilds/{guild_id}/members"), params=payload) + + async def search_guild_members(self, guild_id: int, query: str, limit: int = 1) -> List[dict]: + """ + Search a guild for members whose username or nickname starts with provided string. + + :param guild_id: Guild ID snowflake. + :param query: The string to search for + :param limit: The number of members to return. Defaults to 1. + """ + + return await self._req.request( + Route("GET", f"/guilds/{guild_id}/members/search"), + params={"query": query, "limit": limit}, + ) + + async def add_member_role( + self, guild_id: int, user_id: int, role_id: int, reason: Optional[str] = None + ) -> None: + """ + Adds a role to a guild member. + + :param guild_id: The ID of the guild + :param user_id: The ID of the user + :param role_id: The ID of the role to add + :param reason: The reason for this action. Defaults to None. + """ + return await self._req.request( + Route( + "PUT", + "/guilds/{guild_id}/members/{user_id}/roles/{role_id}", + guild_id=guild_id, + user_id=user_id, + role_id=role_id, + ), + reason=reason, + ) + + async def remove_member_role( + self, guild_id: int, user_id: int, role_id: int, reason: Optional[str] = None + ) -> None: + """ + Removes a role to a guild member. + + :param guild_id: The ID of the guild + :param user_id: The ID of the user + :param role_id: The ID of the role to add + :param reason: The reason for this action. Defaults to None. + """ + return await self._req.request( + Route( + "DELETE", + "/guilds/{guild_id}/members/{user_id}/roles/{role_id}", + guild_id=guild_id, + user_id=user_id, + role_id=role_id, + ), + reason=reason, + ) + + async def modify_member( + self, user_id: int, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Edits a member. + This can nick them, change their roles, mute/deafen (and its contrary), and moving them across channels and/or disconnect them. + + :param user_id: Member ID snowflake. + :param guild_id: Guild ID snowflake. + :param payload: Payload representing parameters (nick, roles, mute, deaf, channel_id) + :param reason: The reason for this action. Defaults to None. + :return: Modified member object. + """ + + return await self._req.request( + Route( + "PATCH", "/guilds/{guild_id}/members/{user_id}", guild_id=guild_id, user_id=user_id + ), + json=payload, + reason=reason, + ) diff --git a/interactions/api/http/Member.pyi b/interactions/api/http/Member.pyi new file mode 100644 index 000000000..5ef545fae --- /dev/null +++ b/interactions/api/http/Member.pyi @@ -0,0 +1,29 @@ +from typing import List, Optional + +from ...api.cache import Cache +from .Request import Request +from .Route import Route + + +class HTTPMember: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def get_member(self, guild_id: int, member_id: int) -> Optional[dict]: ... + async def get_list_of_members( + self, guild_id: int, limit: int = 1, after: Optional[int] = None + ) -> List[dict]: ... + async def search_guild_members(self, guild_id: int, query: str, limit: int = 1) -> List[dict]: ... + async def add_member_role( + self, guild_id: int, user_id: int, role_id: int, reason: Optional[str] = None + ) -> None: ... + async def remove_member_role( + self, guild_id: int, user_id: int, role_id: int, reason: Optional[str] = None + ) -> None: ... + async def modify_member( + self, user_id: int, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index f15497692..69029325c 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -7,6 +7,7 @@ from .Guild import * # noqa: F401 F403 from .HTTPClient import * # noqa: F401 F403 from .Limiter import * # noqa: F401 F403 +from .Member import * # noqa: F401 F403 from .Message import * # noqa: F401 F403 from .Request import * # noqa: F401 F403 from .Route import * # noqa: F401 F403 From 00facd21e9d73c53fbc55a00552f576386db0f1d Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 12:18:58 +0100 Subject: [PATCH 14/47] refactor: move Channel endpoint into file --- interactions/api/http/Channel.py | 320 ++++++++++++++++++++++++++++++ interactions/api/http/__init__.py | 1 + 2 files changed, 321 insertions(+) create mode 100644 interactions/api/http/Channel.py diff --git a/interactions/api/http/Channel.py b/interactions/api/http/Channel.py new file mode 100644 index 000000000..8e188516a --- /dev/null +++ b/interactions/api/http/Channel.py @@ -0,0 +1,320 @@ +from typing import Dict, List, Optional, Union + +from ...api.cache import Cache, Item +from ..models.channel import Channel +from ..models.message import Message +from .Request import Request +from .Route import Route + + +class HTTPChannel: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def get_channel(self, channel_id: int) -> dict: + """ + Gets a channel by ID. If the channel is a thread, it also includes thread members (and other thread attributes). + + :param channel_id: Channel ID snowflake. + :return: Dictionary of the channel object. + """ + request = await self._req.request(Route("GET", f"/channels/{channel_id}")) + self.cache.channels.add(Item(id=str(channel_id), value=Channel(**request))) + + return request + + async def delete_channel(self, channel_id: int) -> None: + """ + Deletes a channel. + + :param channel_id: Channel ID snowflake + """ + return await self._req.request( + Route("DELETE", "/channels/{channel_id}", channel_id=channel_id) + ) + + async def get_channel_messages( + self, + channel_id: int, + limit: int = 50, + around: Optional[int] = None, + before: Optional[int] = None, + after: Optional[int] = None, + ) -> List[dict]: + """ + Get messages from a channel. + + ..note:: + around, before, and after arguments are mutually exclusive. + + :param channel_id: Channel ID snowflake. + :param limit: How many messages to get. Defaults to 50, the max is 100. + :param around: Get messages around this snowflake ID. + :param before: Get messages before this snowflake ID. + :param after: Get messages after this snowflake ID. + :return: An array of Message objects. + """ + params: Dict[str, Union[int, str]] = {"limit": limit} + + params_used = 0 + + if before: + params_used += 1 + params["before"] = before + if after: + params_used += 1 + params["after"] = after + if around: + params_used += 1 + params["around"] = around + + if params_used > 1: + raise ValueError( + "`before`, `after` and `around` are mutually exclusive. Please pass only one of them." + ) + + request = await self._req.request( + Route("GET", f"/channels/{channel_id}/messages"), params=params + ) + + for message in request: + if message.get("id"): + self.cache.messages.add(Item(id=message["id"], value=Message(**message))) + + return request + + async def create_channel( + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Creates a channel within a guild. + + ..note:: + This does not handle payload in this method. Tread carefully. + + :param guild_id: Guild ID snowflake. + :param payload: Payload data. + :param reason: Reason to show in audit log, if needed. + :return: Channel object as dictionary. + """ + request = await self._req.request( + Route("POST", f"/guilds/{guild_id}/channels"), json=payload, reason=reason + ) + if request.get("id"): + self.cache.channels.add(Item(id=request["id"], value=Channel(**request))) + + return request + + async def move_channel( + self, + guild_id: int, + channel_id: int, + new_pos: int, + parent_id: Optional[int], + lock_perms: bool = False, + reason: Optional[str] = None, + ) -> dict: + """ + Moves a channel to a new position. + + :param guild_id: Guild ID snowflake. + :param channel_id: Channel ID snowflake. + :param new_pos: The new channel position. + :param parent_id: The category parent ID, if needed. + :param lock_perms: Sync permissions with the parent associated with parent_id. Defaults to False. + :param reason: Reason to display to the audit log, if any. + :return: ? + """ + payload = {"id": channel_id, "position": new_pos, "lock_permissions": lock_perms} + if parent_id: + payload["parent_id"] = parent_id + + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}/channels"), json=payload, reason=reason + ) + + async def modify_channel( + self, channel_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Update a channel's settings. + + :param channel_id: Channel ID snowflake. + :param payload: Data representing updated settings. + :param reason: Reason, if any. + :return: Channel with updated attributes, if successful. + """ + return await self._req.request( + Route("PATCH", f"/channels/{channel_id}"), json=payload, reason=reason + ) + + async def get_channel_invites(self, channel_id: int) -> List[dict]: + """ + Get the invites for the channel. + + :param channel_id: Channel ID snowflake. + :return: List of invite objects + """ + return await self._req.request(Route("GET", f"/channels/{channel_id}/invites")) + + async def create_channel_invite( + self, channel_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Creates an invite for the given channel. + + ..note:: + This method does not handle payload. It just sends it. + + :param channel_id: Channel ID snowflake. + :param payload: Data representing the payload/invite attributes. + :param reason: Reason to show in the audit log, if any. + :return: An invite object. + """ + return await self._req.request( + Route("POST", f"/channels/{channel_id}/invites"), json=payload, reason=reason + ) + + async def delete_invite(self, invite_code: str, reason: Optional[str] = None) -> dict: + """ + Delete an invite. + + :param invite_code: The code of the invite to delete + :param reason: Reason to show in the audit log, if any. + :return: The deleted invite object + """ + return await self._req.request(Route("DELETE", f"/invites/{invite_code}"), reason=reason) + + async def edit_channel_permission( + self, + channel_id: int, + overwrite_id: int, + allow: str, + deny: str, + perm_type: int, + reason: Optional[str] = None, + ) -> None: + """ + Edits the channel's permission overwrites for a user or role in a given channel. + + :param channel_id: Channel ID snowflake. + :param overwrite_id: The ID of the overridden object. + :param allow: the bitwise value of all allowed permissions + :param deny: the bitwise value of all disallowed permissions + :param perm_type: 0 for a role or 1 for a member + :param reason: Reason to display in the Audit Log, if given. + """ + return await self._req.request( + Route("PUT", f"/channels/{channel_id}/permissions/{overwrite_id}"), + json={"allow": allow, "deny": deny, "type": perm_type}, + reason=reason, + ) + + async def delete_channel_permission( + self, channel_id: int, overwrite_id: int, reason: Optional[str] = None + ) -> None: + """ + Deletes a channel permission overwrite for a user or role in a channel. + + :param channel_id: Channel ID snowflake. + :param overwrite_id: The ID of the overridden object. + :param reason: Reason to display in the Audit Log, if given. + """ + return await self._req.request( + Route("DELETE", f"/channels/{channel_id}/{overwrite_id}"), reason=reason + ) + + async def trigger_typing(self, channel_id: int) -> None: + """ + Posts "... is typing" in a given channel. + + ..note: + By default, this lib doesn't use this endpoint, however, this is listed for third-party implementation. + + :param channel_id: Channel ID snowflake. + """ + return await self._req.request(Route("POST", f"/channels/{channel_id}/typing")) + + async def get_pinned_messages(self, channel_id: int) -> List[dict]: + """ + Get all pinned messages from a channel. + + :param channel_id: Channel ID snowflake. + :return: A list of pinned message objects. + """ + return await self._req.request(Route("GET", f"/channels/{channel_id}/pins")) + + async def create_stage_instance( + self, channel_id: int, topic: str, privacy_level: int = 1, reason: Optional[str] = None + ) -> dict: + """ + Create a new stage instance. + + :param channel_id: Channel ID snowflake. + :param topic: The topic of the stage instance. Limited to 1-120 characters. + :param privacy_level: The privacy_level of the stage instance (defaults to guild-only "1"). + :param reason: The reason for the creating the stage instance, if any. + :return: The new stage instance + """ + return await self._req.request( + Route("POST", "/stage-instances"), + json={ + "channel_id": channel_id, + "topic": topic, + "privacy_level": privacy_level, + }, + reason=reason, + ) + + async def get_stage_instance(self, channel_id: int) -> dict: + """ + Get the stage instance associated with a given channel, if it exists. + + :param channel_id: Channel ID snowflake. + :return: A stage instance. + """ + return await self._req.request(Route("GET", f"/stage-instances/{channel_id}")) + + async def modify_stage_instance( + self, + channel_id: int, + topic: Optional[str] = None, + privacy_level: Optional[int] = None, + reason: Optional[str] = None, + ) -> dict: + """ + Update the fields of a given stage instance. + + :param channel_id: Channel ID snowflake. + :param topic: The new topic of the stage instance, if given. Limited to 1-120 characters. + :param privacy_level: The new privacy_level of the stage instance. + :param reason: The reason for the creating the stage instance, if any. + :return: The updated stage instance. + """ + return await self._req.request( + Route("PATCH", f"/stage-instances/{channel_id}"), + json={ + k: v + for k, v in {"topic": topic, "privacy_level": privacy_level}.items() + if v is not None + }, + reason=reason, + ) + + async def delete_stage_instance(self, channel_id: int, reason: Optional[str] = None) -> None: + """ + Delete a stage instance. + + :param channel_id: Channel ID snowflake. + :param reason: The reason for the creating the stage instance, if any. + """ + return await self._req.request( + Route("DELETE", f"/stage-instances/{channel_id}"), reason=reason + ) diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index 69029325c..6349f0f6a 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -4,6 +4,7 @@ Handles all HTTP-Requests of the library. """ +from .Channel import * # noqa: F401 F403 from .Guild import * # noqa: F401 F403 from .HTTPClient import * # noqa: F401 F403 from .Limiter import * # noqa: F401 F403 From 7fb75502cdac19f33a5a2e67e598be92a16a366f Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 12:19:07 +0100 Subject: [PATCH 15/47] refactor: move Channel endpoint into file --- interactions/api/http/Channel.pyi | 69 +++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 interactions/api/http/Channel.pyi diff --git a/interactions/api/http/Channel.pyi b/interactions/api/http/Channel.pyi new file mode 100644 index 000000000..f3bb44119 --- /dev/null +++ b/interactions/api/http/Channel.pyi @@ -0,0 +1,69 @@ +from typing import Dict, List, Optional, Union + +from ...api.cache import Cache +from .Request import Request + + +class HTTPChannel: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def get_channel(self, channel_id: int) -> dict: ... + async def delete_channel(self, channel_id: int) -> None: ... + async def get_channel_messages( + self, + channel_id: int, + limit: int = 50, + around: Optional[int] = None, + before: Optional[int] = None, + after: Optional[int] = None, + ) -> List[dict]: ... + async def create_channel( + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... + async def move_channel( + self, + guild_id: int, + channel_id: int, + new_pos: int, + parent_id: Optional[int], + lock_perms: bool = False, + reason: Optional[str] = None, + ) -> dict: ... + async def modify_channel( + self, channel_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... + async def get_channel_invites(self, channel_id: int) -> List[dict]: ... + async def create_channel_invite( + self, channel_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... + async def delete_invite(self, invite_code: str, reason: Optional[str] = None) -> dict: ... + async def edit_channel_permission( + self, + channel_id: int, + overwrite_id: int, + allow: str, + deny: str, + perm_type: int, + reason: Optional[str] = None, + ) -> None: ... + async def delete_channel_permission( + self, channel_id: int, overwrite_id: int, reason: Optional[str] = None + ) -> None: ... + async def trigger_typing(self, channel_id: int) -> None: ... + async def get_pinned_messages(self, channel_id: int) -> List[dict]: ... + async def create_stage_instance( + self, channel_id: int, topic: str, privacy_level: int = 1, reason: Optional[str] = None + ) -> dict: ... + async def get_stage_instance(self, channel_id: int) -> dict: ... + async def modify_stage_instance( + self, + channel_id: int, + topic: Optional[str] = None, + privacy_level: Optional[int] = None, + reason: Optional[str] = None, + ) -> dict: ... + async def delete_stage_instance(self, channel_id: int, reason: Optional[str] = None) -> None: ... + a From 0e3a0f150fdce8a78f8a5d804cab2ce14651c1fe Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 12:27:32 +0100 Subject: [PATCH 16/47] refactor: move Thread endpoint into file --- interactions/api/http/Channel.pyi | 1 - interactions/api/http/Thread.py | 192 ++++++++++++++++++++++++++++++ interactions/api/http/Thread.pyi | 37 ++++++ interactions/api/http/__init__.py | 1 + 4 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 interactions/api/http/Thread.py create mode 100644 interactions/api/http/Thread.pyi diff --git a/interactions/api/http/Channel.pyi b/interactions/api/http/Channel.pyi index f3bb44119..061ac5902 100644 --- a/interactions/api/http/Channel.pyi +++ b/interactions/api/http/Channel.pyi @@ -66,4 +66,3 @@ class HTTPChannel: reason: Optional[str] = None, ) -> dict: ... async def delete_stage_instance(self, channel_id: int, reason: Optional[str] = None) -> None: ... - a diff --git a/interactions/api/http/Thread.py b/interactions/api/http/Thread.py new file mode 100644 index 000000000..ac395e399 --- /dev/null +++ b/interactions/api/http/Thread.py @@ -0,0 +1,192 @@ +from typing import List, Optional + +from ...api.cache import Cache, Item +from .Request import Request +from .Route import Route + + +class HTTPThread: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def join_thread(self, thread_id: int) -> None: + """ + Have the bot user join a thread. + + :param thread_id: The thread to join. + """ + return await self._req.request(Route("PUT", f"/channels/{thread_id}/thread-members/@me")) + + async def leave_thread(self, thread_id: int) -> None: + """ + Have the bot user leave a thread. + + :param thread_id: The thread to leave. + """ + return await self._req.request(Route("DELETE", f"/channels/{thread_id}/thread-members/@me")) + + async def add_member_to_thread(self, thread_id: int, user_id: int) -> None: + """ + Add another user to a thread. + + :param thread_id: The ID of the thread + :param user_id: The ID of the user to add + """ + return await self._req.request( + Route("PUT", f"/channels/{thread_id}/thread-members/{user_id}") + ) + + async def remove_member_from_thread(self, thread_id: int, user_id: int) -> None: + """ + Remove another user from a thread. + + :param thread_id: The ID of the thread + :param user_id: The ID of the user to remove + """ + return await self._req.request( + Route("DELETE", f"/channels/{thread_id}/thread-members/{user_id}") + ) + + async def get_member_from_thread(self, thread_id: int, user_id: int) -> dict: + """ + Get a member from a thread. + + :param thread_id: The ID of the thread + :param user_id: The ID of the user to find + :return: A thread member object, if they're in the thread. + """ + # Returns 404 if they don't + return await self._req.request( + Route("GET", f"/channels/{thread_id}/thread-members/{user_id}") + ) + + async def list_thread_members(self, thread_id: int) -> List[dict]: + """ + Get a list of members in the thread. + + :param thread_id: the id of the thread + :return: a list of thread member objects + """ + return await self._req.request(Route("GET", f"/channels/{thread_id}/thread-members")) + + async def list_public_archived_threads( + self, channel_id: int, limit: int = None, before: Optional[int] = None + ) -> List[dict]: + """ + Get a list of archived public threads in a given channel. + + :param channel_id: The channel to get threads from + :param limit: Optional limit of threads to + :param before: Get threads before this Thread snowflake ID + :return: a list of threads + """ + payload = {} + if limit: + payload["limit"] = limit + if before: + payload["before"] = before + return await self._req.request( + Route("GET", f"/channels/{channel_id}/threads/archived/public"), json=payload + ) + + async def list_private_archived_threads( + self, channel_id: int, limit: int = None, before: Optional[int] = None + ) -> List[dict]: + """ + Get a list of archived private threads in a channel. + + :param channel_id: The channel to get threads from + :param limit: Optional limit of threads to + :param before: Get threads before this Thread snowflake ID + :return: a list of threads + """ + payload = {} + if limit: + payload["limit"] = limit + if before: + payload["before"] = before + return await self._req.request( + Route("GET", f"/channels/{channel_id}/threads/archived/private"), json=payload + ) + + async def list_joined_private_archived_threads( + self, channel_id: int, limit: int = None, before: Optional[int] = None + ) -> List[dict]: + """ + Get a list of archived private threads in a channel that the bot has joined. + + :param channel_id: The channel to get threads from + :param limit: Optional limit of threads to + :param before: Get threads before this snowflake ID + :return: a list of threads + """ + payload = {} + if limit: + payload["limit"] = limit + if before: + payload["before"] = before + return await self._req.request( + Route("GET", f"/channels/{channel_id}/users/@me/threads/archived/private"), json=payload + ) + + async def list_active_threads(self, guild_id: int) -> List[dict]: + """ + List active threads within a guild. + + :param guild_id: the guild id to get threads from + :return: A list of active threads + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/threads/active")) + + async def create_thread( + self, + channel_id: int, + name: str, + thread_type: int = None, + auto_archive_duration: Optional[int] = None, + invitable: Optional[bool] = None, + message_id: Optional[int] = None, + reason: Optional[str] = None, + ) -> dict: + """ + From a given channel, create a Thread with an optional message to start with.. + + :param channel_id: The ID of the channel to create this thread in + :param name: The name of the thread + :param auto_archive_duration: duration in minutes to automatically archive the thread after recent activity, + can be set to: 60, 1440, 4320, 10080 + :param thread_type: The type of thread, defaults to public. ignored if creating thread from a message + :param invitable: Boolean to display if the Thread is open to join or private. + :param message_id: An optional message to create a thread from. + :param reason: An optional reason for the audit log + :return: The created thread + """ + payload = {"name": name} + if auto_archive_duration: + payload["auto_archive_duration"] = auto_archive_duration + if message_id: + request = await self._req.request( + Route("POST", f"/channels/{channel_id}/messages/{message_id}/threads"), + json=payload, + reason=reason, + ) + if request.get("id"): + self.cache.channels.add(Item(id=request["id"], value=request)) + return request + + payload["type"] = thread_type + payload["invitable"] = invitable + request = await self._req.request( + Route("POST", f"/channels/{channel_id}/threads"), json=payload, reason=reason + ) + if request.get("id"): + self.cache.channels.add(Item(id=request["id"], value=request)) + + return request diff --git a/interactions/api/http/Thread.pyi b/interactions/api/http/Thread.pyi new file mode 100644 index 000000000..a08050259 --- /dev/null +++ b/interactions/api/http/Thread.pyi @@ -0,0 +1,37 @@ +from typing import List, Optional + +from ...api.cache import Cache +from .Request import Request + +class HTTPThread: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def join_thread(self, thread_id: int) -> None: ... + async def leave_thread(self, thread_id: int) -> None: ... + async def add_member_to_thread(self, thread_id: int, user_id: int) -> None: ... + async def remove_member_from_thread(self, thread_id: int, user_id: int) -> None: ... + async def get_member_from_thread(self, thread_id: int, user_id: int) -> dict: ... + async def list_thread_members(self, thread_id: int) -> List[dict]: ... + async def list_public_archived_threads( + self, channel_id: int, limit: int = None, before: Optional[int] = None + ) -> List[dict]: ... + async def list_private_archived_threads( + self, channel_id: int, limit: int = None, before: Optional[int] = None + ) -> List[dict]: ... + async def list_joined_private_archived_threads( + self, channel_id: int, limit: int = None, before: Optional[int] = None + ) -> List[dict]: ... + async def list_active_threads(self, guild_id: int) -> List[dict]: ... + async def create_thread( + self, + channel_id: int, + name: str, + thread_type: int = None, + auto_archive_duration: Optional[int] = None, + invitable: Optional[bool] = None, + message_id: Optional[int] = None, + reason: Optional[str] = None, + ) -> dict: ... diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index 6349f0f6a..d5539a0f5 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -12,4 +12,5 @@ from .Message import * # noqa: F401 F403 from .Request import * # noqa: F401 F403 from .Route import * # noqa: F401 F403 +from .Thread import * # noqa: F401 F403 from .User import * # noqa: F401 F403 From 034905f411c6ab47464ed5676628ea015b9350eb Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 12:57:42 +0100 Subject: [PATCH 17/47] refactor: move Reaction endpoint into file --- interactions/api/http/Reaction.py | 132 +++++++++++++++++++++++++++++ interactions/api/http/Reaction.pyi | 24 ++++++ interactions/api/http/__init__.py | 1 + 3 files changed, 157 insertions(+) create mode 100644 interactions/api/http/Reaction.py create mode 100644 interactions/api/http/Reaction.pyi diff --git a/interactions/api/http/Reaction.py b/interactions/api/http/Reaction.py new file mode 100644 index 000000000..85f6df99d --- /dev/null +++ b/interactions/api/http/Reaction.py @@ -0,0 +1,132 @@ +from typing import List + +from ...api.cache import Cache +from .Request import Request +from .Route import Route + + +class HTTPReaction: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def create_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: + """ + Create a reaction for a message. + + :param channel_id: Channel snowflake ID. + :param message_id: Message snowflake ID. + :param emoji: The emoji to use (format: `name:id`) + """ + return await self._req.request( + Route( + "PUT", + "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me", + channel_id=channel_id, + message_id=message_id, + emoji=emoji, + ) + ) + + async def remove_self_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: + """ + Remove bot user's reaction from a message. + + :param channel_id: Channel snowflake ID. + :param message_id: Message snowflake ID. + :param emoji: The emoji to remove (format: `name:id`) + """ + return await self._req.request( + Route( + "DELETE", + "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me", + channel_id=channel_id, + message_id=message_id, + emoji=emoji, + ) + ) + + async def remove_user_reaction( + self, channel_id: int, message_id: int, emoji: str, user_id: int + ) -> None: + """ + Remove user's reaction from a message. + + :param channel_id: The channel this is taking place in + :param message_id: The message to remove the reaction on. + :param emoji: The emoji to remove. (format: `name:id`) + :param user_id: The user to remove reaction of. + """ + return await self._req.request( + Route( + "DELETE", + "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}/{user_id}", + channel_id=channel_id, + message_id=message_id, + emoji=emoji, + user_id=user_id, + ) + ) + + async def remove_all_reactions(self, channel_id: int, message_id: int) -> None: + """ + Remove all reactions from a message. + + :param channel_id: The channel this is taking place in. + :param message_id: The message to clear reactions from. + """ + return await self._req.request( + Route( + "DELETE", + "/channels/{channel_id}/messages/{message_id}/reactions", + channel_id=channel_id, + message_id=message_id, + ) + ) + + async def remove_all_reactions_of_emoji( + self, channel_id: int, message_id: int, emoji: str + ) -> None: + """ + Remove all reactions of a certain emoji from a message. + + :param channel_id: Channel snowflake ID. + :param message_id: Message snowflake ID. + :param emoji: The emoji to remove (format: `name:id`) + """ + return await self._req.request( + Route( + "DELETE", + "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}", + channel_id=channel_id, + message_id=message_id, + emoji=emoji, + ) + ) + + async def get_reactions_of_emoji( + self, channel_id: int, message_id: int, emoji: str + ) -> List[dict]: + """ + Gets the users who reacted to the emoji. + + :param channel_id: Channel snowflake ID. + :param message_id: Message snowflake ID. + :param emoji: The emoji to get (format: `name:id`) + :return A list of users who sent that emoji. + """ + return await self._req.request( + Route( + "GET", + "/channels/{channel_id}/messages/{message_id}/reactions/{emoji}", + channel_id=channel_id, + message_id=message_id, + emoji=emoji, + ) + ) diff --git a/interactions/api/http/Reaction.pyi b/interactions/api/http/Reaction.pyi new file mode 100644 index 000000000..a5a33731a --- /dev/null +++ b/interactions/api/http/Reaction.pyi @@ -0,0 +1,24 @@ +from typing import List + +from ...api.cache import Cache +from .Request import Request + + +class HTTPReaction: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def create_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: ... + async def remove_self_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: ... + async def remove_user_reaction( + self, channel_id: int, message_id: int, emoji: str, user_id: int + ) -> None: ... + async def remove_all_reactions(self, channel_id: int, message_id: int) -> None: ... + async def remove_all_reactions_of_emoji( + self, channel_id: int, message_id: int, emoji: str + ) -> None: ... + async def get_reactions_of_emoji( + self, channel_id: int, message_id: int, emoji: str + ) -> List[dict]: ... diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index d5539a0f5..eea3f4706 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -10,6 +10,7 @@ from .Limiter import * # noqa: F401 F403 from .Member import * # noqa: F401 F403 from .Message import * # noqa: F401 F403 +from .Reaction import * # noqa: F401 F403 from .Request import * # noqa: F401 F403 from .Route import * # noqa: F401 F403 from .Thread import * # noqa: F401 F403 From f1126e580dec92f31636f6f4302173643a3c8dd6 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 13:22:43 +0100 Subject: [PATCH 18/47] refactor: move Sticker endpoint into file --- interactions/api/http/Sticker.py | 101 ++++++++++++++++++++++++++++++ interactions/api/http/Sticker.pyi | 27 ++++++++ interactions/api/http/__init__.py | 1 + 3 files changed, 129 insertions(+) create mode 100644 interactions/api/http/Sticker.py create mode 100644 interactions/api/http/Sticker.pyi diff --git a/interactions/api/http/Sticker.py b/interactions/api/http/Sticker.py new file mode 100644 index 000000000..ed6045e28 --- /dev/null +++ b/interactions/api/http/Sticker.py @@ -0,0 +1,101 @@ +from typing import List, Optional + +from aiohttp import FormData + +from ...api.cache import Cache +from .Request import Request +from .Route import Route + + +class HTTPSticker: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def get_sticker(self, sticker_id: int) -> dict: + """ + Get a specific sticker. + + :param sticker_id: The id of the sticker + :return: Sticker or None + """ + return await self._req.request(Route("GET", f"/stickers/{sticker_id}")) + + async def list_nitro_sticker_packs(self) -> List[dict]: + """ + Gets the list of sticker packs available to Nitro subscribers. + + :return: List of sticker packs + """ + return await self._req.request(Route("GET", "/sticker-packs")) + + async def list_guild_stickers(self, guild_id: int) -> List[dict]: + """ + Get the stickers for a guild. + + :param guild_id: The guild to get stickers from + :return: List of Stickers or None + """ + return await self._req.request(Route("GET", f"/guild/{guild_id}/stickers")) + + async def get_guild_sticker(self, guild_id: int, sticker_id: int) -> dict: + """ + Get a sticker from a guild. + + :param guild_id: The guild to get stickers from + :param sticker_id: The sticker to get from the guild + :return: Sticker or None + """ + return await self._req.request(Route("GET", f"/guild/{guild_id}/stickers/{sticker_id}")) + + async def create_guild_sticker( + self, payload: FormData, guild_id: int, reason: Optional[str] = None + ) -> dict: + """ + Create a new sticker for the guild. Requires the MANAGE_EMOJIS_AND_STICKERS permission. + + :param payload: the payload to send. + :param guild_id: The guild to create sticker at. + :param reason: The reason for this action. + :return: The new sticker data on success. + """ + return await self._req.request( + Route("POST", f"/guild/{guild_id}/stickers"), json=payload, reason=reason + ) + + async def modify_guild_sticker( + self, payload: dict, guild_id: int, sticker_id: int, reason: Optional[str] = None + ) -> dict: + """ + Modify the given sticker. Requires the MANAGE_EMOJIS_AND_STICKERS permission. + + :param payload: the payload to send. + :param guild_id: The guild of the target sticker. + :param sticker_id: The sticker to modify. + :param reason: The reason for this action. + :return: The updated sticker data on success. + """ + return await self._req.request( + Route("PATCH", f"/guild/{guild_id}/stickers/{sticker_id}"), json=payload, reason=reason + ) + + async def delete_guild_sticker( + self, guild_id: int, sticker_id: int, reason: Optional[str] = None + ) -> None: + """ + Delete the given sticker. Requires the MANAGE_EMOJIS_AND_STICKERS permission. + + :param guild_id: The guild of the target sticker. + :param sticker_id: The sticker to delete. + :param reason: The reason for this action. + :return: Returns 204 No Content on success. + """ + return await self._req.request( + Route("DELETE", f"/guild/{guild_id}/stickers/{sticker_id}"), reason=reason + ) diff --git a/interactions/api/http/Sticker.pyi b/interactions/api/http/Sticker.pyi new file mode 100644 index 000000000..d86f0439b --- /dev/null +++ b/interactions/api/http/Sticker.pyi @@ -0,0 +1,27 @@ +from typing import List, Optional + +from aiohttp import FormData + +from ...api.cache import Cache +from .Request import Request + + +class HTTPSticker: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def get_sticker(self, sticker_id: int) -> dict: ... + async def list_nitro_sticker_packs(self) -> List[dict]: ... + async def list_guild_stickers(self, guild_id: int) -> List[dict]: ... + async def get_guild_sticker(self, guild_id: int, sticker_id: int) -> dict: ... + async def create_guild_sticker( + self, payload: FormData, guild_id: int, reason: Optional[str] = None + ) -> dict: ... + async def modify_guild_sticker( + self, payload: dict, guild_id: int, sticker_id: int, reason: Optional[str] = None + ) -> dict: ... + async def delete_guild_sticker( + self, guild_id: int, sticker_id: int, reason: Optional[str] = None + ) -> None: ... diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index eea3f4706..eabf9b935 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -13,5 +13,6 @@ from .Reaction import * # noqa: F401 F403 from .Request import * # noqa: F401 F403 from .Route import * # noqa: F401 F403 +from .Sticker import * # noqa: F401 F403 from .Thread import * # noqa: F401 F403 from .User import * # noqa: F401 F403 From 984079a3faf44af8f7c523bd9e1c218e55add74a Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 13:40:29 +0100 Subject: [PATCH 19/47] refactor: move interaction endpoint into file --- interactions/api/http/Interaction.py | 297 ++++++++++++++++++++++++++ interactions/api/http/Interaction.pyi | 57 +++++ interactions/api/http/__init__.py | 1 + 3 files changed, 355 insertions(+) create mode 100644 interactions/api/http/Interaction.py create mode 100644 interactions/api/http/Interaction.pyi diff --git a/interactions/api/http/Interaction.py b/interactions/api/http/Interaction.py new file mode 100644 index 000000000..298c8af71 --- /dev/null +++ b/interactions/api/http/Interaction.py @@ -0,0 +1,297 @@ +from typing import List, Optional, Union + +from ...api.cache import Cache +from ..models import Snowflake +from .Request import Request +from .Route import Route + + +class HTTPInteraction: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def get_application_commands( + self, application_id: Union[int, Snowflake], guild_id: Optional[int] = None + ) -> List[dict]: + """ + Get all application commands from an application. + + :param application_id: Application ID snowflake + :param guild_id: Guild to get commands from, if specified. Defaults to global (None) + :return: A list of Application commands. + """ + application_id = int(application_id) + + if guild_id in (None, "None"): + return await self._req.request(Route("GET", f"/applications/{application_id}/commands")) + else: + return await self._req.request( + Route("GET", f"/applications/{application_id}/guilds/{guild_id}/commands") + ) + + async def create_application_command( + self, application_id: Union[int, Snowflake], data: dict, guild_id: Optional[int] = None + ) -> dict: + """ + Registers to the Discord API an application command. + + :param application_id: Application ID snowflake + :param data: The dictionary that contains the command (name, description, etc) + :param guild_id: Guild ID snowflake to put them in, if applicable. + :return: An application command object. + """ + + application_id = int(application_id) + + url = ( + f"/applications/{application_id}/commands" + if guild_id in (None, "None") + else f"/applications/{application_id}/guilds/{guild_id}/commands" + ) + + return await self._req.request(Route("POST", url), json=data) + + async def overwrite_application_command( + self, application_id: int, data: List[dict], guild_id: Optional[int] = None + ) -> List[dict]: + """ + Overwrites application command(s) from a scope to the new, updated commands. + + ..note: + This applies to all forms of application commands (slash and context menus) + + :param application_id: Application ID snowflake + :param data: The dictionary that contains the command (name, description, etc) + :param guild_id: Guild ID snowflake to put them in, if applicable. + :return: An array of application command objects. + """ + url = ( + f"/applications/{application_id}/commands" + if not guild_id + else f"/applications/{application_id}/guilds/{guild_id}/commands" + ) + + return await self._req.request(Route("PUT", url), json=data) + + async def edit_application_command( + self, + application_id: Union[int, Snowflake], + data: dict, + command_id: Union[int, Snowflake], + guild_id: Optional[int] = None, + ) -> dict: + """ + Edits an application command. + + :param application_id: Application ID snowflake. + :param data: A dictionary containing updated attributes + :param command_id: The application command ID snowflake + :param guild_id: Guild ID snowflake, if given. Defaults to None/global. + :return: The updated application command object. + """ + application_id, command_id = int(application_id), int(command_id) + r = ( + Route( + "PATCH", + "/applications/{application_id}/commands/{command_id}", + application_id=application_id, + command_id=command_id, + ) + if guild_id in (None, "None") + else Route( + "PATCH", + "/applications/{application_id}/guilds/{guild_id}/commands/{command_id}", + application_id=application_id, + command_id=command_id, + guild_id=guild_id, + ) + ) + return await self._req.request(r, json=data) + + async def delete_application_command( + self, application_id: Union[int, Snowflake], command_id: int, guild_id: Optional[int] = None + ) -> None: + """ + Deletes an application command. + + :param application_id: Application ID snowflake. + :param command_id: Application command ID snowflake. + :param guild_id: Guild ID snowflake, if declared. Defaults to None (Global). + """ + + application_id = int(application_id) + + r = ( + Route( + "DELETE", + "/applications/{application_id}/guilds/{guild_id}/commands/{command_id}", + application_id=application_id, + command_id=command_id, + guild_id=guild_id, + ) + if guild_id not in (None, "None") + else Route( + "DELETE", + "/applications/{application_id}/commands/{command_id}", + application_id=application_id, + command_id=command_id, + ) + ) + return await self._req.request(r) + + async def edit_application_command_permissions( + self, application_id: int, guild_id: int, command_id: int, data: List[dict] + ) -> dict: + """ + Edits permissions for an application command. + + :param application_id: Application ID snowflake + :param guild_id: Guild ID snowflake + :param command_id: Application command ID snowflake + :param data: Permission data. + :return: Returns an updated Application Guild permission object. + """ + + return await self._req.request( + Route( + "PUT", + f"/applications/{application_id}/guilds/{guild_id}/commands/{command_id}/permissions", + ), + json=data, + ) + + async def batch_edit_application_command_permissions( + self, application_id: int, guild_id: int, data: List[dict] + ) -> List[dict]: + """ + Edits permissions for all Application Commands in a guild. + + :param application_id: Application ID snowflake + :param guild_id: Guild ID snowflake + :param data: An array of permission dictionaries. + :return: An updated array of application array permissions. + """ + return await self._req.request( + Route("PUT", f"/applications/{application_id}/guilds/{guild_id}/commands/permissions"), + json=data, + ) + + async def get_application_command_permissions( + self, application_id: int, guild_id: int, command_id: int + ) -> dict: + """ + Gets, from the Discord API, permissions from a specific Guild application command. + + :param application_id: Application ID snowflake + :param guild_id: Guild ID snowflake + :param command_id: Application Command ID snowflake + :return: a Guild Application Command permissions object + """ + return await self._req.request( + Route( + "GET", + f"/applications/{application_id}/guilds/{guild_id}/commands/{command_id}/permissions", + ) + ) + + async def get_all_application_command_permissions( + self, application_id: int, guild_id: int + ) -> List[dict]: + """ + Gets, from the Discord API, permissions from all Application commands at that Guild. + + :param application_id: Application ID snowflake + :param guild_id: Guild ID snowflake + :return: An array of Guild Application Command permissions + """ + return await self._req.request( + Route("GET", f"/applications/{application_id}/guilds/{guild_id}/commands/permissions") + ) + + async def create_interaction_response( + self, token: str, application_id: int, data: dict + ) -> None: + """ + Posts initial response to an interaction, but you need to add the token. + + :param token: Token. + :param application_id: Application ID snowflake + :param data: The data to send. + """ + return await self._req.request( + Route("POST", f"/interactions/{application_id}/{token}/callback"), json=data + ) + + # This is still Interactions, but this also applies to webhooks + # i.e. overlay + async def get_original_interaction_response( + self, token: str, application_id: str, message_id: int = "@original" + ) -> dict: + """ + Gets an existing interaction message. + + :param token: token + :param application_id: Application ID snowflake. + :param message_id: Message ID snowflake. Defaults to `@original` which represents the initial response msg. + :return: Message data. + """ + # ^ again, I don't know if python will let me + return await self._req.request( + Route("GET", f"/webhooks/{application_id}/{token}/messages/{message_id}") + ) + + async def edit_interaction_response( + self, data: dict, token: str, application_id: str, message_id: str = "@original" + ) -> dict: + """ + Edits an existing interaction message, but token needs to be manually called. + + :param data: A dictionary containing the new response. + :param token: the token of the interaction + :param application_id: Application ID snowflake. + :param message_id: Message ID snowflake. Defaults to `@original` which represents the initial response msg. + :return: Updated message data. + """ + # ^ again, I don't know if python will let me + return await self._req.request( + Route("PATCH", f"/webhooks/{application_id}/{token}/messages/{message_id}"), + json=data, + ) + + async def delete_interaction_response( + self, token: str, application_id: str, message_id: int = "original" + ) -> None: + """ + Deletes an existing interaction message. + + :param token: the token of the interaction + :param application_id: Application ID snowflake. + :param message_id: Message ID snowflake. Defaults to `@original` which represents the initial response msg. + """ + + # This is, basically, a helper method for the thing, + # because interactions are webhooks + + return await self._req.request( + Route("DELETE", f"/webhooks/{int(application_id)}/{token}/messages/{message_id}") + ) + + async def _post_followup(self, data: dict, token: str, application_id: str) -> dict: + """ + Send a followup to an interaction. + + :param data: the payload to send + :param application_id: the id of the application + :param token: the token of the interaction + """ + + return await self._req.request( + Route("POST", f"/webhooks/{application_id}/{token}"), json=data + ) diff --git a/interactions/api/http/Interaction.pyi b/interactions/api/http/Interaction.pyi new file mode 100644 index 000000000..7620a74cd --- /dev/null +++ b/interactions/api/http/Interaction.pyi @@ -0,0 +1,57 @@ +from typing import List, Optional, Union + +from ..models import Snowflake +from ...api.cache import Cache +from .Request import Request + + +class HTTPInteraction: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def get_application_commands( + self, application_id: Union[int, Snowflake], guild_id: Optional[int] = None + ) -> List[dict]: ... + async def create_application_command( + self, application_id: Union[int, Snowflake], data: dict, guild_id: Optional[int] = None + ) -> dict: ... + async def overwrite_application_command( + self, application_id: int, data: List[dict], guild_id: Optional[int] = None + ) -> List[dict]: ... + async def edit_application_command( + self, + application_id: Union[int, Snowflake], + data: dict, + command_id: Union[int, Snowflake], + guild_id: Optional[int] = None, + ) -> dict: ... + async def delete_application_command( + self, application_id: Union[int, Snowflake], command_id: int, guild_id: Optional[int] = None + ) -> None: ... + async def edit_application_command_permissions( + self, application_id: int, guild_id: int, command_id: int, data: List[dict] + ) -> dict: ... + async def batch_edit_application_command_permissions( + self, application_id: int, guild_id: int, data: List[dict] + ) -> List[dict]: ... + async def get_application_command_permissions( + self, application_id: int, guild_id: int, command_id: int + ) -> dict: ... + async def get_all_application_command_permissions( + self, application_id: int, guild_id: int + ) -> List[dict]: ... + async def create_interaction_response( + self, token: str, application_id: int, data: dict + ) -> None: ... + async def get_original_interaction_response( + self, token: str, application_id: str, message_id: int = "@original" + ) -> dict: ... + async def edit_interaction_response( + self, data: dict, token: str, application_id: str, message_id: str = "@original" + ) -> dict: ... + async def delete_interaction_response( + self, token: str, application_id: str, message_id: int = "original" + ) -> None: ... + async def _post_followup(self, data: dict, token: str, application_id: str) -> dict: ... diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index eabf9b935..3289e64bd 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -7,6 +7,7 @@ from .Channel import * # noqa: F401 F403 from .Guild import * # noqa: F401 F403 from .HTTPClient import * # noqa: F401 F403 +from .Interaction import * # noqa: F401 F403 from .Limiter import * # noqa: F401 F403 from .Member import * # noqa: F401 F403 from .Message import * # noqa: F401 F403 From 4e68598d43c1d928861264cff6d88bcd66b242c5 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 13:57:15 +0100 Subject: [PATCH 20/47] refactor: move webhook endpoint into file --- interactions/api/http/Webhook.py | 230 ++++++++++++++++++++++++++++++ interactions/api/http/Webhook.pyi | 49 +++++++ interactions/api/http/__init__.py | 1 + 3 files changed, 280 insertions(+) create mode 100644 interactions/api/http/Webhook.py create mode 100644 interactions/api/http/Webhook.pyi diff --git a/interactions/api/http/Webhook.py b/interactions/api/http/Webhook.py new file mode 100644 index 000000000..68af02350 --- /dev/null +++ b/interactions/api/http/Webhook.py @@ -0,0 +1,230 @@ +from typing import Any, List, Optional + +from ...api.cache import Cache +from .Request import Request +from .Route import Route + + +class HTTPWebhook: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + # TODO: Not sure why, but there's no webhook models? Will rectify later. + # Also, todo: figure out what avatar is + + async def create_webhook(self, channel_id: int, name: str, avatar: Any = None) -> dict: + """ + Create a new webhook. + + :param channel_id: Channel ID snowflake. + :param name: Name of the webhook (1-80 characters) + :param avatar: The image for the default webhook avatar, if given. + + :return Webhook object + """ + return await self._req.request( + Route("POST", f"/channels/{channel_id}/webhooks"), json={"name": name, "avatar": avatar} + ) + + async def get_channel_webhooks(self, channel_id: int) -> List[dict]: + """ + Return a list of channel webhook objects. + + :param channel_id: Channel ID snowflake. + :return:List of webhook objects + """ + return await self._req.request(Route("GET", f"/channels/{channel_id}/webhooks")) + + async def get_guild_webhooks(self, guild_id: int) -> List[dict]: + """ + Return a list of guild webhook objects. + + :param guild_id: Guild ID snowflake + + :return: List of webhook objects + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/webhooks")) + + async def get_webhook(self, webhook_id: int, webhook_token: str = None) -> dict: + """ + Return the new webhook object for the given id. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: Webhook Token, if given. + + :return:Webhook object + """ + endpoint = f"/webhooks/{webhook_id}{f'/{webhook_token}' if webhook_token else ''}" + + return await self._req.request(Route("GET", endpoint)) + + async def modify_webhook( + self, + webhook_id: int, + name: str, + avatar: Any, + channel_id: int, + webhook_token: str = None, + ) -> dict: + """ + Modify a webhook. + + :param webhook_id: Webhook ID snowflake + :param name: the default name of the webhook + :param avatar: image for the default webhook avatar + :param channel_id: Channel ID snowflake of new destination + :param webhook_token: The token for the webhook, if given. + + :return: Modified webhook object. + """ + endpoint = f"/webhooks/{webhook_id}{f'/{webhook_token}' if webhook_token else ''}" + + return await self._req.request( + Route("PATCH", endpoint), + json={"name": name, "avatar": avatar, "channel_id": channel_id}, + ) + + async def delete_webhook(self, webhook_id: int, webhook_token: str = None): + """ + Delete a webhook. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: The token for the webhook, if given. + """ + + endpoint = f"/webhooks/{webhook_id}{f'/{webhook_token}' if webhook_token else ''}" + + return await self._req.request(Route("DELETE", endpoint)) + + async def execute_webhook( + self, + webhook_id: int, + webhook_token: str, + payload: dict, + wait: bool = False, + thread_id: Optional[int] = None, + ) -> Optional[dict]: + """ + Sends a message as a webhook. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: The token for the webhook. + :param payload: Payload consisting of the message. + :param wait: A bool that signifies waiting for server confirmation of a send before responding. + :param thread_id: Optional, sends a message to the specified thread. + :return: The message sent, if wait=True, else None. + """ + + return await self._req.request( + Route("POST", f"/webhooks/{webhook_id}/{webhook_token}"), + params={"wait": wait, "thread_id": thread_id}, + json=payload, + ) + + async def execute_slack_webhook( + self, webhook_id: int, webhook_token: str, payload: dict + ) -> None: + """ + Sends a message to a Slack-compatible webhook. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: The token for the webhook. + :param payload: Payload consisting of the message. + + :return: ? + + .. note:: + Payload structure is different than Discord's. See `here _` for more details. + """ + + return await self._req.request( + Route("POST", f"/webhooks/{webhook_id}/{webhook_token}/slack"), json=payload + ) + + async def execute_github_webhook( + self, webhook_id: int, webhook_token: str, payload: dict + ) -> None: + """ + Sends a message to a Github-compatible webhook. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: The token for the webhook. + :param payload: Payload consisting of the message. + + :return: ? + + .. note:: + Payload structure is different than Discord's. See `here _` for more details. + """ + + return await self._req.request( + Route("POST", f"/webhooks/{webhook_id}/{webhook_token}/slack"), json=payload + ) + + async def get_webhook_message( + self, webhook_id: int, webhook_token: str, message_id: int + ) -> dict: + """ + Retrieves a message sent from a Webhook. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: Webhook token. + :param message_id: Message ID snowflake, + :return: A Message object. + """ + + return await self._req.request( + Route("GET", f"/webhooks/{webhook_id}/{webhook_token}/messages/{message_id}") + ) + + async def edit_webhook_message( + self, webhook_id: int, webhook_token: str, message_id: int, data: dict + ) -> dict: + """ + Edits a message sent from a Webhook. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: Webhook token. + :param message_id: Message ID snowflake. + :param data: A payload consisting of new message attributes. + :return: An updated message object. + """ + + return await self._req.request( + Route("PATCH", f"/webhooks/{webhook_id}/{webhook_token}/messages/{message_id}"), + json=data, + ) + + async def delete_webhook_message( + self, webhook_id: int, webhook_token: str, message_id: int + ) -> None: + """ + Deletes a message object. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: Webhook token. + :param message_id: Message ID snowflake. + """ + + return await self._req.request( + Route("DELETE", f"/webhooks/{webhook_id}/{webhook_token}/messages/{message_id}") + ) + + async def delete_original_webhook_message(self, webhook_id: int, webhook_token: str) -> None: + """ + Deletes the original message object sent. + + :param webhook_id: Webhook ID snowflake. + :param webhook_token: Webhook token. + """ + + return await self._req.request( + Route("DELETE", f"/webhooks/{webhook_id}/{webhook_token}/messages/@original") + ) diff --git a/interactions/api/http/Webhook.pyi b/interactions/api/http/Webhook.pyi new file mode 100644 index 000000000..298e28e12 --- /dev/null +++ b/interactions/api/http/Webhook.pyi @@ -0,0 +1,49 @@ +from typing import Any, List, Optional + +from ...api.cache import Cache +from .Request import Request + + +class HTTPWebhook: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def create_webhook(self, channel_id: int, name: str, avatar: Any = None) -> dict: ... + async def get_channel_webhooks(self, channel_id: int) -> List[dict]: ... + async def get_guild_webhooks(self, guild_id: int) -> List[dict]: ... + async def get_webhook(self, webhook_id: int, webhook_token: str = None) -> dict: ... + async def modify_webhook( + self, + webhook_id: int, + name: str, + avatar: Any, + channel_id: int, + webhook_token: str = None, + ) -> dict: ... + async def delete_webhook(self, webhook_id: int, webhook_token: str = None): ... + async def execute_webhook( + self, + webhook_id: int, + webhook_token: str, + payload: dict, + wait: bool = False, + thread_id: Optional[int] = None, + ) -> Optional[dict]: ... + async def execute_slack_webhook( + self, webhook_id: int, webhook_token: str, payload: dict + ) -> None: ... + async def execute_github_webhook( + self, webhook_id: int, webhook_token: str, payload: dict + ) -> None: ... + async def get_webhook_message( + self, webhook_id: int, webhook_token: str, message_id: int + ) -> dict: ... + async def edit_webhook_message( + self, webhook_id: int, webhook_token: str, message_id: int, data: dict + ) -> dict: ... + async def delete_webhook_message( + self, webhook_id: int, webhook_token: str, message_id: int + ) -> None: ... + async def delete_original_webhook_message(self, webhook_id: int, webhook_token: str) -> None: ... diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index 3289e64bd..cea120b2f 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -17,3 +17,4 @@ from .Sticker import * # noqa: F401 F403 from .Thread import * # noqa: F401 F403 from .User import * # noqa: F401 F403 +from .Webhook import * # noqa: F401 F403 From 8b820285416ff7434e75fc35edd3bb738e0ce98d Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 14:01:06 +0100 Subject: [PATCH 21/47] refactor: move emoji endpoint into file --- interactions/api/http/Emoji.py | 81 +++++++++++++++++++++++++++++++ interactions/api/http/Emoji.pyi | 23 +++++++++ interactions/api/http/__init__.py | 1 + 3 files changed, 105 insertions(+) create mode 100644 interactions/api/http/Emoji.py create mode 100644 interactions/api/http/Emoji.pyi diff --git a/interactions/api/http/Emoji.py b/interactions/api/http/Emoji.py new file mode 100644 index 000000000..443982e85 --- /dev/null +++ b/interactions/api/http/Emoji.py @@ -0,0 +1,81 @@ +from typing import List, Optional + +from ...api.cache import Cache +from .Request import Request +from .Route import Route + + +class HTTPEmoji: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def get_all_emoji(self, guild_id: int) -> List[dict]: + """ + Gets all emojis from a guild. + + :param guild_id: Guild ID snowflake. + :return: A list of emojis. + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/emojis")) + + async def get_guild_emoji(self, guild_id: int, emoji_id: int) -> dict: + """ + Gets an emote from a guild. + + :param guild_id: Guild ID snowflake. + :param emoji_id: Emoji ID snowflake. + :return: Emoji object + """ + return await self._req.request(Route("GET", f"/guilds/{guild_id}/emojis/{emoji_id}")) + + async def create_guild_emoji( + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Creates an emoji. + + :param guild_id: Guild ID snowflake. + :param payload: Emoji parameters. + :param reason: Optionally, give a reason. + :return: An emoji object with the included parameters. + """ + return await self._req.request( + Route("POST", f"/guilds/{guild_id}/emojis"), json=payload, reason=reason + ) + + async def modify_guild_emoji( + self, guild_id: int, emoji_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: + """ + Modifies an emoji. + + :param guild_id: Guild ID snowflake. + :param emoji_id: Emoji ID snowflake + :param payload: Emoji parameters with updated attributes + :param reason: Optionally, give a reason. + :return: An emoji object with updated attributes. + """ + return await self._req.request( + Route("PATCH", f"/guilds/{guild_id}/emojis/{emoji_id}"), json=payload, reason=reason + ) + + async def delete_guild_emoji( + self, guild_id: int, emoji_id: int, reason: Optional[str] = None + ) -> None: + """ + Deletes an emoji. + + :param guild_id: Guild ID snowflake. + :param emoji_id: Emoji ID snowflake + :param reason: Optionally, give a reason. + """ + await self._req.request( + Route("DELETE", f"/guilds/{guild_id}/emojis/{emoji_id}"), reason=reason + ) diff --git a/interactions/api/http/Emoji.pyi b/interactions/api/http/Emoji.pyi new file mode 100644 index 000000000..e05f7de4d --- /dev/null +++ b/interactions/api/http/Emoji.pyi @@ -0,0 +1,23 @@ +from typing import List, Optional + +from .Request import Request +from ...api.cache import Cache + + +class HTTPEmoji: + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def get_all_emoji(self, guild_id: int) -> List[dict]: ... + async def get_guild_emoji(self, guild_id: int, emoji_id: int) -> dict: ... + async def create_guild_emoji( + self, guild_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... + async def modify_guild_emoji( + self, guild_id: int, emoji_id: int, payload: dict, reason: Optional[str] = None + ) -> dict: ... + async def delete_guild_emoji( + self, guild_id: int, emoji_id: int, reason: Optional[str] = None + ) -> None: ... diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index cea120b2f..c911d0e02 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -5,6 +5,7 @@ """ from .Channel import * # noqa: F401 F403 +from .Emoji import * # noqa: F401 F403 from .Guild import * # noqa: F401 F403 from .HTTPClient import * # noqa: F401 F403 from .Interaction import * # noqa: F401 F403 From 1e514872a339516023eb8781cc8deda924ec7454 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 14:15:22 +0100 Subject: [PATCH 22/47] refactor: move emoji endpoint into file --- interactions/api/http/ScheduledEvent.py | 181 +++++++++++++++++++++++ interactions/api/http/ScheduledEvent.pyi | 36 +++++ interactions/api/http/__init__.py | 1 + 3 files changed, 218 insertions(+) create mode 100644 interactions/api/http/ScheduledEvent.py create mode 100644 interactions/api/http/ScheduledEvent.pyi diff --git a/interactions/api/http/ScheduledEvent.py b/interactions/api/http/ScheduledEvent.py new file mode 100644 index 000000000..89119943e --- /dev/null +++ b/interactions/api/http/ScheduledEvent.py @@ -0,0 +1,181 @@ +from typing import List + +from ...api.cache import Cache +from ..models import Snowflake +from .Request import Request +from .Route import Route + + +class HTTPScheduledEvent: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: + self._req = _req + self.cache = cache + + async def create_scheduled_event(self, guild_id: Snowflake, payload: dict) -> dict: + """ + Creates a scheduled event. + + :param guild_id: Guild ID snowflake. + :param payload: The dictionary containing the parameters and values to edit the associated event. + :return A dictionary containing the new guild scheduled event object on success. + """ + guild_id = int(guild_id) + valid_keys = ( + "channel_id", + "name", + "privacy_level", + "scheduled_start_time", + "scheduled_end_time", + "entity_metadata", + "description", + "entity_type", + ) + data = {k: v for k, v in payload.items() if k in valid_keys} + + return await self._req.request( + Route("POST", "/guilds/{guild_id}/scheduled-events", guild_id=int(guild_id)), + json=data, + ) + + async def get_scheduled_event( + self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, with_user_count: bool + ) -> dict: + """ + Gets a guild scheduled event. + + :param guild_id: Guild ID snowflake. + :param guild_scheduled_event_id: Guild Scheduled Event ID snowflake. + :param with_user_count: A boolean to include number of users subscribed to the associated event, if given. + :return A dictionary containing the guild scheduled event object on success. + """ + guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) + params = {} + if with_user_count: + params["with_user_count"] = with_user_count + + return await self._req.request( + Route( + "GET", + "/guilds/{guild_id}/scheduled-events/{event_id}", + guild_id=guild_id, + event_id=event_id, + ), + params=params, + ) + + async def get_scheduled_events(self, guild_id: Snowflake, with_user_count: bool) -> List[dict]: + """ + Gets all guild scheduled events in a guild. + + :param guild_id: Guild ID snowflake. + :param with_user_count: A boolean to include number of users subscribed to the associated event, if given. + :return A List of a dictionary containing the guild scheduled event objects on success. + """ + guild_id = int(guild_id) + params = {} + if with_user_count: + params["with_user_count"] = with_user_count + + return await self._req.request( + Route("GET", "/guilds/{guild_id}/scheduled-events", guild_id=guild_id), params=params + ) + + async def modify_scheduled_event( + self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, payload: dict + ) -> dict: + """ + Modifies a scheduled event. + + :param guild_id: Guild ID snowflake. + :param guild_scheduled_event_id: Guild Scheduled Event ID snowflake. + :param payload: The dictionary containing the parameters and values to edit the associated event. + :return A dictionary containing the updated guild scheduled event object on success. + """ + guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) + valid_keys = ( + "channel_id", + "name", + "privacy_level", + "scheduled_start_time", + "scheduled_end_time", + "entity_metadata", + "description", + "entity_type", + ) + data = {k: v for k, v in payload.items() if k in valid_keys} + return await self._req.request( + Route( + "PATCH", + "/guilds/{guild_id}/scheduled-events/{event_id}", + guild_id=guild_id, + event_id=event_id, + ), + json=data, + ) + + async def delete_scheduled_event( + self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake + ) -> None: + """ + Deletes a guild scheduled event. + + :param guild_id: Guild ID snowflake. + :param guild_scheduled_event_id: Guild Scheduled Event ID snowflake. + :return Nothing on success. + """ + guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) + + return await self._req.request( + Route( + "DELETE", + "/guilds/{guild_id}/scheduled-events/{event_id}", + guild_id=guild_id, + event_id=event_id, + ) + ) + + async def get_scheduled_event_users( + self, + guild_id: Snowflake, + guild_scheduled_event_id: Snowflake, + limit: int = 100, + with_member: bool = False, + before: Snowflake = None, + after: Snowflake = None, + ) -> dict: + """ + Get the registered users of a scheduled event. + + :param guild_id: Guild ID snowflake. + :param guild_scheduled_event_id: Guild Scheduled Event snowflake. + :param limit: Limit of how many users to pull from the event. Defaults to 100. + :param with_member: Include guild member data if it exists. Defaults to False. + :param before: Considers only users before given user ID snowflake. Defaults to None. + :param after: Considers only users after given user ID snowflake. Defaults to None. + :return: Returns a list of guild scheduled event user objects on success. + """ + guild_id, event_id = int(guild_id), int(guild_scheduled_event_id) + params = { + "limit": limit, + "with_member": with_member, + } + if before: + params["before"] = int(before) + if after: + params["after"] = int(after) + + return await self._req.request( + Route( + "GET", + "/guilds/{guild_id}/scheduled-events/{event_id}/users", + guild_id=guild_id, + event_id=event_id, + ), + params=params, + ) diff --git a/interactions/api/http/ScheduledEvent.pyi b/interactions/api/http/ScheduledEvent.pyi new file mode 100644 index 000000000..e744241ca --- /dev/null +++ b/interactions/api/http/ScheduledEvent.pyi @@ -0,0 +1,36 @@ +from typing import List + + +from ...api.cache import Cache +from ..models import Snowflake +from .Request import Request + + +class HTTPScheduledEvent: + + __slots__ = ("_req", "cache") + + _req: Request + cache: Cache + + def __init__(self, _req, cache) -> None: ... + async def create_scheduled_event(self, guild_id: Snowflake, payload: dict) -> dict: ... + async def get_scheduled_event( + self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, with_user_count: bool + ) -> dict: ... + async def get_scheduled_events(self, guild_id: Snowflake, with_user_count: bool) -> List[dict]: ... + async def modify_scheduled_event( + self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, payload: dict + ) -> dict: ... + async def delete_scheduled_event( + self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake + ) -> None: ... + async def get_scheduled_event_users( + self, + guild_id: Snowflake, + guild_scheduled_event_id: Snowflake, + limit: int = 100, + with_member: bool = False, + before: Snowflake = None, + after: Snowflake = None, + ) -> dict: ... diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index c911d0e02..c343232c5 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -15,6 +15,7 @@ from .Reaction import * # noqa: F401 F403 from .Request import * # noqa: F401 F403 from .Route import * # noqa: F401 F403 +from .ScheduledEvent import * # noqa: F401 F403 from .Sticker import * # noqa: F401 F403 from .Thread import * # noqa: F401 F403 from .User import * # noqa: F401 F403 From cd433cf8c629c07674981504b9a31d981c26bba8 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 17:53:58 +0100 Subject: [PATCH 23/47] refactor: requested changes --- interactions/api/http/__init__.py | 30 +++++++++---------- .../api/http/{Channel.py => channel.py} | 8 ++--- .../api/http/{Channel.pyi => channel.pyi} | 8 ++--- interactions/api/http/{Emoji.py => emoji.py} | 8 ++--- .../api/http/{Emoji.pyi => emoji.pyi} | 6 ++-- interactions/api/http/{Guild.py => guild.py} | 8 ++--- .../api/http/{Guild.pyi => guild.pyi} | 8 ++--- .../http/{Interaction.py => interaction.py} | 8 ++--- .../http/{Interaction.pyi => interaction.pyi} | 6 ++-- .../api/http/{Limiter.py => limiter.py} | 0 .../api/http/{Limiter.pyi => limiter.pyi} | 0 .../api/http/{Member.py => member.py} | 8 ++--- .../api/http/{Member.pyi => member.pyi} | 8 ++--- .../api/http/{Message.py => message.py} | 8 ++--- .../api/http/{Message.pyi => message.pyi} | 6 ++-- .../api/http/{Reaction.py => reaction.py} | 8 ++--- .../api/http/{Reaction.pyi => reaction.pyi} | 6 ++-- .../api/http/{Request.py => request.py} | 6 ++-- .../api/http/{Request.pyi => request.pyi} | 6 ++-- interactions/api/http/{Route.py => route.py} | 0 .../api/http/{Route.pyi => route.pyi} | 0 .../{ScheduledEvent.py => scheduledEvent.py} | 8 ++--- ...{ScheduledEvent.pyi => scheduledEvent.pyi} | 6 ++-- .../api/http/{Sticker.py => sticker.py} | 8 ++--- .../api/http/{Sticker.pyi => sticker.pyi} | 6 ++-- .../api/http/{Thread.py => thread.py} | 8 ++--- .../api/http/{Thread.pyi => thread.pyi} | 6 ++-- interactions/api/http/{User.py => user.py} | 8 ++--- interactions/api/http/{User.pyi => user.pyi} | 6 ++-- .../api/http/{Webhook.py => webhook.py} | 8 ++--- .../api/http/{Webhook.pyi => webhook.pyi} | 6 ++-- 31 files changed, 107 insertions(+), 109 deletions(-) rename interactions/api/http/{Channel.py => channel.py} (99%) rename interactions/api/http/{Channel.pyi => channel.pyi} (95%) rename interactions/api/http/{Emoji.py => emoji.py} (96%) rename interactions/api/http/{Emoji.pyi => emoji.pyi} (90%) rename interactions/api/http/{Guild.py => guild.py} (99%) rename interactions/api/http/{Guild.pyi => guild.pyi} (97%) rename interactions/api/http/{Interaction.py => interaction.py} (99%) rename interactions/api/http/{Interaction.pyi => interaction.pyi} (96%) rename interactions/api/http/{Limiter.py => limiter.py} (100%) rename interactions/api/http/{Limiter.pyi => limiter.pyi} (100%) rename interactions/api/http/{Member.py => member.py} (97%) rename interactions/api/http/{Member.pyi => member.pyi} (90%) rename interactions/api/http/{Message.py => message.py} (98%) rename interactions/api/http/{Message.pyi => message.pyi} (95%) rename interactions/api/http/{Reaction.py => reaction.py} (97%) rename interactions/api/http/{Reaction.pyi => reaction.pyi} (91%) rename interactions/api/http/{Request.py => request.py} (99%) rename interactions/api/http/{Request.pyi => request.pyi} (89%) rename interactions/api/http/{Route.py => route.py} (100%) rename interactions/api/http/{Route.pyi => route.pyi} (100%) rename interactions/api/http/{ScheduledEvent.py => scheduledEvent.py} (98%) rename interactions/api/http/{ScheduledEvent.pyi => scheduledEvent.pyi} (93%) rename interactions/api/http/{Sticker.py => sticker.py} (97%) rename interactions/api/http/{Sticker.pyi => sticker.pyi} (92%) rename interactions/api/http/{Thread.py => thread.py} (98%) rename interactions/api/http/{Thread.pyi => thread.pyi} (95%) rename interactions/api/http/{User.py => user.py} (96%) rename interactions/api/http/{User.pyi => user.pyi} (87%) rename interactions/api/http/{Webhook.py => webhook.py} (98%) rename interactions/api/http/{Webhook.pyi => webhook.pyi} (95%) diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index c343232c5..1e8e7063b 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -4,19 +4,19 @@ Handles all HTTP-Requests of the library. """ -from .Channel import * # noqa: F401 F403 -from .Emoji import * # noqa: F401 F403 -from .Guild import * # noqa: F401 F403 +from .channel import * # noqa: F401 F403 +from .emoji import * # noqa: F401 F403 +from .guild import * # noqa: F401 F403 from .HTTPClient import * # noqa: F401 F403 -from .Interaction import * # noqa: F401 F403 -from .Limiter import * # noqa: F401 F403 -from .Member import * # noqa: F401 F403 -from .Message import * # noqa: F401 F403 -from .Reaction import * # noqa: F401 F403 -from .Request import * # noqa: F401 F403 -from .Route import * # noqa: F401 F403 -from .ScheduledEvent import * # noqa: F401 F403 -from .Sticker import * # noqa: F401 F403 -from .Thread import * # noqa: F401 F403 -from .User import * # noqa: F401 F403 -from .Webhook import * # noqa: F401 F403 +from .interaction import * # noqa: F401 F403 +from .limiter import * # noqa: F401 F403 +from .member import * # noqa: F401 F403 +from .message import * # noqa: F401 F403 +from .reaction import * # noqa: F401 F403 +from .request import * # noqa: F401 F403 +from .route import * # noqa: F401 F403 +from .scheduledEvent import * # noqa: F401 F403 +from .sticker import * # noqa: F401 F403 +from .thread import * # noqa: F401 F403 +from .user import * # noqa: F401 F403 +from .webhook import * # noqa: F401 F403 diff --git a/interactions/api/http/Channel.py b/interactions/api/http/channel.py similarity index 99% rename from interactions/api/http/Channel.py rename to interactions/api/http/channel.py index 8e188516a..c00f883ba 100644 --- a/interactions/api/http/Channel.py +++ b/interactions/api/http/channel.py @@ -3,15 +3,15 @@ from ...api.cache import Cache, Item from ..models.channel import Channel from ..models.message import Message -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPChannel: +class _ChannelRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Channel.pyi b/interactions/api/http/channel.pyi similarity index 95% rename from interactions/api/http/Channel.pyi rename to interactions/api/http/channel.pyi index 061ac5902..cb2a19b97 100644 --- a/interactions/api/http/Channel.pyi +++ b/interactions/api/http/channel.pyi @@ -1,12 +1,12 @@ -from typing import Dict, List, Optional, Union +from typing import List, Optional from ...api.cache import Cache -from .Request import Request +from .request import _Request -class HTTPChannel: +class _ChannelRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Emoji.py b/interactions/api/http/emoji.py similarity index 96% rename from interactions/api/http/Emoji.py rename to interactions/api/http/emoji.py index 443982e85..375b00855 100644 --- a/interactions/api/http/Emoji.py +++ b/interactions/api/http/emoji.py @@ -1,15 +1,15 @@ from typing import List, Optional from ...api.cache import Cache -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPEmoji: +class _EmojiRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Emoji.pyi b/interactions/api/http/emoji.pyi similarity index 90% rename from interactions/api/http/Emoji.pyi rename to interactions/api/http/emoji.pyi index e05f7de4d..ca8a2fabb 100644 --- a/interactions/api/http/Emoji.pyi +++ b/interactions/api/http/emoji.pyi @@ -1,12 +1,12 @@ from typing import List, Optional -from .Request import Request +from .request import _Request from ...api.cache import Cache -class HTTPEmoji: +class _EmojiRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Guild.py b/interactions/api/http/guild.py similarity index 99% rename from interactions/api/http/Guild.py rename to interactions/api/http/guild.py index 38eb85f2e..4d1ad52e0 100644 --- a/interactions/api/http/Guild.py +++ b/interactions/api/http/guild.py @@ -6,15 +6,15 @@ from ..models.guild import Guild from ..models.member import Member from ..models.role import Role -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPGuild: +class _GuildRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Guild.pyi b/interactions/api/http/guild.pyi similarity index 97% rename from interactions/api/http/Guild.pyi rename to interactions/api/http/guild.pyi index e359d722d..ed1680138 100644 --- a/interactions/api/http/Guild.pyi +++ b/interactions/api/http/guild.pyi @@ -1,12 +1,12 @@ -from typing import List, Optional, Dict, Any +from typing import List, Optional from ...api.cache import Cache from ..models.role import Role -from .Request import Request +from .request import _Request -class HTTPGuild: +class _GuildRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Interaction.py b/interactions/api/http/interaction.py similarity index 99% rename from interactions/api/http/Interaction.py rename to interactions/api/http/interaction.py index 298c8af71..0ebaeba47 100644 --- a/interactions/api/http/Interaction.py +++ b/interactions/api/http/interaction.py @@ -2,15 +2,15 @@ from ...api.cache import Cache from ..models import Snowflake -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPInteraction: +class _InteractionRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Interaction.pyi b/interactions/api/http/interaction.pyi similarity index 96% rename from interactions/api/http/Interaction.pyi rename to interactions/api/http/interaction.pyi index 7620a74cd..23652d07a 100644 --- a/interactions/api/http/Interaction.pyi +++ b/interactions/api/http/interaction.pyi @@ -2,12 +2,12 @@ from typing import List, Optional, Union from ..models import Snowflake from ...api.cache import Cache -from .Request import Request +from .request import _Request -class HTTPInteraction: +class _InteractionRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Limiter.py b/interactions/api/http/limiter.py similarity index 100% rename from interactions/api/http/Limiter.py rename to interactions/api/http/limiter.py diff --git a/interactions/api/http/Limiter.pyi b/interactions/api/http/limiter.pyi similarity index 100% rename from interactions/api/http/Limiter.pyi rename to interactions/api/http/limiter.pyi diff --git a/interactions/api/http/Member.py b/interactions/api/http/member.py similarity index 97% rename from interactions/api/http/Member.py rename to interactions/api/http/member.py index 31b4ee841..876d4c9f8 100644 --- a/interactions/api/http/Member.py +++ b/interactions/api/http/member.py @@ -1,15 +1,15 @@ from typing import List, Optional from ...api.cache import Cache -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPMember: +class _MemberRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Member.pyi b/interactions/api/http/member.pyi similarity index 90% rename from interactions/api/http/Member.pyi rename to interactions/api/http/member.pyi index 5ef545fae..8236a2dce 100644 --- a/interactions/api/http/Member.pyi +++ b/interactions/api/http/member.pyi @@ -1,15 +1,13 @@ from typing import List, Optional from ...api.cache import Cache -from .Request import Request -from .Route import Route +from .request import _Request - -class HTTPMember: +class _MemberRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Message.py b/interactions/api/http/message.py similarity index 98% rename from interactions/api/http/Message.py rename to interactions/api/http/message.py index c76291306..0b063a9c2 100644 --- a/interactions/api/http/Message.py +++ b/interactions/api/http/message.py @@ -3,15 +3,15 @@ from ...api.cache import Cache, Item from ..models.message import Embed, Message from ..models.misc import Snowflake -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPMessage: +class _MessageRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Message.pyi b/interactions/api/http/message.pyi similarity index 95% rename from interactions/api/http/Message.pyi rename to interactions/api/http/message.pyi index f3db06787..efd6eb3f9 100644 --- a/interactions/api/http/Message.pyi +++ b/interactions/api/http/message.pyi @@ -3,12 +3,12 @@ from typing import List, Optional, Union from ...api.cache import Cache from ..models.message import Embed, Message from ..models.misc import Snowflake -from .Request import Request +from .request import _Request -class HTTPMessage: +class _MessageRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Reaction.py b/interactions/api/http/reaction.py similarity index 97% rename from interactions/api/http/Reaction.py rename to interactions/api/http/reaction.py index 85f6df99d..b9d0fce83 100644 --- a/interactions/api/http/Reaction.py +++ b/interactions/api/http/reaction.py @@ -1,15 +1,15 @@ from typing import List from ...api.cache import Cache -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPReaction: +class _ReactionRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Reaction.pyi b/interactions/api/http/reaction.pyi similarity index 91% rename from interactions/api/http/Reaction.pyi rename to interactions/api/http/reaction.pyi index a5a33731a..dfedb16d8 100644 --- a/interactions/api/http/Reaction.pyi +++ b/interactions/api/http/reaction.pyi @@ -1,12 +1,12 @@ from typing import List from ...api.cache import Cache -from .Request import Request +from .request import _Request -class HTTPReaction: +class _ReactionRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Request.py b/interactions/api/http/request.py similarity index 99% rename from interactions/api/http/Request.py rename to interactions/api/http/request.py index f563b37c1..7ee26d2d0 100644 --- a/interactions/api/http/Request.py +++ b/interactions/api/http/request.py @@ -13,14 +13,14 @@ from interactions.base import __version__, get_logger from ...api.error import HTTPException -from .Limiter import Limiter -from .Route import Route +from .limiter import Limiter +from .route import Route log: Logger = get_logger("http") _session: ClientSession = ClientSession() -class Request: +class _Request: """ A class representing how HTTP requests are sent/read. diff --git a/interactions/api/http/Request.pyi b/interactions/api/http/request.pyi similarity index 89% rename from interactions/api/http/Request.pyi rename to interactions/api/http/request.pyi index 8eca0551c..91e70ee77 100644 --- a/interactions/api/http/Request.pyi +++ b/interactions/api/http/request.pyi @@ -2,10 +2,10 @@ from asyncio import AbstractEventLoop from typing import Any, Dict, Optional from aiohttp import ClientSession from aiohttp import __version__ as http_version -from .Limiter import Limiter -from .Route import Route +from .limiter import Limiter +from .route import Route -class Request: +class _Request: token: str _loop: AbstractEventLoop diff --git a/interactions/api/http/Route.py b/interactions/api/http/route.py similarity index 100% rename from interactions/api/http/Route.py rename to interactions/api/http/route.py diff --git a/interactions/api/http/Route.pyi b/interactions/api/http/route.pyi similarity index 100% rename from interactions/api/http/Route.pyi rename to interactions/api/http/route.pyi diff --git a/interactions/api/http/ScheduledEvent.py b/interactions/api/http/scheduledEvent.py similarity index 98% rename from interactions/api/http/ScheduledEvent.py rename to interactions/api/http/scheduledEvent.py index 89119943e..82a2dcd95 100644 --- a/interactions/api/http/ScheduledEvent.py +++ b/interactions/api/http/scheduledEvent.py @@ -2,15 +2,15 @@ from ...api.cache import Cache from ..models import Snowflake -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPScheduledEvent: +class _ScheduledEventRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/ScheduledEvent.pyi b/interactions/api/http/scheduledEvent.pyi similarity index 93% rename from interactions/api/http/ScheduledEvent.pyi rename to interactions/api/http/scheduledEvent.pyi index e744241ca..c056ea67a 100644 --- a/interactions/api/http/ScheduledEvent.pyi +++ b/interactions/api/http/scheduledEvent.pyi @@ -3,14 +3,14 @@ from typing import List from ...api.cache import Cache from ..models import Snowflake -from .Request import Request +from .request import _Request -class HTTPScheduledEvent: +class _ScheduledEventRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Sticker.py b/interactions/api/http/sticker.py similarity index 97% rename from interactions/api/http/Sticker.py rename to interactions/api/http/sticker.py index ed6045e28..77fbe16d3 100644 --- a/interactions/api/http/Sticker.py +++ b/interactions/api/http/sticker.py @@ -3,15 +3,15 @@ from aiohttp import FormData from ...api.cache import Cache -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPSticker: +class _StickerRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Sticker.pyi b/interactions/api/http/sticker.pyi similarity index 92% rename from interactions/api/http/Sticker.pyi rename to interactions/api/http/sticker.pyi index d86f0439b..f456bc642 100644 --- a/interactions/api/http/Sticker.pyi +++ b/interactions/api/http/sticker.pyi @@ -3,12 +3,12 @@ from typing import List, Optional from aiohttp import FormData from ...api.cache import Cache -from .Request import Request +from .request import _Request -class HTTPSticker: +class _StickerRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Thread.py b/interactions/api/http/thread.py similarity index 98% rename from interactions/api/http/Thread.py rename to interactions/api/http/thread.py index ac395e399..913dfc220 100644 --- a/interactions/api/http/Thread.py +++ b/interactions/api/http/thread.py @@ -1,15 +1,15 @@ from typing import List, Optional from ...api.cache import Cache, Item -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPThread: +class _ThreadRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Thread.pyi b/interactions/api/http/thread.pyi similarity index 95% rename from interactions/api/http/Thread.pyi rename to interactions/api/http/thread.pyi index a08050259..15d6e49e5 100644 --- a/interactions/api/http/Thread.pyi +++ b/interactions/api/http/thread.pyi @@ -1,11 +1,11 @@ from typing import List, Optional from ...api.cache import Cache -from .Request import Request +from .request import _Request -class HTTPThread: +class _ThreadRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/User.py b/interactions/api/http/user.py similarity index 96% rename from interactions/api/http/User.py rename to interactions/api/http/user.py index 8351134d3..baa94dc56 100644 --- a/interactions/api/http/User.py +++ b/interactions/api/http/user.py @@ -3,15 +3,15 @@ from ...api.cache import Cache, Item from ..models.channel import Channel from ..models.user import User -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPUser: +class _UserRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/User.pyi b/interactions/api/http/user.pyi similarity index 87% rename from interactions/api/http/User.pyi rename to interactions/api/http/user.pyi index d22e8063c..aeaab172c 100644 --- a/interactions/api/http/User.pyi +++ b/interactions/api/http/user.pyi @@ -1,11 +1,11 @@ from typing import Optional from ...api.cache import Cache -from .Request import Request +from .request import _Request -class HTTPUser: +class _UserRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... diff --git a/interactions/api/http/Webhook.py b/interactions/api/http/webhook.py similarity index 98% rename from interactions/api/http/Webhook.py rename to interactions/api/http/webhook.py index 68af02350..929601128 100644 --- a/interactions/api/http/Webhook.py +++ b/interactions/api/http/webhook.py @@ -1,15 +1,15 @@ from typing import Any, List, Optional from ...api.cache import Cache -from .Request import Request -from .Route import Route +from .request import _Request +from .route import Route -class HTTPWebhook: +class _WebhookRequest: __slots__ = ("_req", "cache") - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: diff --git a/interactions/api/http/Webhook.pyi b/interactions/api/http/webhook.pyi similarity index 95% rename from interactions/api/http/Webhook.pyi rename to interactions/api/http/webhook.pyi index 298e28e12..9a1a6dbc5 100644 --- a/interactions/api/http/Webhook.pyi +++ b/interactions/api/http/webhook.pyi @@ -1,12 +1,12 @@ from typing import Any, List, Optional from ...api.cache import Cache -from .Request import Request +from .request import _Request -class HTTPWebhook: +class _WebhookRequest: - _req: Request + _req: _Request cache: Cache def __init__(self, _req, cache) -> None: ... From 4c8a03c19e433cbc12efc870d456606c88ccfb48 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 20:17:12 +0100 Subject: [PATCH 24/47] refactor: reflect breaking changes to all files --- interactions/api/models/channel.py | 46 ++++++++++++------------ interactions/api/models/guild.py | 58 +++++++++++++++--------------- interactions/api/models/member.py | 22 ++++++------ interactions/api/models/message.py | 24 +++++++------ interactions/api/models/role.py | 6 ++-- interactions/client.py | 16 +++++---- interactions/context.py | 48 ++++++++++++------------- interactions/context.pyi | 4 +-- 8 files changed, 117 insertions(+), 107 deletions(-) diff --git a/interactions/api/models/channel.py b/interactions/api/models/channel.py index 02ca3ce22..2aca16d4f 100644 --- a/interactions/api/models/channel.py +++ b/interactions/api/models/channel.py @@ -259,7 +259,9 @@ async def send( components=_components, ) - res = await self._client.create_message(channel_id=int(self.id), payload=payload._json) + res = await self._client.message.create_message( + channel_id=int(self.id), payload=payload._json + ) return Message(**res, _client=self._client) async def delete(self) -> None: @@ -268,7 +270,7 @@ async def delete(self) -> None: """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.delete_channel(channel_id=int(self.id)) + await self._client.channel.delete_channel(channel_id=int(self.id)) async def modify( self, @@ -332,7 +334,7 @@ async def modify( parent_id=_parent_id, nsfw=_nsfw, ) - res = await self._client.modify_channel( + res = await self._client.channel.modify_channel( channel_id=int(self.id), reason=reason, payload=payload._json, @@ -513,7 +515,7 @@ async def add_member( raise TypeError( "The Channel you specified is not a thread!" ) # TODO: Move to new error formatter. - await self._client.add_member_to_thread(thread_id=int(self.id), user_id=member_id) + await self._client.thread.add_member_to_thread(thread_id=int(self.id), user_id=member_id) async def pin_message( self, @@ -528,7 +530,7 @@ async def pin_message( if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.pin_message(channel_id=int(self.id), message_id=message_id) + await self._client.message.pin_message(channel_id=int(self.id), message_id=message_id) async def unpin_message( self, @@ -543,7 +545,7 @@ async def unpin_message( if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.unpin_message(channel_id=int(self.id), message_id=message_id) + await self._client.message.unpin_message(channel_id=int(self.id), message_id=message_id) async def publish_message( self, @@ -560,7 +562,7 @@ async def publish_message( raise AttributeError("HTTPClient not found!") from .message import Message - res = await self._client.publish_message( + res = await self._client.message.publish_message( channel_id=int(self.id), message_id=int(message_id) ) return Message(**res, _client=self._client) @@ -576,7 +578,7 @@ async def get_pinned_messages(self) -> List["Message"]: # noqa raise AttributeError("HTTPClient not found!") from .message import Message - res = await self._client.get_pinned_messages(int(self.id)) + res = await self._client.channel.get_pinned_messages(int(self.id)) return [Message(**message, _client=self._client) for message in res] async def get_message( @@ -589,7 +591,7 @@ async def get_message( :return: The message as object :rtype: Message """ - res = await self._client.get_message( + res = await self._client.channel.get_message( channel_id=int(self.id), message_id=message_id, ) @@ -637,7 +639,7 @@ def check_pinned(message): messages = [ Message(**res) - for res in await self._client.get_channel_messages( + for res in await self._client.channel.get_channel_messages( channel_id=int(self.id), limit=100, before=_before, @@ -662,13 +664,13 @@ def check_pinned(message): _before = int(message.id) _all += messages if len(messages) > 1: - await self._client.delete_messages( + await self._client.message.delete_messages( channel_id=int(self.id), message_ids=[int(message.id) for message in messages], reason=reason, ) elif len(messages) == 1: - await self._client.delete_message( + await self._client.message.delete_message( channel_id=int(self.id), message_id=int(messages[0].id), reason=reason, @@ -685,7 +687,7 @@ def check_pinned(message): while amount > 1: messages = [ Message(**res) - for res in await self._client.get_channel_messages( + for res in await self._client.channel.get_channel_messages( channel_id=int(self.id), limit=amount, before=_before, @@ -711,13 +713,13 @@ def check_pinned(message): _before = int(message.id) _all += messages if len(messages) > 1: - await self._client.delete_messages( + await self._client.message.delete_messages( channel_id=int(self.id), message_ids=[int(message.id) for message in messages], reason=reason, ) elif len(messages) == 1: - await self._client.delete_message( + await self._client.message.delete_message( channel_id=int(self.id), message_id=int(messages[0].id), reason=reason, @@ -731,7 +733,7 @@ def check_pinned(message): while amount == 1: messages = [ Message(**res) - for res in await self._client.get_channel_messages( + for res in await self._client.channel.get_channel_messages( channel_id=int(self.id), limit=amount, before=_before, @@ -753,7 +755,7 @@ def check_pinned(message): _all += messages if not messages: continue - await self._client.delete_message( + await self._client.message.delete_message( channel_id=int(self.id), message_id=int(messages[0].id), reason=reason, @@ -763,7 +765,7 @@ def check_pinned(message): while amount > 0: messages = [ Message(**res) - for res in await self._client.get_channel_messages( + for res in await self._client.channel.get_channel_messages( channel_id=int(self.id), limit=min(amount, 100), before=_before, @@ -786,7 +788,7 @@ def check_pinned(message): _all += messages for message in _all: - await self._client.delete_message( + await self._client.message.delete_message( channel_id=int(self.id), message_id=int(message.id), reason=reason, @@ -834,7 +836,7 @@ async def create_thread( _auto_archive_duration = None if auto_archive_duration is MISSING else auto_archive_duration _invitable = None if invitable is MISSING else invitable _message_id = None if message_id is MISSING else message_id - res = await self._client.create_thread( + res = await self._client.thread.create_thread( channel_id=int(self.id), thread_type=type.value, name=name, @@ -863,7 +865,7 @@ async def get( channel_id = channel if isinstance(channel, int) else int(channel.split(sep="/")[-1]) - res = await client.get_channel(channel_id) + res = await client.channel.get_channel(channel_id) return cls(**res, _client=client) @property @@ -939,7 +941,7 @@ async def create_invite( ) payload["target_application_id"] = target_application_id - res = await self._client.create_channel_invite( + res = await self._client.channel.create_channel_invite( channel_id=int(self.id), payload=payload, reason=reason, diff --git a/interactions/api/models/guild.py b/interactions/api/models/guild.py index 5ae3d7ea2..5ba8b70a1 100644 --- a/interactions/api/models/guild.py +++ b/interactions/api/models/guild.py @@ -346,7 +346,7 @@ async def ban( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.create_guild_ban( + await self._client.guild.create_guild_ban( guild_id=int(self.id), user_id=member_id, reason=reason, @@ -368,7 +368,7 @@ async def remove_ban( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.remove_guild_ban( + await self._client.guild.remove_guild_ban( guild_id=int(self.id), user_id=user_id, reason=reason, @@ -389,7 +389,7 @@ async def kick( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.create_guild_kick( + await self._client.guild.create_guild_kick( guild_id=int(self.id), user_id=member_id, reason=reason, @@ -414,14 +414,14 @@ async def add_member_role( if not self._client: raise AttributeError("HTTPClient not found!") if isinstance(role, Role): - await self._client.add_member_role( + await self._client.member.add_member_role( guild_id=int(self.id), user_id=member_id, role_id=int(role.id), reason=reason, ) else: - await self._client.add_member_role( + await self._client.member.add_member_role( guild_id=int(self.id), user_id=member_id, role_id=role, @@ -447,14 +447,14 @@ async def remove_member_role( if not self._client: raise AttributeError("HTTPClient not found!") if isinstance(role, Role): - await self._client.remove_member_role( + await self._client.member.remove_member_role( guild_id=int(self.id), user_id=member_id, role_id=int(role.id), reason=reason, ) else: - await self._client.remove_member_role( + await self._client.member.remove_member_role( guild_id=int(self.id), user_id=member_id, role_id=role, @@ -496,7 +496,7 @@ async def create_role( hoist=hoist, mentionable=mentionable, ) - res = await self._client.create_guild_role( + res = await self._client.guild.create_guild_role( guild_id=int(self.id), reason=reason, payload=payload._json, @@ -517,7 +517,7 @@ async def get_member( """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.get_member( + res = await self._client.member.get_member( guild_id=int(self.id), member_id=member_id, ) @@ -535,7 +535,7 @@ async def delete_channel( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.delete_channel(channel_id=channel_id) + await self._client.channel.delete_channel(channel_id=channel_id) async def delete_role( self, @@ -552,7 +552,7 @@ async def delete_role( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.delete_guild_role( + await self._client.guild.delete_guild_role( guild_id=int(self.id), role_id=role_id, reason=reason, @@ -590,7 +590,7 @@ async def modify_role( """ if not self._client: raise AttributeError("HTTPClient not found!") - roles = await self._client.get_all_roles(guild_id=int(self.id)) + roles = await self._client.guild.get_all_roles(guild_id=int(self.id)) for i in roles: if int(i["id"]) == role_id: role = Role(**i) @@ -602,7 +602,7 @@ async def modify_role( payload = Role(name=_name, color=_color, hoist=_hoist, mentionable=_mentionable) - res = await self._client.modify_guild_role( + res = await self._client.guild.modify_guild_role( guild_id=int(self.id), role_id=role_id, payload=payload._json, @@ -653,7 +653,7 @@ async def create_thread( _auto_archive_duration = None if auto_archive_duration is MISSING else auto_archive_duration _invitable = None if invitable is MISSING else invitable _message_id = None if message_id is MISSING else message_id - res = await self._client.create_thread( + res = await self._client.thread.create_thread( channel_id=int(self.id), thread_type=type.value, name=name, @@ -743,7 +743,7 @@ async def create_channel( if nsfw is not MISSING: payload["nsfw"] = nsfw - res = await self._client.create_channel( + res = await self._client.channel.create_channel( guild_id=int(self.id), reason=reason, payload=payload, @@ -793,7 +793,7 @@ async def modify_channel( """ if not self._client: raise AttributeError("HTTPClient not found!") - ch = Channel(**await self._client.get_channel(channel_id=channel_id)) + ch = Channel(**await self._client.channel.get_channel(channel_id=channel_id)) _name = ch.name if name is MISSING else name _topic = ch.topic if topic is MISSING else topic @@ -819,7 +819,7 @@ async def modify_channel( nsfw=_nsfw, ) - res = await self._client.modify_channel( + res = await self._client.channel.modify_channel( channel_id=channel_id, reason=reason, payload=payload._json, @@ -880,7 +880,7 @@ async def modify_member( if communication_disabled_until is not MISSING: payload["communication_disabled_until"] = communication_disabled_until - res = await self._client.modify_member( + res = await self._client.member.modify_member( user_id=member_id, guild_id=int(self.id), payload=payload, @@ -900,13 +900,13 @@ async def get_preview(self) -> "GuildPreview": if not self._client: raise AttributeError("HTTPClient not found!") - return GuildPreview(**await self._client.get_guild_preview(guild_id=int(self.id))) + return GuildPreview(**await self._client.guild.get_guild_preview(guild_id=int(self.id))) async def leave(self) -> None: """Removes the bot from the guild.""" if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.leave_guild(guild_id=int(self.id)) + await self._client.guild.leave_guild(guild_id=int(self.id)) async def modify( self, @@ -1035,7 +1035,7 @@ async def modify( if premium_progress_bar_enabled is not MISSING: payload["premium_progress_bar_enabled"] = premium_progress_bar_enabled - res = await self._client.modify_guild( + res = await self._client.guild.modify_guild( guild_id=int(self.id), payload=payload, reason=reason, @@ -1300,7 +1300,7 @@ async def create_scheduled_event( if description is not MISSING: payload["description"] = description - res = await self._client.create_scheduled_event( + res = await self._client.scheduled_event.create_scheduled_event( guild_id=self.id, payload=payload, ) @@ -1373,7 +1373,7 @@ async def modify_scheduled_event( if status is not MISSING: payload["status"] = status - res = await self._client.modify_scheduled_event( + res = await self._client.scheduled_event.modify_scheduled_event( guild_id=self.id, guild_scheduled_event_id=Snowflake(event_id), payload=payload, @@ -1389,7 +1389,7 @@ async def delete_scheduled_event(self, event_id: int) -> None: """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.delete_scheduled_event( + await self._client.scheduled_event.delete_scheduled_event( guild_id=self.id, guild_scheduled_event_id=Snowflake(event_id), ) @@ -1403,7 +1403,7 @@ async def get_all_channels(self) -> List[Channel]: """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.get_all_channels(int(self.id)) + res = await self._client.guild.get_all_channels(int(self.id)) return [Channel(**channel, _client=self._client) for channel in res] async def get_all_roles(self) -> List[Role]: @@ -1415,7 +1415,7 @@ async def get_all_roles(self) -> List[Role]: """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.get_all_roles(int(self.id)) + res = await self._client.guild.get_all_roles(int(self.id)) return [Role(**role, _client=self._client) for role in res] async def get_role( @@ -1433,7 +1433,7 @@ async def get_role( if not self._client: raise AttributeError("HTTPClient not found!") - roles = await self._client.get_all_roles(guild_id=int(self.id)) + roles = await self._client.guild.get_all_roles(guild_id=int(self.id)) for i in roles: if int(i["id"]) == role_id: role = Role(**i) @@ -1461,7 +1461,7 @@ async def modify_role_position( if not self._client: raise AttributeError("HTTPClient not found!") _role_id = role_id.id if isinstance(role_id, Role) else role_id - res = await self._client.modify_guild_role_position( + res = await self._client.guild.modify_guild_role_position( guild_id=int(self.id), position=position, role_id=_role_id, reason=reason ) return [Role(**role, _client=self._client) for role in res] @@ -1475,7 +1475,7 @@ async def get_bans(self) -> List[dict]: """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.get_guild_bans(int(self.id)) + res = await self._client.guild.get_guild_bans(int(self.id)) for ban in res: ban["user"] = User(**ban["user"]) return res diff --git a/interactions/api/models/member.py b/interactions/api/models/member.py index d03054b6a..6cf4de8b0 100644 --- a/interactions/api/models/member.py +++ b/interactions/api/models/member.py @@ -117,7 +117,7 @@ async def ban( :param delete_message_days?: Number of days to delete messages, from 0 to 7. Defaults to 0 :type delete_message_days: Optional[int] """ - await self._client.create_guild_ban( + await self._client.guild.create_guild_ban( guild_id=guild_id, user_id=int(self.user.id), reason=reason, @@ -139,7 +139,7 @@ async def kick( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.create_guild_kick( + await self._client.guild.create_guild_kick( guild_id=guild_id, user_id=int(self.user.id), reason=reason, @@ -164,14 +164,14 @@ async def add_role( if not self._client: raise AttributeError("HTTPClient not found!") if isinstance(role, Role): - await self._client.add_member_role( + await self._client.member.add_member_role( guild_id=guild_id, user_id=int(self.user.id), role_id=int(role.id), reason=reason, ) else: - await self._client.add_member_role( + await self._client.member.add_member_role( guild_id=guild_id, user_id=int(self.user.id), role_id=role, @@ -197,14 +197,14 @@ async def remove_role( if not self._client: raise AttributeError("HTTPClient not found!") if isinstance(role, Role): - await self._client.remove_member_role( + await self._client.member.remove_member_role( guild_id=guild_id, user_id=int(self.user.id), role_id=int(role.id), reason=reason, ) else: - await self._client.remove_member_role( + await self._client.member.remove_member_role( guild_id=guild_id, user_id=int(self.user.id), role_id=role, @@ -278,8 +278,10 @@ async def send( allowed_mentions=_allowed_mentions, ) - channel = Channel(**await self._client.create_dm(recipient_id=int(self.user.id))) - res = await self._client.create_message(channel_id=int(channel.id), payload=payload._json) + channel = Channel(**await self._client.user.create_dm(recipient_id=int(self.user.id))) + res = await self._client.message.create_message( + channel_id=int(channel.id), payload=payload._json + ) return Message(**res, _client=self._client) @@ -337,7 +339,7 @@ async def modify( if communication_disabled_until is not MISSING: payload["communication_disabled_until"] = communication_disabled_until - res = await self._client.modify_member( + res = await self._client.member.modify_member( user_id=int(self.user.id), guild_id=guild_id, payload=payload, @@ -357,7 +359,7 @@ async def add_to_thread( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.add_member_to_thread( + await self._client.thread.add_member_to_thread( user_id=int(self.user.id), thread_id=thread_id, ) diff --git a/interactions/api/models/message.py b/interactions/api/models/message.py index 2cdba00a4..9ef65d7de 100644 --- a/interactions/api/models/message.py +++ b/interactions/api/models/message.py @@ -307,7 +307,7 @@ async def get_channel(self) -> Channel: """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.get_channel(channel_id=int(self.channel_id)) + res = await self._client.channel.get_channel(channel_id=int(self.channel_id)) return Channel(**res, _client=self._client) async def get_guild(self): @@ -320,7 +320,7 @@ async def get_guild(self): raise AttributeError("HTTPClient not found!") from .guild import Guild - res = await self._client.get_guild(guild_id=int(self.guild_id)) + res = await self._client.guild.get_guild(guild_id=int(self.guild_id)) return Guild(**res, _client=self._client) async def delete(self, reason: Optional[str] = None) -> None: @@ -332,7 +332,7 @@ async def delete(self, reason: Optional[str] = None) -> None: """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.delete_message( + await self._client.message.delete_message( message_id=int(self.id), channel_id=int(self.channel_id), reason=reason ) @@ -409,7 +409,7 @@ async def edit( components=_components, ) - _dct = await self._client.edit_message( + _dct = await self._client.message.edit_message( channel_id=int(self.channel_id), message_id=int(self.id), payload=payload._json, @@ -486,7 +486,7 @@ async def reply( components=_components, ) - res = await self._client.create_message( + res = await self._client.message.create_message( channel_id=int(self.channel_id), payload=payload._json ) return Message(**res, _client=self._client) @@ -495,13 +495,17 @@ async def pin(self) -> None: """Pins the message to its channel""" if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.pin_message(channel_id=int(self.channel_id), message_id=int(self.id)) + await self._client.message.pin_message( + channel_id=int(self.channel_id), message_id=int(self.id) + ) async def unpin(self) -> None: """Unpins the message from its channel""" if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.unpin_message(channel_id=int(self.channel_id), message_id=int(self.id)) + await self._client.message.unpin_message( + channel_id=int(self.channel_id), message_id=int(self.id) + ) async def publish(self) -> "Message": """Publishes (API calls it crossposts) the message in its channel to any that is followed by. @@ -511,7 +515,7 @@ async def publish(self) -> "Message": """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.publish_message( + res = await self._client.message.publish_message( channel_id=int(self.channel_id), message_id=int(self.id) ) return Message(**res, _client=self._client) @@ -542,7 +546,7 @@ async def create_thread( raise AttributeError("HTTPClient not found!") _auto_archive_duration = None if auto_archive_duration is MISSING else auto_archive_duration _invitable = None if invitable is MISSING else invitable - res = await self._client.create_thread( + res = await self._client.thread.create_thread( channel_id=int(self.channel_id), message_id=int(self.id), name=name, @@ -568,7 +572,7 @@ async def get_from_url(cls, url: str, client: "HTTPClient") -> "Message": # noq if "channels/" not in url: raise ValueError("You provided an invalid URL!") # TODO: custom error formatter _, _channel_id, _message_id = url.split("channels/")[1].split("/") - _message = await client.get_message( + _message = await client.message.get_message( channel_id=_channel_id, message_id=_message_id, ) diff --git a/interactions/api/models/role.py b/interactions/api/models/role.py index 682da5309..03dd5d35e 100644 --- a/interactions/api/models/role.py +++ b/interactions/api/models/role.py @@ -88,7 +88,7 @@ async def delete( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.delete_guild_role( + await self._client.guild.delete_guild_role( guild_id=guild_id, role_id=int(self.id), reason=reason ), @@ -131,7 +131,7 @@ async def modify( payload = Role(name=_name, color=_color, hoist=_hoist, mentionable=_mentionable) - res = await self._client.modify_guild_role( + res = await self._client.guild.modify_guild_role( guild_id=guild_id, role_id=int(self.id), payload=payload._json, @@ -159,7 +159,7 @@ async def modify_position( """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.modify_guild_role_position( + res = await self._client.guild.modify_guild_role_position( guild_id=guild_id, position=position, role_id=int(self.id), reason=reason ) return [Role(**role, _client=self._client) for role in res] diff --git a/interactions/client.py b/interactions/client.py index b77c15618..b6192c25e 100644 --- a/interactions/client.py +++ b/interactions/client.py @@ -151,7 +151,7 @@ async def __create_sync(self, data: dict) -> None: command: ApplicationCommand = ApplicationCommand( **( - await self._http.create_application_command( + await self._http.interaction.create_application_command( application_id=self.me.id, data=data, guild_id=data.get("guild_id") ) ) @@ -192,7 +192,7 @@ async def __bulk_update_sync(self, data: List[dict], delete: Optional[bool] = Fa log.info( f"Guild commands {', '.join(command['name'] for command in commands)} under ID {guild} have been {'deleted' if delete else 'synced'}." ) - await self._http.overwrite_application_command( + await self._http.interaction.overwrite_application_command( application_id=self.me.id, data=[] if delete else commands, guild_id=guild, @@ -202,7 +202,7 @@ async def __bulk_update_sync(self, data: List[dict], delete: Optional[bool] = Fa log.info( f"Global commands {', '.join(command['name'] for command in global_commands)} have been {'deleted' if delete else 'synced'}." ) - await self._http.overwrite_application_command( + await self._http.interaction.overwrite_application_command( application_id=self.me.id, data=[] if delete else global_commands ) @@ -220,7 +220,9 @@ async def _synchronize(self, payload: Optional[dict] = None) -> None: commands: List[dict] = cache else: log.info("No command cache was found present, retrieving from Web API instead.") - commands: Optional[Union[dict, List[dict]]] = await self._http.get_application_commands( + commands: Optional[ + Union[dict, List[dict]] + ] = await self._http.interaction.get_application_commands( application_id=self.me.id, guild_id=payload.get("guild_id") if payload else None ) @@ -831,7 +833,7 @@ async def autocomplete_choice_list(ctx, user_input: str = ""): if not _command_obj or not _command_obj.id: if getattr(_command_obj, "guild_id", None) or self._automate_sync: _application_commands = self._loop.run_until_complete( - self._http.get_application_commands( + self._http.interaction.get_application_commands( application_id=self.me.id, guild_id=None if not hasattr(_command_obj, "guild_id") @@ -842,7 +844,7 @@ async def autocomplete_choice_list(ctx, user_input: str = ""): else: for _scope in self._scopes: _application_commands = self._loop.run_until_complete( - self._http.get_application_commands( + self._http.interaction.get_application_commands( application_id=self.me.id, guild_id=_scope ) ) @@ -1189,7 +1191,7 @@ def teardown(self): if self.client._automate_sync: [ self.client._loop.create_task( - self.client._http.delete_application_command( + self.client._http.interaction.delete_application_command( cmd["application_id"], cmd["id"], cmd["guild_id"] ) ) diff --git a/interactions/context.py b/interactions/context.py index 9884d21a6..7c39ef680 100644 --- a/interactions/context.py +++ b/interactions/context.py @@ -102,7 +102,7 @@ async def get_channel(self) -> Channel: :rtype: Channel """ - res = await self.client.get_channel(int(self.channel_id)) + res = await self.client.channel.get_channel(int(self.channel_id)) self.channel = Channel(**res, _client=self.client) return self.channel @@ -114,7 +114,7 @@ async def get_guild(self) -> Guild: :rtype: Guild """ - res = await self.client.get_guild(int(self.guild_id)) + res = await self.client.guild.get_guild(int(self.guild_id)) self.guild = Guild(**res, _client=self.client) return self.guild @@ -295,7 +295,7 @@ async def popup(self, modal: Modal) -> None: }, } - await self.client.create_interaction_response( + await self.client.interaction.create_interaction_response( token=self.token, application_id=int(self.id), data=payload, @@ -317,7 +317,7 @@ class CommandContext(_Context): this as a value, but instead ``guild_id``. You will need to manually fetch for this data for the time being. - You can fetch with ``client.get_guild(guild_id)`` which + You can fetch with ``client.guild.get_guild(guild_id)`` which will return a JSON dictionary, which you can then use ``interactions.Guild(**data)`` for an object or continue with a dictionary for your own purposes. @@ -385,12 +385,12 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: if self.deferred: if hasattr(self.message, "id") and self.message.id is not None: - res = await self.client.edit_message( + res = await self.client.message.edit_message( int(self.channel_id), int(self.message.id), payload=payload._json ) self.message = msg = Message(**res, _client=self.client) else: - res = await self.client.edit_interaction_response( + res = await self.client.interaction.edit_interaction_response( token=self.token, application_id=str(self.id), data={"type": self.callback.value, "data": payload._json}, @@ -401,12 +401,12 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: self.message = payload self.message._client = self.client else: - await self.client.edit_message( + await self.client.message.edit_message( int(self.channel_id), res["id"], payload=payload._json ) self.message = msg = Message(**res, _client=self.client) else: - res = await self.client.edit_interaction_response( + res = await self.client.interaction.edit_interaction_response( token=self.token, application_id=str(self.application_id), data={"type": self.callback.value, "data": payload._json}, @@ -414,7 +414,7 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: if res["flags"] == 64: log.warning("You can't edit hidden messages.") else: - await self.client.edit_message( + await self.client.message.edit_message( int(self.channel_id), res["id"], payload=payload._json ) self.message = msg = Message(**res, _client=self.client) @@ -435,7 +435,7 @@ async def defer(self, ephemeral: Optional[bool] = False) -> None: _ephemeral: int = (1 << 6) if ephemeral else 0 self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE - await self.client.create_interaction_response( + await self.client.interaction.create_interaction_response( token=self.token, application_id=int(self.id), data={"type": self.callback.value, "data": {"flags": _ephemeral}}, @@ -452,14 +452,14 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: msg = None if self.responded or self.deferred: if self.deferred: - res = await self.client.edit_interaction_response( + res = await self.client.interaction.edit_interaction_response( data=payload._json, token=self.token, application_id=str(self.application_id), ) self.responded = True else: - res = await self.client._post_followup( + res = await self.client.interaction._post_followup( data=payload._json, token=self.token, application_id=str(self.application_id), @@ -471,7 +471,7 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: application_id=int(self.id), data=_payload, ) - __newdata = await self.client.edit_interaction_response( + __newdata = await self.client.interaction.edit_interaction_response( data={}, token=self.token, application_id=str(self.application_id), @@ -495,11 +495,11 @@ async def delete(self) -> None: being present. """ if self.responded: - await self.client.delete_webhook_message( + await self.client.webhook.delete_webhook_message( webhook_id=int(self.id), webhook_token=self.token, message_id=int(self.message.id) ) else: - await self.client.delete_original_webhook_message(int(self.id), self.token) + await self.client.webhook.delete_original_webhook_message(int(self.id), self.token) self.message = None async def populate(self, choices: Union[Choice, List[Choice]]) -> List[Choice]: @@ -534,7 +534,7 @@ async def func(): 6, message="Autocomplete choice items must be of type Choice" ) - await self.client.create_interaction_response( + await self.client.interaction.create_interaction_response( token=self.token, application_id=int(self.id), data={ @@ -590,7 +590,7 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: if not self.deferred: self.callback = InteractionCallbackType.UPDATE_MESSAGE - await self.client.create_interaction_response( + await self.client.interaction.create_interaction_response( data={"type": self.callback.value, "data": payload._json}, token=self.token, application_id=int(self.id), @@ -598,13 +598,13 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: self.message = payload self.responded = True elif self.callback != InteractionCallbackType.DEFERRED_UPDATE_MESSAGE: - await self.client._post_followup( + await self.client.interaction._post_followup( data=payload._json, token=self.token, application_id=str(self.application_id), ) else: - res = await self.client.edit_interaction_response( + res = await self.client.interaction.edit_interaction_response( data=payload._json, token=self.token, application_id=str(self.application_id), @@ -632,14 +632,14 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: or self.callback == InteractionCallbackType.DEFERRED_UPDATE_MESSAGE ): if self.deferred: - res = await self.client.edit_interaction_response( + res = await self.client.interaction.edit_interaction_response( data=payload._json, token=self.token, application_id=str(self.application_id), ) self.responded = True else: - res = await self.client._post_followup( + res = await self.client.interaction._post_followup( data=payload._json, token=self.token, application_id=str(self.application_id), @@ -647,12 +647,12 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: self.message = msg = Message(**res, _client=self.client) else: - await self.client.create_interaction_response( + await self.client.interaction.create_interaction_response( token=self.token, application_id=int(self.id), data=_payload, ) - __newdata = await self.client.edit_interaction_response( + __newdata = await self.client.interaction.edit_interaction_response( data={}, token=self.token, application_id=str(self.application_id), @@ -688,7 +688,7 @@ async def defer( else: self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE - await self.client.create_interaction_response( + await self.client.interaction.create_interaction_response( token=self.token, application_id=int(self.id), data={"type": self.callback.value, "data": {"flags": _ephemeral}}, diff --git a/interactions/context.pyi b/interactions/context.pyi index d696287d8..bf7d295fc 100644 --- a/interactions/context.pyi +++ b/interactions/context.pyi @@ -1,6 +1,6 @@ -from typing import Any, List, Optional, Union +rom typing import List, Optional, Union -from .api import HTTPClient +from .api.http.HTTPClient import HTTPClient from .api.models.channel import Channel as Channel from .api.models.guild import Guild as Guild from .api.models.member import Member as Member From 200c1e6499d73df4fa7b01d2ae4fc7e333fbf25a Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 20:20:20 +0100 Subject: [PATCH 25/47] refactor: add new HTTPClient --- interactions/api/http/HTTPClient.py | 133 +++++++++++++++++++++++++++ interactions/api/http/HTTPClient.pyi | 45 +++++++++ 2 files changed, 178 insertions(+) create mode 100644 interactions/api/http/HTTPClient.py create mode 100644 interactions/api/http/HTTPClient.pyi diff --git a/interactions/api/http/HTTPClient.py b/interactions/api/http/HTTPClient.py new file mode 100644 index 000000000..23034e4be --- /dev/null +++ b/interactions/api/http/HTTPClient.py @@ -0,0 +1,133 @@ +from typing import Any, Optional, Tuple + +import interactions.api.cache + +from ...api.cache import Cache +from .channel import _ChannelRequest +from .emoji import _EmojiRequest +from .guild import _GuildRequest +from .interaction import _InteractionRequest +from .member import _MemberRequest +from .message import _MessageRequest +from .reaction import _ReactionRequest +from .request import _Request +from .route import Route +from .scheduledEvent import _ScheduledEventRequest +from .sticker import _StickerRequest +from .thread import _ThreadRequest +from .user import _UserRequest +from .webhook import _WebhookRequest + + +class HTTPClient: + """ + The user-facing client of the Web API for individual endpoints. + + :ivar str token: The token of the application. + :ivar Request _req: The requesting interface for endpoints. + :ivar Cache cache: The referenced cache. + """ + + __slots__ = ( + "token", + "_req", + "cache", + "user", + "message", + "guild", + "member", + "channel", + "thread", + "reaction", + "sticker", + "interaction", + "webhook", + "emoji", + "scheduled_event", + ) + + token: str + _req: _Request + member: _MemberRequest + cache: Cache + user: _UserRequest + message: _MessageRequest + guild: _GuildRequest + channel: _ChannelRequest + thread: _ThreadRequest + reaction: _ReactionRequest + sticker: _StickerRequest + interaction: _InteractionRequest + webhook: _WebhookRequest + emoji: _EmojiRequest + scheduled_event: _ScheduledEventRequest + + def __init__(self, token: str): + self.token = token + self._req = _Request(self.token) + self.cache = interactions.api.cache.ref_cache + self.user = _UserRequest(_req=self._req, cache=self.cache) + self.message = _MessageRequest(_req=self._req, cache=self.cache) + self.guild = _GuildRequest(_req=self._req, cache=self.cache) + self.channel = _ChannelRequest(_req=self._req, cache=self.cache) + self.thread = _ThreadRequest(_req=self._req, cache=self.cache) + self.reaction = _ReactionRequest(_req=self._req, cache=self.cache) + self.sticker = _StickerRequest(_req=self._req, cache=self.cache) + self.interaction = _InteractionRequest(_req=self._req, cache=self.cache) + self.webhook = _WebhookRequest(_req=self._req, cache=self.cache) + self.scheduled_event = _ScheduledEventRequest(_req=self._req, cache=self.cache) + self.emoji = _EmojiRequest(_req=self._req, cache=self.cache) + self.member = _MemberRequest(_req=self._req, cache=self.cache) + + # An ideology is that this client does every single HTTP call, which reduces multiple ClientSessions in theory + # because of how they are constructed/closed. This includes Gateway + + async def get_gateway(self) -> str: + """This calls the Gateway endpoint and returns a v9 gateway link with JSON encoding.""" + + url: Any = await self._req.request( + Route("GET", "/gateway") + ) # typehinting Any because pycharm yells + return f'{url["url"]}?v=10&encoding=json' + + async def get_bot_gateway(self) -> Tuple[int, str]: + """ + This calls the BOT Gateway endpoint. + + :return: A tuple denoting (shard, gateway_url), url from API v9 and JSON encoding + """ + + data: Any = await self._req.request(Route("GET", "/gateway/bot")) + return data["shards"], f'{data["url"]}?v=9&encoding=json' + + async def login(self) -> Optional[dict]: + """ + This 'logins' to the gateway, which makes it available to use any other endpoint. + """ + + return await self._req.request( + Route("GET", "/users/@me") + ) # Internally raises any Exception. + + async def logout(self) -> None: + """This 'log outs' the session.""" + + await self._req.request(Route("POST", "/auth/logout")) + + @property + def req(self) -> _Request: + return self._req + + # ---- Oauth2 endpoint + + async def get_current_bot_information(self) -> dict: + """ + Returns the bot user application object without flags. + """ + return await self._req.request(Route("GET", "/oauth2/applications/@me")) + + async def get_current_authorisation_information(self) -> dict: + """ + Returns info about the current authorization of the bot user + """ + return await self._req.request(Route("GET", "/oauth2/@me")) diff --git a/interactions/api/http/HTTPClient.pyi b/interactions/api/http/HTTPClient.pyi new file mode 100644 index 000000000..628035162 --- /dev/null +++ b/interactions/api/http/HTTPClient.pyi @@ -0,0 +1,45 @@ +from typing import Optional, Tuple + +from .request import _Request +from ...api.cache import Cache +from .user import _UserRequest +from .message import _MessageRequest +from .guild import _GuildRequest +from .channel import _ChannelRequest +from .thread import _ThreadRequest +from .sticker import _StickerRequest +from .reaction import _ReactionRequest +from .webhook import _WebhookRequest +from .emoji import _EmojiRequest +from .scheduledEvent import _ScheduledEventRequest +from .interaction import _InteractionRequest +from .member import _MemberRequest + +class HTTPClient: + token: str + _req: _Request + cache: Cache + + message: _MessageRequest + user: _UserRequest + guild: _GuildRequest + channel: _ChannelRequest + member: _MemberRequest + thread: _ThreadRequest + reaction: _ReactionRequest + sticker: _StickerRequest + interaction: _InteractionRequest + webhook: _WebhookRequest + emoji: _EmojiRequest + scheduled_event: _ScheduledEventRequest + + def __init__(self, token: str): ... + + async def get_gateway(self) -> str: ... + async def get_bot_gateway(self) -> Tuple[int, str]: ... + async def login(self) -> Optional[dict]: ... + async def logout(self) -> None: ... + @property + def req(self) -> _Request: ... + async def get_current_bot_information(self) -> dict: ... + async def get_current_authorisation_information(self) -> dict: ... From cad5049396f0994b16863124da689ca53e3ede25 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 21:57:08 +0100 Subject: [PATCH 26/47] docs: --- docs/api.http.rst | 66 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/docs/api.http.rst b/docs/api.http.rst index 31a466af1..43fc16137 100644 --- a/docs/api.http.rst +++ b/docs/api.http.rst @@ -3,6 +3,70 @@ HTTP Client =========== -.. automodule:: interactions.api.http +.. autoclass:: interactions.api.http.route.Route + :members: + :noindex: + +.. autoclass:: interactions.api.http.limiter.Limiter + :members: + :noindex: + +.. autoclass:: interactions.api.http.request._Request + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient.HTTPClient + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient.HTTPClient + :members: + :noindex: + +.. autoclass:: interactions.api.http.channel._ChannelRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._EmojiRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._GuildRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._InteractionRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._MemberRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._MessageRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._ReactionRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._ScheduledEventRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._StickerRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._ThreadRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._UserRequest + :members: + :noindex: + +.. autoclass:: interactions.api.http.HTTPClient._WebhookRequest :members: :noindex: From f73d99f95ce9c580b5e3d4c2dec985153ff34ee9 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Wed, 2 Mar 2022 22:01:56 +0100 Subject: [PATCH 27/47] docs: fix --- docs/api.http.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/api.http.rst b/docs/api.http.rst index 43fc16137..f85d2400c 100644 --- a/docs/api.http.rst +++ b/docs/api.http.rst @@ -1,7 +1,7 @@ .. currentmodule:: interactions -HTTP Client -=========== +HTTP +==== .. autoclass:: interactions.api.http.route.Route :members: @@ -19,9 +19,6 @@ HTTP Client :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient.HTTPClient - :members: - :noindex: .. autoclass:: interactions.api.http.channel._ChannelRequest :members: From 387f86583c8b57d51aa3eb4bc1fb30ce202ef4cd Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Thu, 3 Mar 2022 11:40:40 +0100 Subject: [PATCH 28/47] refactor: rename file --- interactions/api/gateway.py | 2 +- interactions/api/gateway.pyi | 2 +- interactions/api/http/__init__.py | 2 +- interactions/api/http/{HTTPClient.py => http.py} | 0 interactions/api/http/{HTTPClient.pyi => http.pyi} | 0 interactions/api/models/channel.pyi | 2 +- interactions/api/models/guild.pyi | 2 +- interactions/api/models/gw.pyi | 2 +- interactions/api/models/member.pyi | 2 +- interactions/api/models/message.pyi | 2 +- interactions/api/models/role.pyi | 2 +- interactions/client.py | 2 +- interactions/client.pyi | 2 +- interactions/context.pyi | 2 +- 14 files changed, 12 insertions(+), 12 deletions(-) rename interactions/api/http/{HTTPClient.py => http.py} (100%) rename interactions/api/http/{HTTPClient.pyi => http.pyi} (100%) diff --git a/interactions/api/gateway.py b/interactions/api/gateway.py index 12c688125..2198cd2b2 100644 --- a/interactions/api/gateway.py +++ b/interactions/api/gateway.py @@ -25,7 +25,7 @@ from .dispatch import Listener from .enums import OpCodeType from .error import GatewayException -from .http.HTTPClient import HTTPClient +from .http.http import HTTPClient from .models.flags import Intents from .models.misc import MISSING from .models.presence import ClientPresence diff --git a/interactions/api/gateway.pyi b/interactions/api/gateway.pyi index b7ed6baf5..a5ad8d82f 100644 --- a/interactions/api/gateway.pyi +++ b/interactions/api/gateway.pyi @@ -12,7 +12,7 @@ from ..models import Option from ..api.models.misc import MISSING from ..api.models.presence import ClientPresence from .dispatch import Listener -from .http.HTTPClient import HTTPClient +from .http.http import HTTPClient from .models.flags import Intents log: Logger diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index 1e8e7063b..28426d3ba 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -7,7 +7,7 @@ from .channel import * # noqa: F401 F403 from .emoji import * # noqa: F401 F403 from .guild import * # noqa: F401 F403 -from .HTTPClient import * # noqa: F401 F403 +from .http import * # noqa: F401 F403 from .interaction import * # noqa: F401 F403 from .limiter import * # noqa: F401 F403 from .member import * # noqa: F401 F403 diff --git a/interactions/api/http/HTTPClient.py b/interactions/api/http/http.py similarity index 100% rename from interactions/api/http/HTTPClient.py rename to interactions/api/http/http.py diff --git a/interactions/api/http/HTTPClient.pyi b/interactions/api/http/http.pyi similarity index 100% rename from interactions/api/http/HTTPClient.pyi rename to interactions/api/http/http.pyi diff --git a/interactions/api/models/channel.pyi b/interactions/api/models/channel.pyi index 9b0184192..493ecf533 100644 --- a/interactions/api/models/channel.pyi +++ b/interactions/api/models/channel.pyi @@ -6,7 +6,7 @@ from .message import Message, Embed, MessageInteraction from ...models.component import ActionRow, Button, SelectMenu from .misc import DictSerializerMixin, Overwrite, Snowflake, MISSING from .user import User -from ..http.HTTPClient import HTTPClient +from ..http.http import HTTPClient class ChannelType(IntEnum): GUILD_TEXT: int diff --git a/interactions/api/models/guild.pyi b/interactions/api/models/guild.pyi index 3a654b49c..9f6257e86 100644 --- a/interactions/api/models/guild.pyi +++ b/interactions/api/models/guild.pyi @@ -9,7 +9,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .presence import PresenceActivity from .role import Role from .user import User -from ..http.HTTPClient import HTTPClient +from ..http.http import HTTPClient class VerificationLevel(IntEnum): NONE: int diff --git a/interactions/api/models/gw.pyi b/interactions/api/models/gw.pyi index 84d7a39a5..045e3e3de 100644 --- a/interactions/api/models/gw.pyi +++ b/interactions/api/models/gw.pyi @@ -9,7 +9,7 @@ from .presence import PresenceActivity from .role import Role from .user import User from .team import Application -from ..http.HTTPClient import HTTPClient +from ..http.http import HTTPClient from ...models.command import Permission class ApplicationCommandPermissions(DictSerializerMixin): diff --git a/interactions/api/models/member.pyi b/interactions/api/models/member.pyi index 02c8e5249..eab6b111e 100644 --- a/interactions/api/models/member.pyi +++ b/interactions/api/models/member.pyi @@ -5,7 +5,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .role import Role from .user import User from .flags import Permissions -from ..http.HTTPClient import HTTPClient +from ..http.http import HTTPClient from .message import Message, Embed, MessageInteraction from ...models.component import ActionRow, Button, SelectMenu diff --git a/interactions/api/models/message.pyi b/interactions/api/models/message.pyi index 7537fae9e..4b8c9892b 100644 --- a/interactions/api/models/message.pyi +++ b/interactions/api/models/message.pyi @@ -7,7 +7,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .role import Role from .team import Application from .user import User -from ..http.HTTPClient import HTTPClient +from ..http.http import HTTPClient from ...models.component import ActionRow, Button, SelectMenu from .guild import Guild diff --git a/interactions/api/models/role.pyi b/interactions/api/models/role.pyi index b78886290..2dbee194c 100644 --- a/interactions/api/models/role.pyi +++ b/interactions/api/models/role.pyi @@ -1,7 +1,7 @@ from typing import Any, Optional, List from .misc import DictSerializerMixin, MISSING, Snowflake -from ..http.HTTPClient import HTTPClient +from ..http.http import HTTPClient class RoleTags(DictSerializerMixin): _json: dict diff --git a/interactions/client.py b/interactions/client.py index b6192c25e..ccb33c787 100644 --- a/interactions/client.py +++ b/interactions/client.py @@ -13,7 +13,7 @@ from .api.cache import Item as Build from .api.error import InteractionException, JSONException from .api.gateway import WebSocketClient -from .api.http.HTTPClient import HTTPClient +from .api.http.http import HTTPClient from .api.models.flags import Intents from .api.models.guild import Guild from .api.models.misc import MISSING, Snowflake diff --git a/interactions/client.pyi b/interactions/client.pyi index 1d65d78ba..96b7ad25e 100644 --- a/interactions/client.pyi +++ b/interactions/client.pyi @@ -4,7 +4,7 @@ from typing import Any, Callable, Coroutine, Dict, List, NoReturn, Optional, Tup from .api.cache import Cache from .api.gateway import WebSocketClient -from .api.http.HTTPClient import HTTPClient +from .api.http.http import HTTPClient from .api.models.flags import Intents from .api.models.guild import Guild from .api.models.misc import MISSING, Snowflake diff --git a/interactions/context.pyi b/interactions/context.pyi index bf7d295fc..d0b0e1348 100644 --- a/interactions/context.pyi +++ b/interactions/context.pyi @@ -1,6 +1,6 @@ rom typing import List, Optional, Union -from .api.http.HTTPClient import HTTPClient +from .api.http.http import HTTPClient from .api.models.channel import Channel as Channel from .api.models.guild import Guild as Guild from .api.models.member import Member as Member From 93478364469a6df9b41786343994104ebea8a422 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Thu, 3 Mar 2022 11:43:23 +0100 Subject: [PATCH 29/47] refactor: rename file --- docs/api.http.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.http.rst b/docs/api.http.rst index f85d2400c..9b705682e 100644 --- a/docs/api.http.rst +++ b/docs/api.http.rst @@ -15,7 +15,7 @@ HTTP :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient.HTTPClient +.. autoclass:: interactions.api.http.http.HTTPClient :members: :noindex: From 7414a03b7fd8ef4d9d9e8e0bd3ce1a8b441a0ed0 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Thu, 3 Mar 2022 12:22:57 +0100 Subject: [PATCH 30/47] refactor: subclassing --- interactions/api/http/channel.py | 7 +-- interactions/api/http/channel.pyi | 2 +- interactions/api/http/emoji.py | 7 +-- interactions/api/http/emoji.pyi | 2 +- interactions/api/http/guild.py | 7 +-- interactions/api/http/guild.pyi | 2 +- interactions/api/http/http.py | 51 +++++++++++---------- interactions/api/http/http.pyi | 26 +---------- interactions/api/http/interaction.py | 7 +-- interactions/api/http/interaction.pyi | 2 +- interactions/api/http/member.py | 7 +-- interactions/api/http/member.pyi | 2 +- interactions/api/http/message.py | 7 +-- interactions/api/http/message.pyi | 5 +- interactions/api/http/reaction.py | 7 +-- interactions/api/http/reaction.pyi | 2 +- interactions/api/http/scheduledEvent.py | 7 +-- interactions/api/http/scheduledEvent.pyi | 2 +- interactions/api/http/sticker.py | 7 +-- interactions/api/http/sticker.pyi | 2 +- interactions/api/http/thread.py | 7 +-- interactions/api/http/thread.pyi | 2 +- interactions/api/http/user.py | 7 +-- interactions/api/http/user.pyi | 2 +- interactions/api/http/webhook.py | 7 +-- interactions/api/http/webhook.pyi | 2 +- interactions/api/models/channel.py | 46 +++++++++---------- interactions/api/models/guild.py | 58 ++++++++++++------------ interactions/api/models/member.py | 22 ++++----- interactions/api/models/message.py | 24 ++++------ interactions/api/models/role.py | 6 +-- interactions/client.py | 16 +++---- interactions/context.py | 48 ++++++++++---------- interactions/context.pyi | 2 +- 34 files changed, 171 insertions(+), 239 deletions(-) diff --git a/interactions/api/http/channel.py b/interactions/api/http/channel.py index c00f883ba..62b508cba 100644 --- a/interactions/api/http/channel.py +++ b/interactions/api/http/channel.py @@ -9,14 +9,11 @@ class _ChannelRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def get_channel(self, channel_id: int) -> dict: """ diff --git a/interactions/api/http/channel.pyi b/interactions/api/http/channel.pyi index cb2a19b97..4b9c35b84 100644 --- a/interactions/api/http/channel.pyi +++ b/interactions/api/http/channel.pyi @@ -9,7 +9,7 @@ class _ChannelRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def get_channel(self, channel_id: int) -> dict: ... async def delete_channel(self, channel_id: int) -> None: ... async def get_channel_messages( diff --git a/interactions/api/http/emoji.py b/interactions/api/http/emoji.py index 375b00855..e8b57eb9c 100644 --- a/interactions/api/http/emoji.py +++ b/interactions/api/http/emoji.py @@ -7,14 +7,11 @@ class _EmojiRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def get_all_emoji(self, guild_id: int) -> List[dict]: """ diff --git a/interactions/api/http/emoji.pyi b/interactions/api/http/emoji.pyi index ca8a2fabb..c51005da8 100644 --- a/interactions/api/http/emoji.pyi +++ b/interactions/api/http/emoji.pyi @@ -9,7 +9,7 @@ class _EmojiRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def get_all_emoji(self, guild_id: int) -> List[dict]: ... async def get_guild_emoji(self, guild_id: int, emoji_id: int) -> dict: ... async def create_guild_emoji( diff --git a/interactions/api/http/guild.py b/interactions/api/http/guild.py index 4d1ad52e0..c89e9f3cd 100644 --- a/interactions/api/http/guild.py +++ b/interactions/api/http/guild.py @@ -12,14 +12,11 @@ class _GuildRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def get_self_guilds(self) -> List[dict]: """ diff --git a/interactions/api/http/guild.pyi b/interactions/api/http/guild.pyi index ed1680138..f9e650ddf 100644 --- a/interactions/api/http/guild.pyi +++ b/interactions/api/http/guild.pyi @@ -9,7 +9,7 @@ class _GuildRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def get_self_guilds(self) -> List[dict]: ... async def get_guild(self, guild_id: int) -> dict: ... async def get_guild_preview(self, guild_id: int) -> dict: ... diff --git a/interactions/api/http/http.py b/interactions/api/http/http.py index 23034e4be..9adb7a1f2 100644 --- a/interactions/api/http/http.py +++ b/interactions/api/http/http.py @@ -19,7 +19,20 @@ from .webhook import _WebhookRequest -class HTTPClient: +class HTTPClient( + _ChannelRequest, + _EmojiRequest, + _GuildRequest, + _InteractionRequest, + _MemberRequest, + _MessageRequest, + _ReactionRequest, + _ScheduledEventRequest, + _StickerRequest, + _ThreadRequest, + _UserRequest, + _WebhookRequest, +): """ The user-facing client of the Web API for individual endpoints. @@ -48,36 +61,24 @@ class HTTPClient: token: str _req: _Request - member: _MemberRequest cache: Cache - user: _UserRequest - message: _MessageRequest - guild: _GuildRequest - channel: _ChannelRequest - thread: _ThreadRequest - reaction: _ReactionRequest - sticker: _StickerRequest - interaction: _InteractionRequest - webhook: _WebhookRequest - emoji: _EmojiRequest - scheduled_event: _ScheduledEventRequest def __init__(self, token: str): self.token = token self._req = _Request(self.token) self.cache = interactions.api.cache.ref_cache - self.user = _UserRequest(_req=self._req, cache=self.cache) - self.message = _MessageRequest(_req=self._req, cache=self.cache) - self.guild = _GuildRequest(_req=self._req, cache=self.cache) - self.channel = _ChannelRequest(_req=self._req, cache=self.cache) - self.thread = _ThreadRequest(_req=self._req, cache=self.cache) - self.reaction = _ReactionRequest(_req=self._req, cache=self.cache) - self.sticker = _StickerRequest(_req=self._req, cache=self.cache) - self.interaction = _InteractionRequest(_req=self._req, cache=self.cache) - self.webhook = _WebhookRequest(_req=self._req, cache=self.cache) - self.scheduled_event = _ScheduledEventRequest(_req=self._req, cache=self.cache) - self.emoji = _EmojiRequest(_req=self._req, cache=self.cache) - self.member = _MemberRequest(_req=self._req, cache=self.cache) + _UserRequest.__init__(self) + _MessageRequest.__init__(self) + _GuildRequest.__init__(self) + _ChannelRequest.__init__(self) + _ThreadRequest.__init__(self) + _ReactionRequest.__init__(self) + _StickerRequest.__init__(self) + _InteractionRequest.__init__(self) + _WebhookRequest.__init__(self) + _ScheduledEventRequest.__init__(self) + _EmojiRequest.__init__(self) + _MemberRequest.__init__(self) # An ideology is that this client does every single HTTP call, which reduces multiple ClientSessions in theory # because of how they are constructed/closed. This includes Gateway diff --git a/interactions/api/http/http.pyi b/interactions/api/http/http.pyi index 628035162..7b905363f 100644 --- a/interactions/api/http/http.pyi +++ b/interactions/api/http/http.pyi @@ -2,36 +2,14 @@ from typing import Optional, Tuple from .request import _Request from ...api.cache import Cache -from .user import _UserRequest -from .message import _MessageRequest -from .guild import _GuildRequest -from .channel import _ChannelRequest -from .thread import _ThreadRequest -from .sticker import _StickerRequest -from .reaction import _ReactionRequest -from .webhook import _WebhookRequest -from .emoji import _EmojiRequest -from .scheduledEvent import _ScheduledEventRequest -from .interaction import _InteractionRequest -from .member import _MemberRequest + class HTTPClient: token: str _req: _Request cache: Cache - message: _MessageRequest - user: _UserRequest - guild: _GuildRequest - channel: _ChannelRequest - member: _MemberRequest - thread: _ThreadRequest - reaction: _ReactionRequest - sticker: _StickerRequest - interaction: _InteractionRequest - webhook: _WebhookRequest - emoji: _EmojiRequest - scheduled_event: _ScheduledEventRequest + def __init__(self, token: str): ... diff --git a/interactions/api/http/interaction.py b/interactions/api/http/interaction.py index 0ebaeba47..b609eb8df 100644 --- a/interactions/api/http/interaction.py +++ b/interactions/api/http/interaction.py @@ -8,14 +8,11 @@ class _InteractionRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def get_application_commands( self, application_id: Union[int, Snowflake], guild_id: Optional[int] = None diff --git a/interactions/api/http/interaction.pyi b/interactions/api/http/interaction.pyi index 23652d07a..2056085f8 100644 --- a/interactions/api/http/interaction.pyi +++ b/interactions/api/http/interaction.pyi @@ -10,7 +10,7 @@ class _InteractionRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def get_application_commands( self, application_id: Union[int, Snowflake], guild_id: Optional[int] = None ) -> List[dict]: ... diff --git a/interactions/api/http/member.py b/interactions/api/http/member.py index 876d4c9f8..417e7ebec 100644 --- a/interactions/api/http/member.py +++ b/interactions/api/http/member.py @@ -7,14 +7,11 @@ class _MemberRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def get_member(self, guild_id: int, member_id: int) -> Optional[dict]: """ diff --git a/interactions/api/http/member.pyi b/interactions/api/http/member.pyi index 8236a2dce..e7ed242b9 100644 --- a/interactions/api/http/member.pyi +++ b/interactions/api/http/member.pyi @@ -10,7 +10,7 @@ class _MemberRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def get_member(self, guild_id: int, member_id: int) -> Optional[dict]: ... async def get_list_of_members( self, guild_id: int, limit: int = 1, after: Optional[int] = None diff --git a/interactions/api/http/message.py b/interactions/api/http/message.py index 0b063a9c2..4e12ea42d 100644 --- a/interactions/api/http/message.py +++ b/interactions/api/http/message.py @@ -9,14 +9,11 @@ class _MessageRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def send_message( self, diff --git a/interactions/api/http/message.pyi b/interactions/api/http/message.pyi index efd6eb3f9..d788e0798 100644 --- a/interactions/api/http/message.pyi +++ b/interactions/api/http/message.pyi @@ -11,9 +11,8 @@ class _MessageRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def send_message( self, channel_id: Union[int, Snowflake], diff --git a/interactions/api/http/reaction.py b/interactions/api/http/reaction.py index b9d0fce83..c7dbee8ee 100644 --- a/interactions/api/http/reaction.py +++ b/interactions/api/http/reaction.py @@ -7,14 +7,11 @@ class _ReactionRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def create_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: """ diff --git a/interactions/api/http/reaction.pyi b/interactions/api/http/reaction.pyi index dfedb16d8..f18ae1791 100644 --- a/interactions/api/http/reaction.pyi +++ b/interactions/api/http/reaction.pyi @@ -9,7 +9,7 @@ class _ReactionRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def create_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: ... async def remove_self_reaction(self, channel_id: int, message_id: int, emoji: str) -> None: ... async def remove_user_reaction( diff --git a/interactions/api/http/scheduledEvent.py b/interactions/api/http/scheduledEvent.py index 82a2dcd95..36362cc25 100644 --- a/interactions/api/http/scheduledEvent.py +++ b/interactions/api/http/scheduledEvent.py @@ -8,14 +8,11 @@ class _ScheduledEventRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def create_scheduled_event(self, guild_id: Snowflake, payload: dict) -> dict: """ diff --git a/interactions/api/http/scheduledEvent.pyi b/interactions/api/http/scheduledEvent.pyi index c056ea67a..efe4aaea3 100644 --- a/interactions/api/http/scheduledEvent.pyi +++ b/interactions/api/http/scheduledEvent.pyi @@ -13,7 +13,7 @@ class _ScheduledEventRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def create_scheduled_event(self, guild_id: Snowflake, payload: dict) -> dict: ... async def get_scheduled_event( self, guild_id: Snowflake, guild_scheduled_event_id: Snowflake, with_user_count: bool diff --git a/interactions/api/http/sticker.py b/interactions/api/http/sticker.py index 77fbe16d3..e824269e2 100644 --- a/interactions/api/http/sticker.py +++ b/interactions/api/http/sticker.py @@ -9,14 +9,11 @@ class _StickerRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def get_sticker(self, sticker_id: int) -> dict: """ diff --git a/interactions/api/http/sticker.pyi b/interactions/api/http/sticker.pyi index f456bc642..9d4df9eca 100644 --- a/interactions/api/http/sticker.pyi +++ b/interactions/api/http/sticker.pyi @@ -11,7 +11,7 @@ class _StickerRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def get_sticker(self, sticker_id: int) -> dict: ... async def list_nitro_sticker_packs(self) -> List[dict]: ... async def list_guild_stickers(self, guild_id: int) -> List[dict]: ... diff --git a/interactions/api/http/thread.py b/interactions/api/http/thread.py index 913dfc220..027c398b5 100644 --- a/interactions/api/http/thread.py +++ b/interactions/api/http/thread.py @@ -7,14 +7,11 @@ class _ThreadRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def join_thread(self, thread_id: int) -> None: """ diff --git a/interactions/api/http/thread.pyi b/interactions/api/http/thread.pyi index 15d6e49e5..2e5666797 100644 --- a/interactions/api/http/thread.pyi +++ b/interactions/api/http/thread.pyi @@ -8,7 +8,7 @@ class _ThreadRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def join_thread(self, thread_id: int) -> None: ... async def leave_thread(self, thread_id: int) -> None: ... async def add_member_to_thread(self, thread_id: int, user_id: int) -> None: ... diff --git a/interactions/api/http/user.py b/interactions/api/http/user.py index baa94dc56..aa14388f1 100644 --- a/interactions/api/http/user.py +++ b/interactions/api/http/user.py @@ -9,14 +9,11 @@ class _UserRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass async def get_self(self) -> dict: """ diff --git a/interactions/api/http/user.pyi b/interactions/api/http/user.pyi index aeaab172c..195f4dbfe 100644 --- a/interactions/api/http/user.pyi +++ b/interactions/api/http/user.pyi @@ -8,7 +8,7 @@ class _UserRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def get_self(self) -> dict: ... async def get_user(self, user_id: Optional[int] = None) -> dict: ... async def modify_self(self, payload: dict) -> dict: ... diff --git a/interactions/api/http/webhook.py b/interactions/api/http/webhook.py index 929601128..731df42d4 100644 --- a/interactions/api/http/webhook.py +++ b/interactions/api/http/webhook.py @@ -7,14 +7,11 @@ class _WebhookRequest: - __slots__ = ("_req", "cache") - _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: - self._req = _req - self.cache = cache + def __init__(self) -> None: + pass # TODO: Not sure why, but there's no webhook models? Will rectify later. # Also, todo: figure out what avatar is diff --git a/interactions/api/http/webhook.pyi b/interactions/api/http/webhook.pyi index 9a1a6dbc5..ea81c6312 100644 --- a/interactions/api/http/webhook.pyi +++ b/interactions/api/http/webhook.pyi @@ -9,7 +9,7 @@ class _WebhookRequest: _req: _Request cache: Cache - def __init__(self, _req, cache) -> None: ... + def __init__(self) -> None: ... async def create_webhook(self, channel_id: int, name: str, avatar: Any = None) -> dict: ... async def get_channel_webhooks(self, channel_id: int) -> List[dict]: ... async def get_guild_webhooks(self, guild_id: int) -> List[dict]: ... diff --git a/interactions/api/models/channel.py b/interactions/api/models/channel.py index 2aca16d4f..02ca3ce22 100644 --- a/interactions/api/models/channel.py +++ b/interactions/api/models/channel.py @@ -259,9 +259,7 @@ async def send( components=_components, ) - res = await self._client.message.create_message( - channel_id=int(self.id), payload=payload._json - ) + res = await self._client.create_message(channel_id=int(self.id), payload=payload._json) return Message(**res, _client=self._client) async def delete(self) -> None: @@ -270,7 +268,7 @@ async def delete(self) -> None: """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.channel.delete_channel(channel_id=int(self.id)) + await self._client.delete_channel(channel_id=int(self.id)) async def modify( self, @@ -334,7 +332,7 @@ async def modify( parent_id=_parent_id, nsfw=_nsfw, ) - res = await self._client.channel.modify_channel( + res = await self._client.modify_channel( channel_id=int(self.id), reason=reason, payload=payload._json, @@ -515,7 +513,7 @@ async def add_member( raise TypeError( "The Channel you specified is not a thread!" ) # TODO: Move to new error formatter. - await self._client.thread.add_member_to_thread(thread_id=int(self.id), user_id=member_id) + await self._client.add_member_to_thread(thread_id=int(self.id), user_id=member_id) async def pin_message( self, @@ -530,7 +528,7 @@ async def pin_message( if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.message.pin_message(channel_id=int(self.id), message_id=message_id) + await self._client.pin_message(channel_id=int(self.id), message_id=message_id) async def unpin_message( self, @@ -545,7 +543,7 @@ async def unpin_message( if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.message.unpin_message(channel_id=int(self.id), message_id=message_id) + await self._client.unpin_message(channel_id=int(self.id), message_id=message_id) async def publish_message( self, @@ -562,7 +560,7 @@ async def publish_message( raise AttributeError("HTTPClient not found!") from .message import Message - res = await self._client.message.publish_message( + res = await self._client.publish_message( channel_id=int(self.id), message_id=int(message_id) ) return Message(**res, _client=self._client) @@ -578,7 +576,7 @@ async def get_pinned_messages(self) -> List["Message"]: # noqa raise AttributeError("HTTPClient not found!") from .message import Message - res = await self._client.channel.get_pinned_messages(int(self.id)) + res = await self._client.get_pinned_messages(int(self.id)) return [Message(**message, _client=self._client) for message in res] async def get_message( @@ -591,7 +589,7 @@ async def get_message( :return: The message as object :rtype: Message """ - res = await self._client.channel.get_message( + res = await self._client.get_message( channel_id=int(self.id), message_id=message_id, ) @@ -639,7 +637,7 @@ def check_pinned(message): messages = [ Message(**res) - for res in await self._client.channel.get_channel_messages( + for res in await self._client.get_channel_messages( channel_id=int(self.id), limit=100, before=_before, @@ -664,13 +662,13 @@ def check_pinned(message): _before = int(message.id) _all += messages if len(messages) > 1: - await self._client.message.delete_messages( + await self._client.delete_messages( channel_id=int(self.id), message_ids=[int(message.id) for message in messages], reason=reason, ) elif len(messages) == 1: - await self._client.message.delete_message( + await self._client.delete_message( channel_id=int(self.id), message_id=int(messages[0].id), reason=reason, @@ -687,7 +685,7 @@ def check_pinned(message): while amount > 1: messages = [ Message(**res) - for res in await self._client.channel.get_channel_messages( + for res in await self._client.get_channel_messages( channel_id=int(self.id), limit=amount, before=_before, @@ -713,13 +711,13 @@ def check_pinned(message): _before = int(message.id) _all += messages if len(messages) > 1: - await self._client.message.delete_messages( + await self._client.delete_messages( channel_id=int(self.id), message_ids=[int(message.id) for message in messages], reason=reason, ) elif len(messages) == 1: - await self._client.message.delete_message( + await self._client.delete_message( channel_id=int(self.id), message_id=int(messages[0].id), reason=reason, @@ -733,7 +731,7 @@ def check_pinned(message): while amount == 1: messages = [ Message(**res) - for res in await self._client.channel.get_channel_messages( + for res in await self._client.get_channel_messages( channel_id=int(self.id), limit=amount, before=_before, @@ -755,7 +753,7 @@ def check_pinned(message): _all += messages if not messages: continue - await self._client.message.delete_message( + await self._client.delete_message( channel_id=int(self.id), message_id=int(messages[0].id), reason=reason, @@ -765,7 +763,7 @@ def check_pinned(message): while amount > 0: messages = [ Message(**res) - for res in await self._client.channel.get_channel_messages( + for res in await self._client.get_channel_messages( channel_id=int(self.id), limit=min(amount, 100), before=_before, @@ -788,7 +786,7 @@ def check_pinned(message): _all += messages for message in _all: - await self._client.message.delete_message( + await self._client.delete_message( channel_id=int(self.id), message_id=int(message.id), reason=reason, @@ -836,7 +834,7 @@ async def create_thread( _auto_archive_duration = None if auto_archive_duration is MISSING else auto_archive_duration _invitable = None if invitable is MISSING else invitable _message_id = None if message_id is MISSING else message_id - res = await self._client.thread.create_thread( + res = await self._client.create_thread( channel_id=int(self.id), thread_type=type.value, name=name, @@ -865,7 +863,7 @@ async def get( channel_id = channel if isinstance(channel, int) else int(channel.split(sep="/")[-1]) - res = await client.channel.get_channel(channel_id) + res = await client.get_channel(channel_id) return cls(**res, _client=client) @property @@ -941,7 +939,7 @@ async def create_invite( ) payload["target_application_id"] = target_application_id - res = await self._client.channel.create_channel_invite( + res = await self._client.create_channel_invite( channel_id=int(self.id), payload=payload, reason=reason, diff --git a/interactions/api/models/guild.py b/interactions/api/models/guild.py index 5ba8b70a1..5ae3d7ea2 100644 --- a/interactions/api/models/guild.py +++ b/interactions/api/models/guild.py @@ -346,7 +346,7 @@ async def ban( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.guild.create_guild_ban( + await self._client.create_guild_ban( guild_id=int(self.id), user_id=member_id, reason=reason, @@ -368,7 +368,7 @@ async def remove_ban( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.guild.remove_guild_ban( + await self._client.remove_guild_ban( guild_id=int(self.id), user_id=user_id, reason=reason, @@ -389,7 +389,7 @@ async def kick( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.guild.create_guild_kick( + await self._client.create_guild_kick( guild_id=int(self.id), user_id=member_id, reason=reason, @@ -414,14 +414,14 @@ async def add_member_role( if not self._client: raise AttributeError("HTTPClient not found!") if isinstance(role, Role): - await self._client.member.add_member_role( + await self._client.add_member_role( guild_id=int(self.id), user_id=member_id, role_id=int(role.id), reason=reason, ) else: - await self._client.member.add_member_role( + await self._client.add_member_role( guild_id=int(self.id), user_id=member_id, role_id=role, @@ -447,14 +447,14 @@ async def remove_member_role( if not self._client: raise AttributeError("HTTPClient not found!") if isinstance(role, Role): - await self._client.member.remove_member_role( + await self._client.remove_member_role( guild_id=int(self.id), user_id=member_id, role_id=int(role.id), reason=reason, ) else: - await self._client.member.remove_member_role( + await self._client.remove_member_role( guild_id=int(self.id), user_id=member_id, role_id=role, @@ -496,7 +496,7 @@ async def create_role( hoist=hoist, mentionable=mentionable, ) - res = await self._client.guild.create_guild_role( + res = await self._client.create_guild_role( guild_id=int(self.id), reason=reason, payload=payload._json, @@ -517,7 +517,7 @@ async def get_member( """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.member.get_member( + res = await self._client.get_member( guild_id=int(self.id), member_id=member_id, ) @@ -535,7 +535,7 @@ async def delete_channel( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.channel.delete_channel(channel_id=channel_id) + await self._client.delete_channel(channel_id=channel_id) async def delete_role( self, @@ -552,7 +552,7 @@ async def delete_role( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.guild.delete_guild_role( + await self._client.delete_guild_role( guild_id=int(self.id), role_id=role_id, reason=reason, @@ -590,7 +590,7 @@ async def modify_role( """ if not self._client: raise AttributeError("HTTPClient not found!") - roles = await self._client.guild.get_all_roles(guild_id=int(self.id)) + roles = await self._client.get_all_roles(guild_id=int(self.id)) for i in roles: if int(i["id"]) == role_id: role = Role(**i) @@ -602,7 +602,7 @@ async def modify_role( payload = Role(name=_name, color=_color, hoist=_hoist, mentionable=_mentionable) - res = await self._client.guild.modify_guild_role( + res = await self._client.modify_guild_role( guild_id=int(self.id), role_id=role_id, payload=payload._json, @@ -653,7 +653,7 @@ async def create_thread( _auto_archive_duration = None if auto_archive_duration is MISSING else auto_archive_duration _invitable = None if invitable is MISSING else invitable _message_id = None if message_id is MISSING else message_id - res = await self._client.thread.create_thread( + res = await self._client.create_thread( channel_id=int(self.id), thread_type=type.value, name=name, @@ -743,7 +743,7 @@ async def create_channel( if nsfw is not MISSING: payload["nsfw"] = nsfw - res = await self._client.channel.create_channel( + res = await self._client.create_channel( guild_id=int(self.id), reason=reason, payload=payload, @@ -793,7 +793,7 @@ async def modify_channel( """ if not self._client: raise AttributeError("HTTPClient not found!") - ch = Channel(**await self._client.channel.get_channel(channel_id=channel_id)) + ch = Channel(**await self._client.get_channel(channel_id=channel_id)) _name = ch.name if name is MISSING else name _topic = ch.topic if topic is MISSING else topic @@ -819,7 +819,7 @@ async def modify_channel( nsfw=_nsfw, ) - res = await self._client.channel.modify_channel( + res = await self._client.modify_channel( channel_id=channel_id, reason=reason, payload=payload._json, @@ -880,7 +880,7 @@ async def modify_member( if communication_disabled_until is not MISSING: payload["communication_disabled_until"] = communication_disabled_until - res = await self._client.member.modify_member( + res = await self._client.modify_member( user_id=member_id, guild_id=int(self.id), payload=payload, @@ -900,13 +900,13 @@ async def get_preview(self) -> "GuildPreview": if not self._client: raise AttributeError("HTTPClient not found!") - return GuildPreview(**await self._client.guild.get_guild_preview(guild_id=int(self.id))) + return GuildPreview(**await self._client.get_guild_preview(guild_id=int(self.id))) async def leave(self) -> None: """Removes the bot from the guild.""" if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.guild.leave_guild(guild_id=int(self.id)) + await self._client.leave_guild(guild_id=int(self.id)) async def modify( self, @@ -1035,7 +1035,7 @@ async def modify( if premium_progress_bar_enabled is not MISSING: payload["premium_progress_bar_enabled"] = premium_progress_bar_enabled - res = await self._client.guild.modify_guild( + res = await self._client.modify_guild( guild_id=int(self.id), payload=payload, reason=reason, @@ -1300,7 +1300,7 @@ async def create_scheduled_event( if description is not MISSING: payload["description"] = description - res = await self._client.scheduled_event.create_scheduled_event( + res = await self._client.create_scheduled_event( guild_id=self.id, payload=payload, ) @@ -1373,7 +1373,7 @@ async def modify_scheduled_event( if status is not MISSING: payload["status"] = status - res = await self._client.scheduled_event.modify_scheduled_event( + res = await self._client.modify_scheduled_event( guild_id=self.id, guild_scheduled_event_id=Snowflake(event_id), payload=payload, @@ -1389,7 +1389,7 @@ async def delete_scheduled_event(self, event_id: int) -> None: """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.scheduled_event.delete_scheduled_event( + await self._client.delete_scheduled_event( guild_id=self.id, guild_scheduled_event_id=Snowflake(event_id), ) @@ -1403,7 +1403,7 @@ async def get_all_channels(self) -> List[Channel]: """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.guild.get_all_channels(int(self.id)) + res = await self._client.get_all_channels(int(self.id)) return [Channel(**channel, _client=self._client) for channel in res] async def get_all_roles(self) -> List[Role]: @@ -1415,7 +1415,7 @@ async def get_all_roles(self) -> List[Role]: """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.guild.get_all_roles(int(self.id)) + res = await self._client.get_all_roles(int(self.id)) return [Role(**role, _client=self._client) for role in res] async def get_role( @@ -1433,7 +1433,7 @@ async def get_role( if not self._client: raise AttributeError("HTTPClient not found!") - roles = await self._client.guild.get_all_roles(guild_id=int(self.id)) + roles = await self._client.get_all_roles(guild_id=int(self.id)) for i in roles: if int(i["id"]) == role_id: role = Role(**i) @@ -1461,7 +1461,7 @@ async def modify_role_position( if not self._client: raise AttributeError("HTTPClient not found!") _role_id = role_id.id if isinstance(role_id, Role) else role_id - res = await self._client.guild.modify_guild_role_position( + res = await self._client.modify_guild_role_position( guild_id=int(self.id), position=position, role_id=_role_id, reason=reason ) return [Role(**role, _client=self._client) for role in res] @@ -1475,7 +1475,7 @@ async def get_bans(self) -> List[dict]: """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.guild.get_guild_bans(int(self.id)) + res = await self._client.get_guild_bans(int(self.id)) for ban in res: ban["user"] = User(**ban["user"]) return res diff --git a/interactions/api/models/member.py b/interactions/api/models/member.py index 6cf4de8b0..d03054b6a 100644 --- a/interactions/api/models/member.py +++ b/interactions/api/models/member.py @@ -117,7 +117,7 @@ async def ban( :param delete_message_days?: Number of days to delete messages, from 0 to 7. Defaults to 0 :type delete_message_days: Optional[int] """ - await self._client.guild.create_guild_ban( + await self._client.create_guild_ban( guild_id=guild_id, user_id=int(self.user.id), reason=reason, @@ -139,7 +139,7 @@ async def kick( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.guild.create_guild_kick( + await self._client.create_guild_kick( guild_id=guild_id, user_id=int(self.user.id), reason=reason, @@ -164,14 +164,14 @@ async def add_role( if not self._client: raise AttributeError("HTTPClient not found!") if isinstance(role, Role): - await self._client.member.add_member_role( + await self._client.add_member_role( guild_id=guild_id, user_id=int(self.user.id), role_id=int(role.id), reason=reason, ) else: - await self._client.member.add_member_role( + await self._client.add_member_role( guild_id=guild_id, user_id=int(self.user.id), role_id=role, @@ -197,14 +197,14 @@ async def remove_role( if not self._client: raise AttributeError("HTTPClient not found!") if isinstance(role, Role): - await self._client.member.remove_member_role( + await self._client.remove_member_role( guild_id=guild_id, user_id=int(self.user.id), role_id=int(role.id), reason=reason, ) else: - await self._client.member.remove_member_role( + await self._client.remove_member_role( guild_id=guild_id, user_id=int(self.user.id), role_id=role, @@ -278,10 +278,8 @@ async def send( allowed_mentions=_allowed_mentions, ) - channel = Channel(**await self._client.user.create_dm(recipient_id=int(self.user.id))) - res = await self._client.message.create_message( - channel_id=int(channel.id), payload=payload._json - ) + channel = Channel(**await self._client.create_dm(recipient_id=int(self.user.id))) + res = await self._client.create_message(channel_id=int(channel.id), payload=payload._json) return Message(**res, _client=self._client) @@ -339,7 +337,7 @@ async def modify( if communication_disabled_until is not MISSING: payload["communication_disabled_until"] = communication_disabled_until - res = await self._client.member.modify_member( + res = await self._client.modify_member( user_id=int(self.user.id), guild_id=guild_id, payload=payload, @@ -359,7 +357,7 @@ async def add_to_thread( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.thread.add_member_to_thread( + await self._client.add_member_to_thread( user_id=int(self.user.id), thread_id=thread_id, ) diff --git a/interactions/api/models/message.py b/interactions/api/models/message.py index 9ef65d7de..2cdba00a4 100644 --- a/interactions/api/models/message.py +++ b/interactions/api/models/message.py @@ -307,7 +307,7 @@ async def get_channel(self) -> Channel: """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.channel.get_channel(channel_id=int(self.channel_id)) + res = await self._client.get_channel(channel_id=int(self.channel_id)) return Channel(**res, _client=self._client) async def get_guild(self): @@ -320,7 +320,7 @@ async def get_guild(self): raise AttributeError("HTTPClient not found!") from .guild import Guild - res = await self._client.guild.get_guild(guild_id=int(self.guild_id)) + res = await self._client.get_guild(guild_id=int(self.guild_id)) return Guild(**res, _client=self._client) async def delete(self, reason: Optional[str] = None) -> None: @@ -332,7 +332,7 @@ async def delete(self, reason: Optional[str] = None) -> None: """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.message.delete_message( + await self._client.delete_message( message_id=int(self.id), channel_id=int(self.channel_id), reason=reason ) @@ -409,7 +409,7 @@ async def edit( components=_components, ) - _dct = await self._client.message.edit_message( + _dct = await self._client.edit_message( channel_id=int(self.channel_id), message_id=int(self.id), payload=payload._json, @@ -486,7 +486,7 @@ async def reply( components=_components, ) - res = await self._client.message.create_message( + res = await self._client.create_message( channel_id=int(self.channel_id), payload=payload._json ) return Message(**res, _client=self._client) @@ -495,17 +495,13 @@ async def pin(self) -> None: """Pins the message to its channel""" if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.message.pin_message( - channel_id=int(self.channel_id), message_id=int(self.id) - ) + await self._client.pin_message(channel_id=int(self.channel_id), message_id=int(self.id)) async def unpin(self) -> None: """Unpins the message from its channel""" if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.message.unpin_message( - channel_id=int(self.channel_id), message_id=int(self.id) - ) + await self._client.unpin_message(channel_id=int(self.channel_id), message_id=int(self.id)) async def publish(self) -> "Message": """Publishes (API calls it crossposts) the message in its channel to any that is followed by. @@ -515,7 +511,7 @@ async def publish(self) -> "Message": """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.message.publish_message( + res = await self._client.publish_message( channel_id=int(self.channel_id), message_id=int(self.id) ) return Message(**res, _client=self._client) @@ -546,7 +542,7 @@ async def create_thread( raise AttributeError("HTTPClient not found!") _auto_archive_duration = None if auto_archive_duration is MISSING else auto_archive_duration _invitable = None if invitable is MISSING else invitable - res = await self._client.thread.create_thread( + res = await self._client.create_thread( channel_id=int(self.channel_id), message_id=int(self.id), name=name, @@ -572,7 +568,7 @@ async def get_from_url(cls, url: str, client: "HTTPClient") -> "Message": # noq if "channels/" not in url: raise ValueError("You provided an invalid URL!") # TODO: custom error formatter _, _channel_id, _message_id = url.split("channels/")[1].split("/") - _message = await client.message.get_message( + _message = await client.get_message( channel_id=_channel_id, message_id=_message_id, ) diff --git a/interactions/api/models/role.py b/interactions/api/models/role.py index 03dd5d35e..682da5309 100644 --- a/interactions/api/models/role.py +++ b/interactions/api/models/role.py @@ -88,7 +88,7 @@ async def delete( """ if not self._client: raise AttributeError("HTTPClient not found!") - await self._client.guild.delete_guild_role( + await self._client.delete_guild_role( guild_id=guild_id, role_id=int(self.id), reason=reason ), @@ -131,7 +131,7 @@ async def modify( payload = Role(name=_name, color=_color, hoist=_hoist, mentionable=_mentionable) - res = await self._client.guild.modify_guild_role( + res = await self._client.modify_guild_role( guild_id=guild_id, role_id=int(self.id), payload=payload._json, @@ -159,7 +159,7 @@ async def modify_position( """ if not self._client: raise AttributeError("HTTPClient not found!") - res = await self._client.guild.modify_guild_role_position( + res = await self._client.modify_guild_role_position( guild_id=guild_id, position=position, role_id=int(self.id), reason=reason ) return [Role(**role, _client=self._client) for role in res] diff --git a/interactions/client.py b/interactions/client.py index ccb33c787..173b7cc14 100644 --- a/interactions/client.py +++ b/interactions/client.py @@ -151,7 +151,7 @@ async def __create_sync(self, data: dict) -> None: command: ApplicationCommand = ApplicationCommand( **( - await self._http.interaction.create_application_command( + await self._http.create_application_command( application_id=self.me.id, data=data, guild_id=data.get("guild_id") ) ) @@ -192,7 +192,7 @@ async def __bulk_update_sync(self, data: List[dict], delete: Optional[bool] = Fa log.info( f"Guild commands {', '.join(command['name'] for command in commands)} under ID {guild} have been {'deleted' if delete else 'synced'}." ) - await self._http.interaction.overwrite_application_command( + await self._http.overwrite_application_command( application_id=self.me.id, data=[] if delete else commands, guild_id=guild, @@ -202,7 +202,7 @@ async def __bulk_update_sync(self, data: List[dict], delete: Optional[bool] = Fa log.info( f"Global commands {', '.join(command['name'] for command in global_commands)} have been {'deleted' if delete else 'synced'}." ) - await self._http.interaction.overwrite_application_command( + await self._http.overwrite_application_command( application_id=self.me.id, data=[] if delete else global_commands ) @@ -220,9 +220,7 @@ async def _synchronize(self, payload: Optional[dict] = None) -> None: commands: List[dict] = cache else: log.info("No command cache was found present, retrieving from Web API instead.") - commands: Optional[ - Union[dict, List[dict]] - ] = await self._http.interaction.get_application_commands( + commands: Optional[Union[dict, List[dict]]] = await self._http.get_application_commands( application_id=self.me.id, guild_id=payload.get("guild_id") if payload else None ) @@ -833,7 +831,7 @@ async def autocomplete_choice_list(ctx, user_input: str = ""): if not _command_obj or not _command_obj.id: if getattr(_command_obj, "guild_id", None) or self._automate_sync: _application_commands = self._loop.run_until_complete( - self._http.interaction.get_application_commands( + self._http.get_application_commands( application_id=self.me.id, guild_id=None if not hasattr(_command_obj, "guild_id") @@ -844,7 +842,7 @@ async def autocomplete_choice_list(ctx, user_input: str = ""): else: for _scope in self._scopes: _application_commands = self._loop.run_until_complete( - self._http.interaction.get_application_commands( + self._http.get_application_commands( application_id=self.me.id, guild_id=_scope ) ) @@ -1191,7 +1189,7 @@ def teardown(self): if self.client._automate_sync: [ self.client._loop.create_task( - self.client._http.interaction.delete_application_command( + self.client._http.delete_application_command( cmd["application_id"], cmd["id"], cmd["guild_id"] ) ) diff --git a/interactions/context.py b/interactions/context.py index 7c39ef680..9884d21a6 100644 --- a/interactions/context.py +++ b/interactions/context.py @@ -102,7 +102,7 @@ async def get_channel(self) -> Channel: :rtype: Channel """ - res = await self.client.channel.get_channel(int(self.channel_id)) + res = await self.client.get_channel(int(self.channel_id)) self.channel = Channel(**res, _client=self.client) return self.channel @@ -114,7 +114,7 @@ async def get_guild(self) -> Guild: :rtype: Guild """ - res = await self.client.guild.get_guild(int(self.guild_id)) + res = await self.client.get_guild(int(self.guild_id)) self.guild = Guild(**res, _client=self.client) return self.guild @@ -295,7 +295,7 @@ async def popup(self, modal: Modal) -> None: }, } - await self.client.interaction.create_interaction_response( + await self.client.create_interaction_response( token=self.token, application_id=int(self.id), data=payload, @@ -317,7 +317,7 @@ class CommandContext(_Context): this as a value, but instead ``guild_id``. You will need to manually fetch for this data for the time being. - You can fetch with ``client.guild.get_guild(guild_id)`` which + You can fetch with ``client.get_guild(guild_id)`` which will return a JSON dictionary, which you can then use ``interactions.Guild(**data)`` for an object or continue with a dictionary for your own purposes. @@ -385,12 +385,12 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: if self.deferred: if hasattr(self.message, "id") and self.message.id is not None: - res = await self.client.message.edit_message( + res = await self.client.edit_message( int(self.channel_id), int(self.message.id), payload=payload._json ) self.message = msg = Message(**res, _client=self.client) else: - res = await self.client.interaction.edit_interaction_response( + res = await self.client.edit_interaction_response( token=self.token, application_id=str(self.id), data={"type": self.callback.value, "data": payload._json}, @@ -401,12 +401,12 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: self.message = payload self.message._client = self.client else: - await self.client.message.edit_message( + await self.client.edit_message( int(self.channel_id), res["id"], payload=payload._json ) self.message = msg = Message(**res, _client=self.client) else: - res = await self.client.interaction.edit_interaction_response( + res = await self.client.edit_interaction_response( token=self.token, application_id=str(self.application_id), data={"type": self.callback.value, "data": payload._json}, @@ -414,7 +414,7 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: if res["flags"] == 64: log.warning("You can't edit hidden messages.") else: - await self.client.message.edit_message( + await self.client.edit_message( int(self.channel_id), res["id"], payload=payload._json ) self.message = msg = Message(**res, _client=self.client) @@ -435,7 +435,7 @@ async def defer(self, ephemeral: Optional[bool] = False) -> None: _ephemeral: int = (1 << 6) if ephemeral else 0 self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE - await self.client.interaction.create_interaction_response( + await self.client.create_interaction_response( token=self.token, application_id=int(self.id), data={"type": self.callback.value, "data": {"flags": _ephemeral}}, @@ -452,14 +452,14 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: msg = None if self.responded or self.deferred: if self.deferred: - res = await self.client.interaction.edit_interaction_response( + res = await self.client.edit_interaction_response( data=payload._json, token=self.token, application_id=str(self.application_id), ) self.responded = True else: - res = await self.client.interaction._post_followup( + res = await self.client._post_followup( data=payload._json, token=self.token, application_id=str(self.application_id), @@ -471,7 +471,7 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: application_id=int(self.id), data=_payload, ) - __newdata = await self.client.interaction.edit_interaction_response( + __newdata = await self.client.edit_interaction_response( data={}, token=self.token, application_id=str(self.application_id), @@ -495,11 +495,11 @@ async def delete(self) -> None: being present. """ if self.responded: - await self.client.webhook.delete_webhook_message( + await self.client.delete_webhook_message( webhook_id=int(self.id), webhook_token=self.token, message_id=int(self.message.id) ) else: - await self.client.webhook.delete_original_webhook_message(int(self.id), self.token) + await self.client.delete_original_webhook_message(int(self.id), self.token) self.message = None async def populate(self, choices: Union[Choice, List[Choice]]) -> List[Choice]: @@ -534,7 +534,7 @@ async def func(): 6, message="Autocomplete choice items must be of type Choice" ) - await self.client.interaction.create_interaction_response( + await self.client.create_interaction_response( token=self.token, application_id=int(self.id), data={ @@ -590,7 +590,7 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: if not self.deferred: self.callback = InteractionCallbackType.UPDATE_MESSAGE - await self.client.interaction.create_interaction_response( + await self.client.create_interaction_response( data={"type": self.callback.value, "data": payload._json}, token=self.token, application_id=int(self.id), @@ -598,13 +598,13 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: self.message = payload self.responded = True elif self.callback != InteractionCallbackType.DEFERRED_UPDATE_MESSAGE: - await self.client.interaction._post_followup( + await self.client._post_followup( data=payload._json, token=self.token, application_id=str(self.application_id), ) else: - res = await self.client.interaction.edit_interaction_response( + res = await self.client.edit_interaction_response( data=payload._json, token=self.token, application_id=str(self.application_id), @@ -632,14 +632,14 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: or self.callback == InteractionCallbackType.DEFERRED_UPDATE_MESSAGE ): if self.deferred: - res = await self.client.interaction.edit_interaction_response( + res = await self.client.edit_interaction_response( data=payload._json, token=self.token, application_id=str(self.application_id), ) self.responded = True else: - res = await self.client.interaction._post_followup( + res = await self.client._post_followup( data=payload._json, token=self.token, application_id=str(self.application_id), @@ -647,12 +647,12 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: self.message = msg = Message(**res, _client=self.client) else: - await self.client.interaction.create_interaction_response( + await self.client.create_interaction_response( token=self.token, application_id=int(self.id), data=_payload, ) - __newdata = await self.client.interaction.edit_interaction_response( + __newdata = await self.client.edit_interaction_response( data={}, token=self.token, application_id=str(self.application_id), @@ -688,7 +688,7 @@ async def defer( else: self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE - await self.client.interaction.create_interaction_response( + await self.client.create_interaction_response( token=self.token, application_id=int(self.id), data={"type": self.callback.value, "data": {"flags": _ephemeral}}, diff --git a/interactions/context.pyi b/interactions/context.pyi index d0b0e1348..f1ec548d5 100644 --- a/interactions/context.pyi +++ b/interactions/context.pyi @@ -1,4 +1,4 @@ -rom typing import List, Optional, Union +from typing import List, Optional, Union from .api.http.http import HTTPClient from .api.models.channel import Channel as Channel From 754d5d0363043ea997aef99b5726022a974005fe Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Thu, 3 Mar 2022 14:52:13 +0100 Subject: [PATCH 31/47] refactor: remove leftover slots --- interactions/api/http/http.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/interactions/api/http/http.py b/interactions/api/http/http.py index 9adb7a1f2..d3bb8c3e7 100644 --- a/interactions/api/http/http.py +++ b/interactions/api/http/http.py @@ -45,18 +45,6 @@ class HTTPClient( "token", "_req", "cache", - "user", - "message", - "guild", - "member", - "channel", - "thread", - "reaction", - "sticker", - "interaction", - "webhook", - "emoji", - "scheduled_event", ) token: str From 2ba40ae21b3571d32ea378bb1144a1abf882d88c Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 00:23:20 +0100 Subject: [PATCH 32/47] Update docs/api.http.rst Co-authored-by: fl0w <41456914+goverfl0w@users.noreply.github.com> --- docs/api.http.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api.http.rst b/docs/api.http.rst index 9b705682e..d6ec21ad6 100644 --- a/docs/api.http.rst +++ b/docs/api.http.rst @@ -19,7 +19,6 @@ HTTP :members: :noindex: - .. autoclass:: interactions.api.http.channel._ChannelRequest :members: :noindex: From 9607770c874c208603ffc9a2c8ab0633f0361ce2 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:38:48 +0100 Subject: [PATCH 33/47] Update api.http.rst --- docs/api.http.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/api.http.rst b/docs/api.http.rst index d6ec21ad6..6d1b568df 100644 --- a/docs/api.http.rst +++ b/docs/api.http.rst @@ -15,7 +15,7 @@ HTTP :members: :noindex: -.. autoclass:: interactions.api.http.http.HTTPClient +.. autoclass:: interactions.api.http.client.HTTPClient :members: :noindex: @@ -23,46 +23,46 @@ HTTP :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._EmojiRequest +.. autoclass:: interactions.api.http.emoji._EmojiRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._GuildRequest +.. autoclass:: interactions.api.http.guild._GuildRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._InteractionRequest +.. autoclass:: interactions.api.http.interaction._InteractionRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._MemberRequest +.. autoclass:: interactions.api.http.member._MemberRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._MessageRequest +.. autoclass:: interactions.api.http.message._MessageRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._ReactionRequest +.. autoclass:: interactions.api.http.reaction._ReactionRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._ScheduledEventRequest +.. autoclass:: interactions.api.http.scheduledEvent._ScheduledEventRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._StickerRequest +.. autoclass:: interactions.api.http.sticker._StickerRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._ThreadRequest +.. autoclass:: interactions.api.http.thread._ThreadRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._UserRequest +.. autoclass:: interactions.api.http.user._UserRequest :members: :noindex: -.. autoclass:: interactions.api.http.HTTPClient._WebhookRequest +.. autoclass:: interactions.api.http.webhook._WebhookRequest :members: :noindex: From 76ca8ff4bc0d6fcac82a35d418abb3b6b4cb241a Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:42:34 +0100 Subject: [PATCH 34/47] Rename http.pyi to client.pyi --- interactions/api/http/{http.pyi => client.pyi} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename interactions/api/http/{http.pyi => client.pyi} (100%) diff --git a/interactions/api/http/http.pyi b/interactions/api/http/client.pyi similarity index 100% rename from interactions/api/http/http.pyi rename to interactions/api/http/client.pyi From 7d7edbb42f4fa12f5e9c3e0900dd3541c0db691c Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:44:42 +0100 Subject: [PATCH 35/47] Rename http.py to client.py --- interactions/api/http/{http.py => client.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename interactions/api/http/{http.py => client.py} (100%) diff --git a/interactions/api/http/http.py b/interactions/api/http/client.py similarity index 100% rename from interactions/api/http/http.py rename to interactions/api/http/client.py From d722ee3e947f963c7cb8dec38072f7a3d1f912a5 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:56:22 +0100 Subject: [PATCH 36/47] Update gateway.py --- interactions/api/gateway.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/gateway.py b/interactions/api/gateway.py index 2198cd2b2..26c842699 100644 --- a/interactions/api/gateway.py +++ b/interactions/api/gateway.py @@ -25,7 +25,7 @@ from .dispatch import Listener from .enums import OpCodeType from .error import GatewayException -from .http.http import HTTPClient +from .http.client import HTTPClient from .models.flags import Intents from .models.misc import MISSING from .models.presence import ClientPresence From 6dc0c949b1d0c5bd6af1a1d62380eb71dac6168a Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:56:40 +0100 Subject: [PATCH 37/47] Update gateway.pyi --- interactions/api/gateway.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/gateway.pyi b/interactions/api/gateway.pyi index a5ad8d82f..0a7a5f856 100644 --- a/interactions/api/gateway.pyi +++ b/interactions/api/gateway.pyi @@ -12,7 +12,7 @@ from ..models import Option from ..api.models.misc import MISSING from ..api.models.presence import ClientPresence from .dispatch import Listener -from .http.http import HTTPClient +from .http.client import HTTPClient from .models.flags import Intents log: Logger From 3c483340b0da1021bb3365d426fdefc071e32faf Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:57:05 +0100 Subject: [PATCH 38/47] Update channel.pyi --- interactions/api/models/channel.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/models/channel.pyi b/interactions/api/models/channel.pyi index 493ecf533..3d0519457 100644 --- a/interactions/api/models/channel.pyi +++ b/interactions/api/models/channel.pyi @@ -6,7 +6,7 @@ from .message import Message, Embed, MessageInteraction from ...models.component import ActionRow, Button, SelectMenu from .misc import DictSerializerMixin, Overwrite, Snowflake, MISSING from .user import User -from ..http.http import HTTPClient +from ..http.client import HTTPClient class ChannelType(IntEnum): GUILD_TEXT: int From fce5d88aec20340d76219aa63d8b8b7b8cda4cea Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:57:16 +0100 Subject: [PATCH 39/47] Update guild.pyi --- interactions/api/models/guild.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/models/guild.pyi b/interactions/api/models/guild.pyi index 9f6257e86..cc6d1240a 100644 --- a/interactions/api/models/guild.pyi +++ b/interactions/api/models/guild.pyi @@ -9,7 +9,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .presence import PresenceActivity from .role import Role from .user import User -from ..http.http import HTTPClient +from ..http.client import HTTPClient class VerificationLevel(IntEnum): NONE: int From 243434b5cbd3d42ac720f1023efca06fc3250cdc Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:57:28 +0100 Subject: [PATCH 40/47] Update member.pyi --- interactions/api/models/member.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/models/member.pyi b/interactions/api/models/member.pyi index eab6b111e..b321c0118 100644 --- a/interactions/api/models/member.pyi +++ b/interactions/api/models/member.pyi @@ -5,7 +5,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .role import Role from .user import User from .flags import Permissions -from ..http.http import HTTPClient +from ..http.client import HTTPClient from .message import Message, Embed, MessageInteraction from ...models.component import ActionRow, Button, SelectMenu From f915342fe3663f1cffe592e24242066736472cb1 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:57:45 +0100 Subject: [PATCH 41/47] Update message.pyi --- interactions/api/models/message.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/models/message.pyi b/interactions/api/models/message.pyi index 4b8c9892b..d9e4bf5fc 100644 --- a/interactions/api/models/message.pyi +++ b/interactions/api/models/message.pyi @@ -7,7 +7,7 @@ from .misc import DictSerializerMixin, MISSING, Snowflake from .role import Role from .team import Application from .user import User -from ..http.http import HTTPClient +from ..http.client import HTTPClient from ...models.component import ActionRow, Button, SelectMenu from .guild import Guild From b20b565da12ea3bb32e8a9c302e6e9c0ca32a405 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:58:00 +0100 Subject: [PATCH 42/47] Update role.pyi --- interactions/api/models/role.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/models/role.pyi b/interactions/api/models/role.pyi index 2dbee194c..b865fc311 100644 --- a/interactions/api/models/role.pyi +++ b/interactions/api/models/role.pyi @@ -1,7 +1,7 @@ from typing import Any, Optional, List from .misc import DictSerializerMixin, MISSING, Snowflake -from ..http.http import HTTPClient +from ..http.client import HTTPClient class RoleTags(DictSerializerMixin): _json: dict From 24e260882fdfc408bf27322480299bbb88622c01 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:58:47 +0100 Subject: [PATCH 43/47] Update client.py --- interactions/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/client.py b/interactions/client.py index 173b7cc14..d03453e4b 100644 --- a/interactions/client.py +++ b/interactions/client.py @@ -13,7 +13,7 @@ from .api.cache import Item as Build from .api.error import InteractionException, JSONException from .api.gateway import WebSocketClient -from .api.http.http import HTTPClient +from .api.http.client import HTTPClient from .api.models.flags import Intents from .api.models.guild import Guild from .api.models.misc import MISSING, Snowflake From 2a9ae1604b608b92bf15e2b7d920c60549fd6dfa Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:59:59 +0100 Subject: [PATCH 44/47] Update client.pyi --- interactions/client.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/client.pyi b/interactions/client.pyi index 96b7ad25e..756db1606 100644 --- a/interactions/client.pyi +++ b/interactions/client.pyi @@ -4,7 +4,7 @@ from typing import Any, Callable, Coroutine, Dict, List, NoReturn, Optional, Tup from .api.cache import Cache from .api.gateway import WebSocketClient -from .api.http.http import HTTPClient +from .api.http.client import HTTPClient from .api.models.flags import Intents from .api.models.guild import Guild from .api.models.misc import MISSING, Snowflake From 68493fe186afc0e64499ef4854f03ec218390635 Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 21:00:12 +0100 Subject: [PATCH 45/47] Update context.pyi --- interactions/context.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/context.pyi b/interactions/context.pyi index f1ec548d5..b8a92a178 100644 --- a/interactions/context.pyi +++ b/interactions/context.pyi @@ -1,6 +1,6 @@ from typing import List, Optional, Union -from .api.http.http import HTTPClient +from .api.http.client import HTTPClient from .api.models.channel import Channel as Channel from .api.models.guild import Guild as Guild from .api.models.member import Member as Member From 9eb26cd317c0f23bdcb1e07811d070cffb7b3eaa Mon Sep 17 00:00:00 2001 From: EdVraz <88881326+EdVraz@users.noreply.github.com> Date: Mon, 14 Mar 2022 21:02:17 +0100 Subject: [PATCH 46/47] Update __init__.py --- interactions/api/http/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index 28426d3ba..14a93f7a4 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -7,7 +7,7 @@ from .channel import * # noqa: F401 F403 from .emoji import * # noqa: F401 F403 from .guild import * # noqa: F401 F403 -from .http import * # noqa: F401 F403 +from .client import * # noqa: F401 F403 from .interaction import * # noqa: F401 F403 from .limiter import * # noqa: F401 F403 from .member import * # noqa: F401 F403 From 0dcd8665118f670bc5b72edbc15939239ac6ed6f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:03:56 +0000 Subject: [PATCH 47/47] ci: correct from checks. --- interactions/api/http/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/api/http/__init__.py b/interactions/api/http/__init__.py index 14a93f7a4..d206b90d1 100644 --- a/interactions/api/http/__init__.py +++ b/interactions/api/http/__init__.py @@ -5,9 +5,9 @@ """ from .channel import * # noqa: F401 F403 +from .client import * # noqa: F401 F403 from .emoji import * # noqa: F401 F403 from .guild import * # noqa: F401 F403 -from .client import * # noqa: F401 F403 from .interaction import * # noqa: F401 F403 from .limiter import * # noqa: F401 F403 from .member import * # noqa: F401 F403