diff --git a/discord/channel.py b/discord/channel.py index f24653920..9b8da13a4 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -637,6 +637,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): name: str, message: Optional[Snowflake] = None, auto_archive_duration: ThreadArchiveDuration = 1440, + reason: Optional[str] = None ) -> Thread: """|coro| @@ -650,6 +651,8 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): you must have :attr:`~discord.Permissions.send_messages` and :attr:`~discord.Permissions.use_threads` in order to start the thread. + .. versionadded:: 2.0 + Parameters ----------- name: :class:`str` @@ -661,6 +664,8 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): auto_archive_duration: :class:`int` The duration in minutes before a thread is automatically archived for inactivity. Defaults to ``1440`` or 24 hours. + reason: :class:`str` + The reason for starting a new thread. Shows up on the audit log. Raises ------- @@ -681,6 +686,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): name=name, auto_archive_duration=auto_archive_duration, type=ChannelType.private_thread.value, + reason=reason, ) else: data = await self._state.http.start_public_thread( @@ -689,6 +695,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): name=name, auto_archive_duration=auto_archive_duration, type=ChannelType.public_thread.value, + reason=reason, ) return Thread(guild=self.guild, state=self._state, data=data) @@ -706,6 +713,8 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): You must have :attr:`~Permissions.read_message_history` to use this. If iterating over private threads then :attr:`~Permissions.manage_threads` is also required. + .. versionadded:: 2.0 + Parameters ----------- limit: Optional[:class:`bool`] @@ -1119,7 +1128,7 @@ class StageChannel(VocalGuildChannel): """ return utils.get(self.guild.stage_instances, channel_id=self.id) - async def create_instance(self, *, topic: str, privacy_level: StagePrivacyLevel = MISSING) -> StageInstance: + async def create_instance(self, *, topic: str, privacy_level: StagePrivacyLevel = MISSING, reason: Optional[str] = None) -> StageInstance: """|coro| Create a stage instance. @@ -1135,6 +1144,8 @@ class StageChannel(VocalGuildChannel): The stage instance's topic. privacy_level: :class:`StagePrivacyLevel` The stage instance's privacy level. Defaults to :attr:`StagePrivacyLevel.guild_only`. + reason: :class:`str` + The reason the stage instance was created. Shows up on the audit log. Raises ------ @@ -1159,7 +1170,7 @@ class StageChannel(VocalGuildChannel): payload['privacy_level'] = privacy_level.value - data = await self._state.http.create_stage_instance(**payload) + data = await self._state.http.create_stage_instance(**payload, reason=reason) return StageInstance(guild=self.guild, state=self._state, data=data) async def fetch_instance(self) -> StageInstance: diff --git a/discord/http.py b/discord/http.py index 865100d88..86a9e0944 100644 --- a/discord/http.py +++ b/discord/http.py @@ -436,7 +436,7 @@ class HTTPClient: if embed: payload['embeds'] = [embed] - + if embeds: payload['embeds'] = embeds @@ -713,11 +713,7 @@ class HTTPClient: 'delete_message_days': delete_message_days, } - if reason: - # thanks aiohttp - r.url = f'{r.url}?reason={_uriquote(reason)}' - - return self.request(r, params=params) + return self.request(r, params=params, reason=reason) def unban(self, user_id: Snowflake, guild_id: Snowflake, *, reason: Optional[str] = None) -> Response[None]: r = Route('DELETE', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id) @@ -879,6 +875,7 @@ class HTTPClient: name: str, auto_archive_duration: threads.ThreadArchiveDuration, type: threads.ThreadType, + reason: Optional[str] = None, ) -> Response[threads.Thread]: payload = { 'name': name, @@ -889,7 +886,7 @@ class HTTPClient: route = Route( 'POST', '/channels/{channel_id}/messages/{message_id}/threads', channel_id=channel_id, message_id=message_id ) - return self.request(route, json=payload) + return self.request(route, json=payload, reason=reason) def start_private_thread( self, @@ -898,6 +895,7 @@ class HTTPClient: name: str, auto_archive_duration: threads.ThreadArchiveDuration, type: threads.ThreadType, + reason: Optional[str] = None, ) -> Response[threads.Thread]: payload = { 'name': name, @@ -906,7 +904,7 @@ class HTTPClient: } route = Route('POST', '/channels/{channel_id}/threads', channel_id=channel_id) - return self.request(route, json=payload) + return self.request(route, json=payload, reason=reason) def join_thread(self, channel_id: Snowflake) -> Response[None]: return self.request(Route('POST', '/channels/{channel_id}/thread-members/@me', channel_id=channel_id)) @@ -1237,12 +1235,12 @@ class HTTPClient: return self.request(r) - def delete_integration(self, guild_id: Snowflake, integration_id: Snowflake) -> Response[None]: + def delete_integration(self, guild_id: Snowflake, integration_id: Snowflake, *, reason: Optional[str] = None) -> Response[None]: r = Route( 'DELETE', '/guilds/{guild_id}/integrations/{integration_id}', guild_id=guild_id, integration_id=integration_id ) - return self.request(r) + return self.request(r, reason=reason) def get_audit_logs( self, @@ -1422,7 +1420,7 @@ class HTTPClient: def get_stage_instance(self, channel_id: Snowflake) -> Response[channel.StageInstance]: return self.request(Route('GET', '/stage-instances/{channel_id}', channel_id=channel_id)) - def create_stage_instance(self, **payload) -> Response[channel.StageInstance]: + def create_stage_instance(self, *, reason: Optional[str], **payload: Any) -> Response[channel.StageInstance]: valid_keys = ( 'channel_id', 'topic', @@ -1430,19 +1428,19 @@ class HTTPClient: ) payload = {k: v for k, v in payload.items() if k in valid_keys} - return self.request(Route('POST', '/stage-instances'), json=payload) + return self.request(Route('POST', '/stage-instances'), json=payload, reason=reason) - def edit_stage_instance(self, channel_id: Snowflake, **payload) -> Response[None]: + def edit_stage_instance(self, channel_id: Snowflake, *, reason: Optional[str] = None, **payload: Any) -> Response[None]: valid_keys = ( 'topic', 'privacy_level', ) payload = {k: v for k, v in payload.items() if k in valid_keys} - return self.request(Route('PATCH', '/stage-instances/{channel_id}', channel_id=channel_id), json=payload) + return self.request(Route('PATCH', '/stage-instances/{channel_id}', channel_id=channel_id), json=payload, reason=reason) - def delete_stage_instance(self, channel_id: Snowflake) -> Response[None]: - return self.request(Route('DELETE', '/stage-instances/{channel_id}', channel_id=channel_id)) + def delete_stage_instance(self, channel_id: Snowflake, *, reason: Optional[str] = None) -> Response[None]: + return self.request(Route('DELETE', '/stage-instances/{channel_id}', channel_id=channel_id), reason=reason) # Application commands (global) @@ -1571,9 +1569,9 @@ class HTTPClient: return self.request(r) def bulk_upsert_guild_commands( - self, + self, application_id: Snowflake, - guild_id: Snowflake, + guild_id: Snowflake, payload: List[interactions.EditApplicationCommand], ) -> Response[List[interactions.ApplicationCommand]]: r = Route( diff --git a/discord/integrations.py b/discord/integrations.py index e2d6e1166..fa1029bf0 100644 --- a/discord/integrations.py +++ b/discord/integrations.py @@ -127,7 +127,7 @@ class Integration: self.user = User(state=self._state, data=user) if user else None self.enabled: bool = data['enabled'] - async def delete(self) -> None: + async def delete(self, *, reason: Optional[str] = None) -> None: """|coro| Deletes the integration. @@ -135,6 +135,13 @@ class Integration: You must have the :attr:`~Permissions.manage_guild` permission to do this. + Parameters + ----------- + reason: :class:`str` + The reason the integration was deleted. Shows up on the audit log. + + .. versionadded:: 2.0 + Raises ------- Forbidden @@ -142,7 +149,7 @@ class Integration: HTTPException Deleting the integration failed. """ - await self._state.http.delete_integration(self.guild.id, self.id) + await self._state.http.delete_integration(self.guild.id, self.id, reason=reason) class StreamIntegration(Integration): diff --git a/discord/stage_instance.py b/discord/stage_instance.py index 338e5ddcf..cbb6df192 100644 --- a/discord/stage_instance.py +++ b/discord/stage_instance.py @@ -111,7 +111,7 @@ class StageInstance(Hashable): def is_public(self) -> bool: return self.privacy_level is StagePrivacyLevel.public - async def edit(self, *, topic: str = MISSING, privacy_level: StagePrivacyLevel = MISSING) -> None: + async def edit(self, *, topic: str = MISSING, privacy_level: StagePrivacyLevel = MISSING, reason: Optional[str] = None) -> None: """|coro| Edits the stage instance. @@ -125,6 +125,8 @@ class StageInstance(Hashable): The stage instance's new topic. privacy_level: :class:`StagePrivacyLevel` The stage instance's new privacy level. + reason: :class:`str` + The reason the stage instance was edited. Shows up on the audit log. Raises ------ @@ -148,9 +150,9 @@ class StageInstance(Hashable): payload['privacy_level'] = privacy_level.value if payload: - await self._state.http.edit_stage_instance(self.channel_id, **payload) + await self._state.http.edit_stage_instance(self.channel_id, **payload, reason=reason) - async def delete(self) -> None: + async def delete(self, *, reason: Optional[str] = None) -> None: """|coro| Deletes the stage instance. @@ -158,6 +160,11 @@ class StageInstance(Hashable): You must have the :attr:`~Permissions.manage_channels` permission to use this. + Parameters + ----------- + reason: :class:`str` + The reason the stage instance was deleted. Shows up on the audit log. + Raises ------ Forbidden @@ -165,4 +172,4 @@ class StageInstance(Hashable): HTTPException Deleting the stage instance failed. """ - await self._state.http.delete_stage_instance(self.channel_id) + await self._state.http.delete_stage_instance(self.channel_id, reason=reason)