mirror of
				https://github.com/Rapptz/discord.py.git
				synced 2025-10-25 02:23:04 +00:00 
			
		
		
		
	Add support for audit log reasons.
Most routes now have a 'reason' keyword argument.
This commit is contained in:
		| @@ -121,7 +121,7 @@ class GuildChannel: | |||||||
|         return self.name |         return self.name | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def _move(self, position): |     def _move(self, position, *, reason): | ||||||
|         if position < 0: |         if position < 0: | ||||||
|             raise InvalidArgument('Channel position cannot be less than 0.') |             raise InvalidArgument('Channel position cannot be less than 0.') | ||||||
|  |  | ||||||
| @@ -145,7 +145,7 @@ class GuildChannel: | |||||||
|             channels.insert(position, self) |             channels.insert(position, self) | ||||||
|  |  | ||||||
|         payload = [{'id': c.id, 'position': index } for index, c in enumerate(channels)] |         payload = [{'id': c.id, 'position': index } for index, c in enumerate(channels)] | ||||||
|         yield from http.move_channel_position(self.guild.id, payload) |         yield from http.move_channel_position(self.guild.id, payload, reason=reason) | ||||||
|  |  | ||||||
|     def _fill_overwrites(self, data): |     def _fill_overwrites(self, data): | ||||||
|         self._overwrites = [] |         self._overwrites = [] | ||||||
| @@ -351,13 +351,19 @@ class GuildChannel: | |||||||
|         return base |         return base | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def delete(self): |     def delete(self, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Deletes the channel. |         Deletes the channel. | ||||||
|  |  | ||||||
|         You must have Manage Channel permission to use this. |         You must have Manage Channel permission to use this. | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ----------- | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for deleting this channel. | ||||||
|  |             Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
|         Forbidden |         Forbidden | ||||||
| @@ -367,10 +373,10 @@ class GuildChannel: | |||||||
|         HTTPException |         HTTPException | ||||||
|             Deleting the channel failed. |             Deleting the channel failed. | ||||||
|         """ |         """ | ||||||
|         yield from self._state.http.delete_channel(self.id) |         yield from self._state.http.delete_channel(self.id, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def set_permissions(self, target, *, overwrite=_undefined, **permissions): |     def set_permissions(self, target, *, overwrite=_undefined, reason=None, **permissions): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Sets the channel specific permission overwrites for a target in the |         Sets the channel specific permission overwrites for a target in the | ||||||
| @@ -418,6 +424,8 @@ class GuildChannel: | |||||||
|         \*\*permissions |         \*\*permissions | ||||||
|             A keyword argument list of permissions to set for ease of use. |             A keyword argument list of permissions to set for ease of use. | ||||||
|             Cannot be mixed with ``overwrite``. |             Cannot be mixed with ``overwrite``. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for doing this action. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -453,15 +461,15 @@ class GuildChannel: | |||||||
|         # TODO: wait for event |         # TODO: wait for event | ||||||
|  |  | ||||||
|         if overwrite is None: |         if overwrite is None: | ||||||
|             yield from http.delete_channel_permissions(self.id, target.id) |             yield from http.delete_channel_permissions(self.id, target.id, reason=reason) | ||||||
|         elif isinstance(overwrite, PermissionOverwrite): |         elif isinstance(overwrite, PermissionOverwrite): | ||||||
|             (allow, deny) = overwrite.pair() |             (allow, deny) = overwrite.pair() | ||||||
|             yield from http.edit_channel_permissions(self.id, target.id, allow.value, deny.value, perm_type) |             yield from http.edit_channel_permissions(self.id, target.id, allow.value, deny.value, perm_type, reason=reason) | ||||||
|         else: |         else: | ||||||
|             raise InvalidArgument('Invalid overwrite type provided.') |             raise InvalidArgument('Invalid overwrite type provided.') | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def create_invite(self, **fields): |     def create_invite(self, *, reason=None, **fields): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Creates an instant invite. |         Creates an instant invite. | ||||||
| @@ -481,6 +489,8 @@ class GuildChannel: | |||||||
|             Indicates if a unique invite URL should be created. Defaults to True. |             Indicates if a unique invite URL should be created. Defaults to True. | ||||||
|             If this is set to False then it will return a previously created |             If this is set to False then it will return a previously created | ||||||
|             invite. |             invite. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for creating this invite. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -493,7 +503,7 @@ class GuildChannel: | |||||||
|             The invite that was created. |             The invite that was created. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         data = yield from self._state.http.create_invite(self.id, **fields) |         data = yield from self._state.http.create_invite(self.id, reason=reason, **fields) | ||||||
|         return Invite.from_incomplete(data=data, state=self._state) |         return Invite.from_incomplete(data=data, state=self._state) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
| @@ -537,7 +547,7 @@ class Messageable(metaclass=abc.ABCMeta): | |||||||
|         raise NotImplementedError |         raise NotImplementedError | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def send(self, content=None, *, tts=False, embed=None, file=None, files=None, delete_after=None): |     def send(self, content=None, *, tts=False, embed=None, file=None, files=None, reason=None, delete_after=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Sends a message to the destination with the content given. |         Sends a message to the destination with the content given. | ||||||
| @@ -571,6 +581,9 @@ class Messageable(metaclass=abc.ABCMeta): | |||||||
|             If provided, the number of seconds to wait in the background |             If provided, the number of seconds to wait in the background | ||||||
|             before deleting the message we just sent. If the deletion fails, |             before deleting the message we just sent. If the deletion fails, | ||||||
|             then it is silently ignored. |             then it is silently ignored. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for deleting the message, if necessary. | ||||||
|  |             Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         -------- |         -------- | ||||||
| @@ -626,7 +639,7 @@ class Messageable(metaclass=abc.ABCMeta): | |||||||
|             def delete(): |             def delete(): | ||||||
|                 yield from asyncio.sleep(delete_after, loop=state.loop) |                 yield from asyncio.sleep(delete_after, loop=state.loop) | ||||||
|                 try: |                 try: | ||||||
|                     yield from ret.delete() |                     yield from ret.delete(reason=reason) | ||||||
|                 except: |                 except: | ||||||
|                     pass |                     pass | ||||||
|             compat.create_task(delete(), loop=state.loop) |             compat.create_task(delete(), loop=state.loop) | ||||||
|   | |||||||
| @@ -37,9 +37,9 @@ import asyncio | |||||||
| __all__ = ('TextChannel', 'VoiceChannel', 'DMChannel', 'GroupChannel', '_channel_factory') | __all__ = ('TextChannel', 'VoiceChannel', 'DMChannel', 'GroupChannel', '_channel_factory') | ||||||
|  |  | ||||||
| @asyncio.coroutine | @asyncio.coroutine | ||||||
| def _single_delete_strategy(messages): | def _single_delete_strategy(messages, *, reason): | ||||||
|     for m in messages: |     for m in messages: | ||||||
|         yield from m.delete() |         yield from m.delete(reason=reason) | ||||||
|  |  | ||||||
| class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | ||||||
|     """Represents a Discord guild text channel. |     """Represents a Discord guild text channel. | ||||||
| @@ -116,7 +116,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | |||||||
|         return n == 'nsfw' or n[:5] == 'nsfw-' |         return n == 'nsfw' or n[:5] == 'nsfw-' | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def edit(self, **options): |     def edit(self, *, reason=None, **options): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Edits the channel. |         Edits the channel. | ||||||
| @@ -132,6 +132,8 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | |||||||
|             The new channel's topic. |             The new channel's topic. | ||||||
|         position: int |         position: int | ||||||
|             The new channel's position. |             The new channel's position. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for editing this channel. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------ |         ------ | ||||||
| @@ -147,15 +149,15 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | |||||||
|         except KeyError: |         except KeyError: | ||||||
|             pass |             pass | ||||||
|         else: |         else: | ||||||
|             yield from self._move(position) |             yield from self._move(position, reason=reason) | ||||||
|             self.position = position |             self.position = position | ||||||
|  |  | ||||||
|         if options: |         if options: | ||||||
|             data = yield from self._state.http.edit_channel(self.id, **options) |             data = yield from self._state.http.edit_channel(self.id, reason=reason, **options) | ||||||
|             self._update(self.guild, data) |             self._update(self.guild, data) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def delete_messages(self, messages): |     def delete_messages(self, messages, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Deletes a list of messages. This is similar to :meth:`Message.delete` |         Deletes a list of messages. This is similar to :meth:`Message.delete` | ||||||
| @@ -165,8 +167,10 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | |||||||
|  |  | ||||||
|         Parameters |         Parameters | ||||||
|         ----------- |         ----------- | ||||||
|         messages : iterable of :class:`Message` |         messages: iterable of :class:`Message` | ||||||
|             An iterable of messages denoting which ones to bulk delete. |             An iterable of messages denoting which ones to bulk delete. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for bulk deleting these messages. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------ |         ------ | ||||||
| @@ -186,10 +190,10 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | |||||||
|         message_ids = [m.id for m in messages] |         message_ids = [m.id for m in messages] | ||||||
|         channel = yield from self._get_channel() |         channel = yield from self._get_channel() | ||||||
|  |  | ||||||
|         yield from self._state.http.delete_messages(channel.id, message_ids) |         yield from self._state.http.delete_messages(channel.id, message_ids, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def purge(self, *, limit=100, check=None, before=None, after=None, around=None): |     def purge(self, *, limit=100, check=None, before=None, after=None, around=None, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Purges a list of messages that meet the criteria given by the predicate |         Purges a list of messages that meet the criteria given by the predicate | ||||||
| @@ -219,6 +223,8 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | |||||||
|             Same as ``after`` in :meth:`history`. |             Same as ``after`` in :meth:`history`. | ||||||
|         around |         around | ||||||
|             Same as ``around`` in :meth:`history`. |             Same as ``around`` in :meth:`history`. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for doing this action. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -262,17 +268,17 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | |||||||
|                 if count >= 2: |                 if count >= 2: | ||||||
|                     # more than 2 messages -> bulk delete |                     # more than 2 messages -> bulk delete | ||||||
|                     to_delete = ret[-count:] |                     to_delete = ret[-count:] | ||||||
|                     yield from strategy(to_delete) |                     yield from strategy(to_delete, reason=reason) | ||||||
|                 elif count == 1: |                 elif count == 1: | ||||||
|                     # delete a single message |                     # delete a single message | ||||||
|                     yield from ret[-1].delete() |                     yield from ret[-1].delete(reason=reason) | ||||||
|  |  | ||||||
|                 return ret |                 return ret | ||||||
|             else: |             else: | ||||||
|                 if count == 100: |                 if count == 100: | ||||||
|                     # we've reached a full 'queue' |                     # we've reached a full 'queue' | ||||||
|                     to_delete = ret[-100:] |                     to_delete = ret[-100:] | ||||||
|                     yield from strategy(to_delete) |                     yield from strategy(to_delete, reason=reason) | ||||||
|                     count = 0 |                     count = 0 | ||||||
|                     yield from asyncio.sleep(1) |                     yield from asyncio.sleep(1) | ||||||
|  |  | ||||||
| @@ -283,7 +289,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): | |||||||
|                             yield from ret[-1].delete() |                             yield from ret[-1].delete() | ||||||
|                         elif count >= 2: |                         elif count >= 2: | ||||||
|                             to_delete = ret[-count:] |                             to_delete = ret[-count:] | ||||||
|                             yield from strategy(to_delete) |                             yield from strategy(to_delete, reason=reason) | ||||||
|  |  | ||||||
|                         count = 0 |                         count = 0 | ||||||
|                         strategy = _single_delete_strategy |                         strategy = _single_delete_strategy | ||||||
| @@ -362,7 +368,7 @@ class VoiceChannel(discord.abc.Callable, discord.abc.GuildChannel, Hashable): | |||||||
|         return ret |         return ret | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def edit(self, **options): |     def edit(self, *, reason=None, **options): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Edits the channel. |         Edits the channel. | ||||||
| @@ -378,6 +384,8 @@ class VoiceChannel(discord.abc.Callable, discord.abc.GuildChannel, Hashable): | |||||||
|             The new channel's user limit. |             The new channel's user limit. | ||||||
|         position: int |         position: int | ||||||
|             The new channel's position. |             The new channel's position. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for editing this channel. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------ |         ------ | ||||||
| @@ -392,11 +400,11 @@ class VoiceChannel(discord.abc.Callable, discord.abc.GuildChannel, Hashable): | |||||||
|         except KeyError: |         except KeyError: | ||||||
|             pass |             pass | ||||||
|         else: |         else: | ||||||
|             yield from self._move(position) |             yield from self._move(position, reason=reason) | ||||||
|             self.position = position |             self.position = position | ||||||
|  |  | ||||||
|         if options: |         if options: | ||||||
|             data = yield from self._state.http.edit_channel(self.id, **options) |             data = yield from self._state.http.edit_channel(self.id, reason=reason, **options) | ||||||
|             self._update(self.guild, data) |             self._update(self.guild, data) | ||||||
|  |  | ||||||
| class DMChannel(discord.abc.Messageable, Hashable): | class DMChannel(discord.abc.Messageable, Hashable): | ||||||
|   | |||||||
| @@ -118,7 +118,7 @@ class Emoji(Hashable): | |||||||
|  |  | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def delete(self): |     def delete(self, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Deletes the custom emoji. |         Deletes the custom emoji. | ||||||
| @@ -128,6 +128,11 @@ class Emoji(Hashable): | |||||||
|  |  | ||||||
|         Guild local emotes can only be deleted by user bots. |         Guild local emotes can only be deleted by user bots. | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ----------- | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for deleting this emoji. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
|         Forbidden |         Forbidden | ||||||
| @@ -136,10 +141,10 @@ class Emoji(Hashable): | |||||||
|             An error occurred deleting the emoji. |             An error occurred deleting the emoji. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         yield from self._state.http.delete_custom_emoji(self.guild.id, self.id) |         yield from self._state.http.delete_custom_emoji(self.guild.id, self.id, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def edit(self, *, name): |     def edit(self, *, name, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Edits the custom emoji. |         Edits the custom emoji. | ||||||
| @@ -153,6 +158,8 @@ class Emoji(Hashable): | |||||||
|         ----------- |         ----------- | ||||||
|         name: str |         name: str | ||||||
|             The new emoji name. |             The new emoji name. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for editing this emoji. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -162,4 +169,4 @@ class Emoji(Hashable): | |||||||
|             An error occurred editing the emoji. |             An error occurred editing the emoji. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         yield from self._state.http.edit_custom_emoji(self.guild.id, self.id, name=name) |         yield from self._state.http.edit_custom_emoji(self.guild.id, self.id, name=name, reason=reason) | ||||||
|   | |||||||
| @@ -427,7 +427,7 @@ class Guild(Hashable): | |||||||
|  |  | ||||||
|         return utils.find(pred, members) |         return utils.find(pred, members) | ||||||
|  |  | ||||||
|     def _create_channel(self, name, overwrites, type): |     def _create_channel(self, name, overwrites, type, reason): | ||||||
|         if overwrites is None: |         if overwrites is None: | ||||||
|             overwrites = {} |             overwrites = {} | ||||||
|         elif not isinstance(overwrites, dict): |         elif not isinstance(overwrites, dict): | ||||||
| @@ -452,10 +452,10 @@ class Guild(Hashable): | |||||||
|  |  | ||||||
|             perms.append(payload) |             perms.append(payload) | ||||||
|  |  | ||||||
|         return self._state.http.create_channel(self.id, name, str(type), permission_overwrites=perms) |         return self._state.http.create_channel(self.id, name, str(type), permission_overwrites=perms, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def create_text_channel(self, name, *, overwrites=None): |     def create_text_channel(self, name, *, overwrites=None, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Creates a :class:`TextChannel` for the guild. |         Creates a :class:`TextChannel` for the guild. | ||||||
| @@ -495,6 +495,8 @@ class Guild(Hashable): | |||||||
|             A `dict` of target (either a role or a member) to |             A `dict` of target (either a role or a member) to | ||||||
|             :class:`PermissionOverwrite` to apply upon creation of a channel. |             :class:`PermissionOverwrite` to apply upon creation of a channel. | ||||||
|             Useful for creating secret channels. |             Useful for creating secret channels. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for creating this channel. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -510,17 +512,17 @@ class Guild(Hashable): | |||||||
|         :class:`TextChannel` |         :class:`TextChannel` | ||||||
|             The channel that was just created. |             The channel that was just created. | ||||||
|         """ |         """ | ||||||
|         data = yield from self._create_channel(name, overwrites, ChannelType.text) |         data = yield from self._create_channel(name, overwrites, ChannelType.text, reason=reason) | ||||||
|         return TextChannel(state=self._state, guild=self, data=data) |         return TextChannel(state=self._state, guild=self, data=data) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def create_voice_channel(self, name, *, overwrites=None): |     def create_voice_channel(self, name, *, overwrites=None, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Same as :meth:`create_text_channel` except makes a |         Same as :meth:`create_text_channel` except makes a | ||||||
|         :class:`VoiceChannel` instead. |         :class:`VoiceChannel` instead. | ||||||
|         """ |         """ | ||||||
|         data = yield from self._create_channel(name, overwrites, ChannelType.voice) |         data = yield from self._create_channel(name, overwrites, ChannelType.voice, reason=reason) | ||||||
|         return VoiceChannel(state=self._state, guild=self, data=data) |         return VoiceChannel(state=self._state, guild=self, data=data) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
| @@ -559,7 +561,7 @@ class Guild(Hashable): | |||||||
|         yield from self._state.http.delete_guild(self.id) |         yield from self._state.http.delete_guild(self.id) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def edit(self, **fields): |     def edit(self, *, reason=None, **fields): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Edits the guild. |         Edits the guild. | ||||||
| @@ -590,6 +592,8 @@ class Guild(Hashable): | |||||||
|             be owner of the guild to do this. |             be owner of the guild to do this. | ||||||
|         verification_level: :class:`VerificationLevel` |         verification_level: :class:`VerificationLevel` | ||||||
|             The new verification level for the guild. |             The new verification level for the guild. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for editing this guild. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -642,7 +646,8 @@ class Guild(Hashable): | |||||||
|             raise InvalidArgument('verification_level field must of type VerificationLevel') |             raise InvalidArgument('verification_level field must of type VerificationLevel') | ||||||
|  |  | ||||||
|         fields['verification_level'] = level.value |         fields['verification_level'] = level.value | ||||||
|         yield from self._state.http.edit_guild(self.id, **fields) |  | ||||||
|  |         yield from self._state.http.edit_guild(self.id, reason=reason, **fields) | ||||||
|  |  | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
| @@ -678,7 +683,7 @@ class Guild(Hashable): | |||||||
|                 for e in data] |                 for e in data] | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def prune_members(self, *, days): |     def prune_members(self, *, days, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Prunes the guild from its inactive members. |         Prunes the guild from its inactive members. | ||||||
| @@ -696,6 +701,8 @@ class Guild(Hashable): | |||||||
|         ----------- |         ----------- | ||||||
|         days: int |         days: int | ||||||
|             The number of days before counting as inactive. |             The number of days before counting as inactive. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for doing this action. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -715,7 +722,7 @@ class Guild(Hashable): | |||||||
|         if not isinstance(days, int): |         if not isinstance(days, int): | ||||||
|             raise InvalidArgument('Expected int for ``days``, received {0.__class__.__name__} instead.'.format(days)) |             raise InvalidArgument('Expected int for ``days``, received {0.__class__.__name__} instead.'.format(days)) | ||||||
|  |  | ||||||
|         data = yield from self._state.http.prune_members(self.id, days) |         data = yield from self._state.http.prune_members(self.id, days, reason=reason) | ||||||
|         return data['pruned'] |         return data['pruned'] | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
| @@ -784,7 +791,7 @@ class Guild(Hashable): | |||||||
|         return result |         return result | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def create_invite(self, **fields): |     def create_invite(self, *, reason=None, **fields): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Creates an instant invite. |         Creates an instant invite. | ||||||
| @@ -804,6 +811,8 @@ class Guild(Hashable): | |||||||
|             Indicates if a unique invite URL should be created. Defaults to True. |             Indicates if a unique invite URL should be created. Defaults to True. | ||||||
|             If this is set to False then it will return a previously created |             If this is set to False then it will return a previously created | ||||||
|             invite. |             invite. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for creating this invite. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -816,11 +825,11 @@ class Guild(Hashable): | |||||||
|             The invite that was created. |             The invite that was created. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         data = yield from self._state.http.create_invite(self.id, **fields) |         data = yield from self._state.http.create_invite(self.id, reason=reason, **fields) | ||||||
|         return Invite.from_incomplete(data=data, state=self._state) |         return Invite.from_incomplete(data=data, state=self._state) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def create_custom_emoji(self, *, name, image): |     def create_custom_emoji(self, *, name, image, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Creates a custom :class:`Emoji` for the guild. |         Creates a custom :class:`Emoji` for the guild. | ||||||
| @@ -839,6 +848,8 @@ class Guild(Hashable): | |||||||
|         image: bytes |         image: bytes | ||||||
|             The *bytes-like* object representing the image data to use. |             The *bytes-like* object representing the image data to use. | ||||||
|             Only JPG and PNG images are supported. |             Only JPG and PNG images are supported. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for creating this emoji. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Returns |         Returns | ||||||
|         -------- |         -------- | ||||||
| @@ -854,11 +865,11 @@ class Guild(Hashable): | |||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         img = utils._bytes_to_base64_data(image) |         img = utils._bytes_to_base64_data(image) | ||||||
|         data = yield from self._state.http.create_custom_emoji(self.id, name, img) |         data = yield from self._state.http.create_custom_emoji(self.id, name, img, reason=reason) | ||||||
|         return self._state.store_emoji(self, data) |         return self._state.store_emoji(self, data) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def create_role(self, **fields): |     def create_role(self, *, reason=None, **fields): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Creates a :class:`Role` for the guild. |         Creates a :class:`Role` for the guild. | ||||||
| @@ -880,6 +891,8 @@ class Guild(Hashable): | |||||||
|         mentionable: bool |         mentionable: bool | ||||||
|             Indicates if the role should be mentionable by others. |             Indicates if the role should be mentionable by others. | ||||||
|             Defaults to False. |             Defaults to False. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for creating this role. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Returns |         Returns | ||||||
|         -------- |         -------- | ||||||
| @@ -915,7 +928,7 @@ class Guild(Hashable): | |||||||
|             if key not in valid_keys: |             if key not in valid_keys: | ||||||
|                 raise InvalidArgument('%r is not a valid field.' % key) |                 raise InvalidArgument('%r is not a valid field.' % key) | ||||||
|  |  | ||||||
|         data = yield from self._state.http.create_role(self.id, **fields) |         data = yield from self._state.http.create_role(self.id, reason=reason, **fields) | ||||||
|         role = Role(guild=self, data=data, state=self._state) |         role = Role(guild=self, data=data, state=self._state) | ||||||
|  |  | ||||||
|         # TODO: add to cache |         # TODO: add to cache | ||||||
| @@ -979,7 +992,7 @@ class Guild(Hashable): | |||||||
|         yield from self._state.http.ban(user.id, self.id, delete_message_days, reason=reason) |         yield from self._state.http.ban(user.id, self.id, delete_message_days, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def unban(self, user): |     def unban(self, user, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Unbans a user from the guild. |         Unbans a user from the guild. | ||||||
| @@ -993,6 +1006,8 @@ class Guild(Hashable): | |||||||
|         ----------- |         ----------- | ||||||
|         user: :class:`abc.Snowflake` |         user: :class:`abc.Snowflake` | ||||||
|             The user to unban. |             The user to unban. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for doing this action. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -1001,7 +1016,7 @@ class Guild(Hashable): | |||||||
|         HTTPException |         HTTPException | ||||||
|             Unbanning failed. |             Unbanning failed. | ||||||
|         """ |         """ | ||||||
|         yield from self._state.http.unban(user.id, self.id) |         yield from self._state.http.unban(user.id, self.id, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def vanity_invite(self): |     def vanity_invite(self): | ||||||
| @@ -1038,7 +1053,7 @@ class Guild(Hashable): | |||||||
|         return Invite(state=self._state, data=payload) |         return Invite(state=self._state, data=payload) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def change_vanity_invite(self, new_code): |     def change_vanity_invite(self, new_code, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Changes the guild's special vanity invite. |         Changes the guild's special vanity invite. | ||||||
| @@ -1048,6 +1063,13 @@ class Guild(Hashable): | |||||||
|  |  | ||||||
|         You must have :attr:`Permissions.manage_guild` to use this as well. |         You must have :attr:`Permissions.manage_guild` to use this as well. | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ----------- | ||||||
|  |         new_code: str | ||||||
|  |             The new vanity URL code. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for changing the vanity invite. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
|         Forbidden |         Forbidden | ||||||
| @@ -1056,7 +1078,7 @@ class Guild(Hashable): | |||||||
|             Setting the vanity invite failed. |             Setting the vanity invite failed. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         yield from self._state.http.change_vanity_code(self.id, new_code) |         yield from self._state.http.change_vanity_code(self.id, new_code, reason=reason) | ||||||
|  |  | ||||||
|     def ack(self): |     def ack(self): | ||||||
|         """|coro| |         """|coro| | ||||||
|   | |||||||
							
								
								
									
										127
									
								
								discord/http.py
									
									
									
									
									
								
							
							
						
						
									
										127
									
								
								discord/http.py
									
									
									
									
									
								
							| @@ -125,6 +125,14 @@ class HTTPClient: | |||||||
|             headers['Content-Type'] = 'application/json' |             headers['Content-Type'] = 'application/json' | ||||||
|             kwargs['data'] = utils.to_json(kwargs.pop('json')) |             kwargs['data'] = utils.to_json(kwargs.pop('json')) | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             reason = kwargs.pop('reason') | ||||||
|  |         except KeyError: | ||||||
|  |             pass | ||||||
|  |         else: | ||||||
|  |             if reason: | ||||||
|  |                 headers['X-Audit-Log-Reason'] = reason | ||||||
|  |  | ||||||
|         kwargs['headers'] = headers |         kwargs['headers'] = headers | ||||||
|  |  | ||||||
|         if not self._global_over.is_set(): |         if not self._global_over.is_set(): | ||||||
| @@ -336,18 +344,18 @@ class HTTPClient: | |||||||
|     def ack_guild(self, guild_id): |     def ack_guild(self, guild_id): | ||||||
|         return self.request(Route('POST', '/guilds/{guild_id}/ack', guild_id=guild_id)) |         return self.request(Route('POST', '/guilds/{guild_id}/ack', guild_id=guild_id)) | ||||||
|  |  | ||||||
|     def delete_message(self, channel_id, message_id): |     def delete_message(self, channel_id, message_id, *, reason=None): | ||||||
|         r = Route('DELETE', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, |         r = Route('DELETE', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, | ||||||
|                                                                             message_id=message_id) |                                                                             message_id=message_id) | ||||||
|         return self.request(r) |         return self.request(r, reason=reason) | ||||||
|  |  | ||||||
|     def delete_messages(self, channel_id, message_ids): |     def delete_messages(self, channel_id, message_ids, *, reason=None): | ||||||
|         r = Route('POST', '/channels/{channel_id}/messages/bulk_delete', channel_id=channel_id) |         r = Route('POST', '/channels/{channel_id}/messages/bulk_delete', channel_id=channel_id) | ||||||
|         payload = { |         payload = { | ||||||
|             'messages': message_ids |             'messages': message_ids | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return self.request(r, json=payload) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def edit_message(self, message_id, channel_id, **fields): |     def edit_message(self, message_id, channel_id, **fields): | ||||||
|         r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, |         r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, | ||||||
| @@ -426,11 +434,11 @@ class HTTPClient: | |||||||
|  |  | ||||||
|         return self.request(r, params=params) |         return self.request(r, params=params) | ||||||
|  |  | ||||||
|     def unban(self, user_id, guild_id): |     def unban(self, user_id, guild_id, *, reason=None): | ||||||
|         r = Route('DELETE', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id) |         r = Route('DELETE', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id) | ||||||
|         return self.request(r) |         return self.request(r, reason=reason) | ||||||
|  |  | ||||||
|     def guild_voice_state(self, user_id, guild_id, *, mute=None, deafen=None): |     def guild_voice_state(self, user_id, guild_id, *, mute=None, deafen=None, reason=None): | ||||||
|         r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) |         r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) | ||||||
|         payload = {} |         payload = {} | ||||||
|         if mute is not None: |         if mute is not None: | ||||||
| @@ -439,7 +447,7 @@ class HTTPClient: | |||||||
|         if deafen is not None: |         if deafen is not None: | ||||||
|             payload['deaf'] = deafen |             payload['deaf'] = deafen | ||||||
|  |  | ||||||
|         return self.request(r, json=payload) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def edit_profile(self, password, username, avatar, **fields): |     def edit_profile(self, password, username, avatar, **fields): | ||||||
|         payload = { |         payload = { | ||||||
| @@ -456,38 +464,40 @@ class HTTPClient: | |||||||
|  |  | ||||||
|         return self.request(Route('PATCH', '/users/@me'), json=payload) |         return self.request(Route('PATCH', '/users/@me'), json=payload) | ||||||
|  |  | ||||||
|     def change_my_nickname(self, guild_id, nickname): |     def change_my_nickname(self, guild_id, nickname, *, reason=None): | ||||||
|  |         r = Route('PATCH', '/guilds/{guild_id}/members/@me/nick', guild_id=guild_id) | ||||||
|         payload = { |         payload = { | ||||||
|             'nick': nickname |             'nick': nickname | ||||||
|         } |         } | ||||||
|         return self.request(Route('PATCH', '/guilds/{guild_id}/members/@me/nick', guild_id=guild_id), json=payload) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def change_nickname(self, guild_id, user_id, nickname): |     def change_nickname(self, guild_id, user_id, nickname, *, reason=None): | ||||||
|         r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) |         r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) | ||||||
|         payload = { |         payload = { | ||||||
|             'nick': nickname |             'nick': nickname | ||||||
|         } |         } | ||||||
|         return self.request(r, json=payload) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def edit_member(self, guild_id, user_id, **fields): |     def edit_member(self, guild_id, user_id, *, reason=None, **fields): | ||||||
|         r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) |         r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) | ||||||
|         return self.request(r, json=fields) |         return self.request(r, json=fields, reason=reason) | ||||||
|  |  | ||||||
|     # Channel management |     # Channel management | ||||||
|  |  | ||||||
|     def edit_channel(self, channel_id, **options): |     def edit_channel(self, channel_id, *, reason=None, **options): | ||||||
|  |         r = Route('PATCH', '/channels/{channel_id}', channel_id=channel_id) | ||||||
|         valid_keys = ('name', 'topic', 'bitrate', 'user_limit', 'position') |         valid_keys = ('name', 'topic', 'bitrate', 'user_limit', 'position') | ||||||
|         payload = { |         payload = { | ||||||
|             k: v for k, v in options.items() if k in valid_keys |             k: v for k, v in options.items() if k in valid_keys | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return self.request(Route('PATCH', '/channels/{channel_id}', channel_id=channel_id), json=payload) |         return self.request(r, reason=reason, json=payload) | ||||||
|  |  | ||||||
|     def move_channel_position(self, guild_id, positions): |     def move_channel_position(self, guild_id, positions, *, reason=None): | ||||||
|         r = Route('PATCH', '/guilds/{guild_id}/channels', guild_id=guild_id) |         r = Route('PATCH', '/guilds/{guild_id}/channels', guild_id=guild_id) | ||||||
|         return self.request(r, json=positions) |         return self.request(r, json=positions, reason=reason) | ||||||
|  |  | ||||||
|     def create_channel(self, guild_id, name, channe_type, permission_overwrites=None): |     def create_channel(self, guild_id, name, channe_type, permission_overwrites=None, *, reason=None): | ||||||
|         payload = { |         payload = { | ||||||
|             'name': name, |             'name': name, | ||||||
|             'type': channe_type |             'type': channe_type | ||||||
| @@ -496,10 +506,10 @@ class HTTPClient: | |||||||
|         if permission_overwrites is not None: |         if permission_overwrites is not None: | ||||||
|             payload['permission_overwrites'] = permission_overwrites |             payload['permission_overwrites'] = permission_overwrites | ||||||
|  |  | ||||||
|         return self.request(Route('POST', '/guilds/{guild_id}/channels', guild_id=guild_id), json=payload) |         return self.request(Route('POST', '/guilds/{guild_id}/channels', guild_id=guild_id), json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def delete_channel(self, channel_id): |     def delete_channel(self, channel_id, *, reason=None): | ||||||
|         return self.request(Route('DELETE', '/channels/{channel_id}', channel_id=channel_id)) |         return self.request(Route('DELETE', '/channels/{channel_id}', channel_id=channel_id), reason=reason) | ||||||
|  |  | ||||||
|     # Guild management |     # Guild management | ||||||
|  |  | ||||||
| @@ -518,7 +528,7 @@ class HTTPClient: | |||||||
|  |  | ||||||
|         return self.request(Route('POST', '/guilds'), json=payload) |         return self.request(Route('POST', '/guilds'), json=payload) | ||||||
|  |  | ||||||
|     def edit_guild(self, guild_id, **fields): |     def edit_guild(self, guild_id, *, reason=None, **fields): | ||||||
|         valid_keys = ('name', 'region', 'icon', 'afk_timeout', 'owner_id', |         valid_keys = ('name', 'region', 'icon', 'afk_timeout', 'owner_id', | ||||||
|                       'afk_channel_id', 'splash', 'verification_level') |                       'afk_channel_id', 'splash', 'verification_level') | ||||||
|  |  | ||||||
| @@ -526,7 +536,7 @@ class HTTPClient: | |||||||
|             k: v for k, v in fields.items() if k in valid_keys |             k: v for k, v in fields.items() if k in valid_keys | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return self.request(Route('PATCH', '/guilds/{guild_id}', guild_id=guild_id), json=payload) |         return self.request(Route('PATCH', '/guilds/{guild_id}', guild_id=guild_id), json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def get_bans(self, guild_id): |     def get_bans(self, guild_id): | ||||||
|         return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id)) |         return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id)) | ||||||
| @@ -534,15 +544,15 @@ class HTTPClient: | |||||||
|     def get_vanity_code(self, guild_id): |     def get_vanity_code(self, guild_id): | ||||||
|         return self.request(Route('GET', '/guilds/{guild_id}/vanity-url', guild_id=guild_id)) |         return self.request(Route('GET', '/guilds/{guild_id}/vanity-url', guild_id=guild_id)) | ||||||
|  |  | ||||||
|     def change_vanity_code(self, guild_id, code): |     def change_vanity_code(self, guild_id, code, *, reason=None): | ||||||
|         payload = { 'code': code } |         payload = { 'code': code } | ||||||
|         return self.request(Route('PATCH', '/guilds/{guild_id}/vanity-url', guild_id=guild_id), json=payload) |         return self.request(Route('PATCH', '/guilds/{guild_id}/vanity-url', guild_id=guild_id), json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def prune_members(self, guild_id, days): |     def prune_members(self, guild_id, days, *, reason=None): | ||||||
|         params = { |         params = { | ||||||
|             'days': days |             'days': days | ||||||
|         } |         } | ||||||
|         return self.request(Route('POST', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params) |         return self.request(Route('POST', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params, reason=reason) | ||||||
|  |  | ||||||
|     def estimate_pruned_members(self, guild_id, days): |     def estimate_pruned_members(self, guild_id, days): | ||||||
|         params = { |         params = { | ||||||
| @@ -550,24 +560,25 @@ class HTTPClient: | |||||||
|         } |         } | ||||||
|         return self.request(Route('GET', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params) |         return self.request(Route('GET', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params) | ||||||
|  |  | ||||||
|     def create_custom_emoji(self, guild_id, name, image): |     def create_custom_emoji(self, guild_id, name, image, *, reason=None): | ||||||
|         payload = { |         payload = { | ||||||
|             'name': name, |             'name': name, | ||||||
|             'image': image |             'image': image | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         r = Route('POST', '/guilds/{guild_id}/emojis', guild_id=guild_id) |         r = Route('POST', '/guilds/{guild_id}/emojis', guild_id=guild_id) | ||||||
|         return self.request(r, json=payload) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def delete_custom_emoji(self, guild_id, emoji_id): |     def delete_custom_emoji(self, guild_id, emoji_id, *, reason=None): | ||||||
|         return self.request(Route('DELETE', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id)) |         r = Route('DELETE', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id) | ||||||
|  |         return self.request(r, reason=reason) | ||||||
|  |  | ||||||
|     def edit_custom_emoji(self, guild_id, emoji_id, *, name): |     def edit_custom_emoji(self, guild_id, emoji_id, *, name, reason=None): | ||||||
|         payload = { |         payload = { | ||||||
|             'name': name |             'name': name | ||||||
|         } |         } | ||||||
|         r = Route('PATCH', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id) |         r = Route('PATCH', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id) | ||||||
|         return self.request(r, json=payload) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def get_audit_logs(self, guild_id, limit=100, before=None, after=None, user_id=None, action_type=None): |     def get_audit_logs(self, guild_id, limit=100, before=None, after=None, user_id=None, action_type=None): | ||||||
|         params = { 'limit': limit } |         params = { 'limit': limit } | ||||||
| @@ -585,7 +596,7 @@ class HTTPClient: | |||||||
|  |  | ||||||
|     # Invite management |     # Invite management | ||||||
|  |  | ||||||
|     def create_invite(self, channel_id, **options): |     def create_invite(self, channel_id, *, reason=None, **options): | ||||||
|         r = Route('POST', '/channels/{channel_id}/invites', channel_id=channel_id) |         r = Route('POST', '/channels/{channel_id}/invites', channel_id=channel_id) | ||||||
|         payload = { |         payload = { | ||||||
|             'max_age': options.get('max_age', 0), |             'max_age': options.get('max_age', 0), | ||||||
| @@ -594,7 +605,7 @@ class HTTPClient: | |||||||
|             'unique': options.get('unique', True) |             'unique': options.get('unique', True) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return self.request(r, json=payload) |         return self.request(r, reason=reason, json=payload) | ||||||
|  |  | ||||||
|     def get_invite(self, invite_id): |     def get_invite(self, invite_id): | ||||||
|         return self.request(Route('GET', '/invite/{invite_id}', invite_id=invite_id)) |         return self.request(Route('GET', '/invite/{invite_id}', invite_id=invite_id)) | ||||||
| @@ -605,45 +616,45 @@ class HTTPClient: | |||||||
|     def invites_from_channel(self, channel_id): |     def invites_from_channel(self, channel_id): | ||||||
|         return self.request(Route('GET', '/channels/{channel_id}/invites', channel_id=channel_id)) |         return self.request(Route('GET', '/channels/{channel_id}/invites', channel_id=channel_id)) | ||||||
|  |  | ||||||
|     def delete_invite(self, invite_id): |     def delete_invite(self, invite_id, *, reason=None): | ||||||
|         return self.request(Route('DELETE', '/invite/{invite_id}', invite_id=invite_id)) |         return self.request(Route('DELETE', '/invite/{invite_id}', invite_id=invite_id), reason=reason) | ||||||
|  |  | ||||||
|     # Role management |     # Role management | ||||||
|  |  | ||||||
|     def edit_role(self, guild_id, role_id, **fields): |     def edit_role(self, guild_id, role_id, *, reason=None, **fields): | ||||||
|         r = Route('PATCH', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) |         r = Route('PATCH', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) | ||||||
|         valid_keys = ('name', 'permissions', 'color', 'hoist', 'mentionable') |         valid_keys = ('name', 'permissions', 'color', 'hoist', 'mentionable') | ||||||
|         payload = { |         payload = { | ||||||
|             k: v for k, v in fields.items() if k in valid_keys |             k: v for k, v in fields.items() if k in valid_keys | ||||||
|         } |         } | ||||||
|         return self.request(r, json=payload) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def delete_role(self, guild_id, role_id): |     def delete_role(self, guild_id, role_id, *, reason=None): | ||||||
|         r = Route('DELETE', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) |         r = Route('DELETE', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) | ||||||
|         return self.request(r) |         return self.request(r, reason=reason) | ||||||
|  |  | ||||||
|     def replace_roles(self, user_id, guild_id, role_ids): |     def replace_roles(self, user_id, guild_id, role_ids, *, reason=None): | ||||||
|         return self.edit_member(guild_id=guild_id, user_id=user_id, roles=role_ids) |         return self.edit_member(guild_id=guild_id, user_id=user_id, roles=role_ids, reason=reason) | ||||||
|  |  | ||||||
|     def create_role(self, guild_id, **fields): |     def create_role(self, guild_id, *, reason=None, **fields): | ||||||
|         r = Route('POST', '/guilds/{guild_id}/roles', guild_id=guild_id) |         r = Route('POST', '/guilds/{guild_id}/roles', guild_id=guild_id) | ||||||
|         return self.request(r, json=fields) |         return self.request(r, json=fields, reason=reason) | ||||||
|  |  | ||||||
|     def move_role_position(self, guild_id, positions): |     def move_role_position(self, guild_id, positions, *, reason=None): | ||||||
|         r = Route('PATCH', '/guilds/{guild_id}/roles', guild_id=guild_id) |         r = Route('PATCH', '/guilds/{guild_id}/roles', guild_id=guild_id) | ||||||
|         return self.request(r, json=positions) |         return self.request(r, json=positions, reason=reason) | ||||||
|  |  | ||||||
|     def add_role(self, guild_id, user_id, role_id): |     def add_role(self, guild_id, user_id, role_id, *, reason=None): | ||||||
|         r = Route('PUT', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}', |         r = Route('PUT', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}', | ||||||
|                   guild_id=guild_id, user_id=user_id, role_id=role_id) |                   guild_id=guild_id, user_id=user_id, role_id=role_id) | ||||||
|         return self.request(r) |         return self.request(r, reason=reason) | ||||||
|  |  | ||||||
|     def remove_role(self, guild_id, user_id, role_id): |     def remove_role(self, guild_id, user_id, role_id, *, reason=None): | ||||||
|         r = Route('DELETE', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}', |         r = Route('DELETE', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}', | ||||||
|                   guild_id=guild_id, user_id=user_id, role_id=role_id) |                   guild_id=guild_id, user_id=user_id, role_id=role_id) | ||||||
|         return self.request(r) |         return self.request(r, reason=reason) | ||||||
|  |  | ||||||
|     def edit_channel_permissions(self, channel_id, target, allow, deny, type): |     def edit_channel_permissions(self, channel_id, target, allow, deny, type, *, reason=None): | ||||||
|         payload = { |         payload = { | ||||||
|             'id': target, |             'id': target, | ||||||
|             'allow': allow, |             'allow': allow, | ||||||
| @@ -651,16 +662,16 @@ class HTTPClient: | |||||||
|             'type': type |             'type': type | ||||||
|         } |         } | ||||||
|         r = Route('PUT', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target) |         r = Route('PUT', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target) | ||||||
|         return self.request(r, json=payload) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|     def delete_channel_permissions(self, channel_id, target): |     def delete_channel_permissions(self, channel_id, target, *, reason=None): | ||||||
|         r = Route('DELETE', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target) |         r = Route('DELETE', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target) | ||||||
|         return self.request(r) |         return self.request(r, reason=reason) | ||||||
|  |  | ||||||
|     # Voice management |     # Voice management | ||||||
|  |  | ||||||
|     def move_member(self, user_id, guild_id, channel_id): |     def move_member(self, user_id, guild_id, channel_id, *, reason=None): | ||||||
|         return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id) |         return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason) | ||||||
|  |  | ||||||
|  |  | ||||||
|     # Relationship related |     # Relationship related | ||||||
|   | |||||||
| @@ -147,11 +147,16 @@ class Invite(Hashable): | |||||||
|         yield from self._state.http.accept_invite(self.code) |         yield from self._state.http.accept_invite(self.code) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def delete(self): |     def delete(self, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Revokes the instant invite. |         Revokes the instant invite. | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ----------- | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for deleting this invite. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
|         Forbidden |         Forbidden | ||||||
| @@ -162,4 +167,4 @@ class Invite(Hashable): | |||||||
|             Revoking the invite failed. |             Revoking the invite failed. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         yield from self._state.http.delete_invite(self.code) |         yield from self._state.http.delete_invite(self.code, reason=reason) | ||||||
|   | |||||||
| @@ -349,12 +349,12 @@ class Member(discord.abc.Messageable): | |||||||
|         yield from self.guild.ban(self, **kwargs) |         yield from self.guild.ban(self, **kwargs) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def unban(self): |     def unban(self, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Unbans this member. Equivalent to :meth:`Guild.unban` |         Unbans this member. Equivalent to :meth:`Guild.unban` | ||||||
|         """ |         """ | ||||||
|         yield from self.guild.unban(self) |         yield from self.guild.unban(self, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def kick(self, *, reason=None): |     def kick(self, *, reason=None): | ||||||
| @@ -365,7 +365,7 @@ class Member(discord.abc.Messageable): | |||||||
|         yield from self.guild.kick(self, reason=reason) |         yield from self.guild.kick(self, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def edit(self, **fields): |     def edit(self, *, reason=None, **fields): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Edits the member's data. |         Edits the member's data. | ||||||
| @@ -400,6 +400,8 @@ class Member(discord.abc.Messageable): | |||||||
|             The member's new list of roles. This *replaces* the roles. |             The member's new list of roles. This *replaces* the roles. | ||||||
|         voice_channel: :class:`VoiceChannel` |         voice_channel: :class:`VoiceChannel` | ||||||
|             The voice channel to move the member to. |             The voice channel to move the member to. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for editing this member. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -420,7 +422,7 @@ class Member(discord.abc.Messageable): | |||||||
|         else: |         else: | ||||||
|             nick = nick if nick else '' |             nick = nick if nick else '' | ||||||
|             if self._state.self_id == self.id: |             if self._state.self_id == self.id: | ||||||
|                 yield from http.change_my_nickname(guild_id, nick) |                 yield from http.change_my_nickname(guild_id, nick, reason=reason) | ||||||
|             else: |             else: | ||||||
|                 payload['nick'] = nick |                 payload['nick'] = nick | ||||||
|  |  | ||||||
| @@ -446,12 +448,12 @@ class Member(discord.abc.Messageable): | |||||||
|         else: |         else: | ||||||
|             payload['roles'] = tuple(r.id for r in roles) |             payload['roles'] = tuple(r.id for r in roles) | ||||||
|  |  | ||||||
|         yield from http.edit_member(guild_id, self.id, **payload) |         yield from http.edit_member(guild_id, self.id, reason=reason, **payload) | ||||||
|  |  | ||||||
|         # TODO: wait for WS event for modify-in-place behaviour |         # TODO: wait for WS event for modify-in-place behaviour | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def move_to(self, channel): |     def move_to(self, channel, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Moves a member to a new voice channel (they must be connected first). |         Moves a member to a new voice channel (they must be connected first). | ||||||
| @@ -465,11 +467,13 @@ class Member(discord.abc.Messageable): | |||||||
|         ----------- |         ----------- | ||||||
|         channel: :class:`VoiceChannel` |         channel: :class:`VoiceChannel` | ||||||
|             The new voice channel to move the member to. |             The new voice channel to move the member to. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for doing this action. Shows up on the audit log. | ||||||
|         """ |         """ | ||||||
|         yield from self.edit(voice_channel=channel) |         yield from self.edit(voice_channel=channel, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def add_roles(self, *roles): |     def add_roles(self, *roles, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Gives the member a number of :class:`Role`\s. |         Gives the member a number of :class:`Role`\s. | ||||||
| @@ -481,6 +485,8 @@ class Member(discord.abc.Messageable): | |||||||
|         ----------- |         ----------- | ||||||
|         \*roles |         \*roles | ||||||
|             An argument list of :class:`Role`\s to give the member. |             An argument list of :class:`Role`\s to give the member. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for adding these roles. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -491,10 +497,10 @@ class Member(discord.abc.Messageable): | |||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         new_roles = utils._unique(r for s in (self.roles[1:], roles) for r in s) |         new_roles = utils._unique(r for s in (self.roles[1:], roles) for r in s) | ||||||
|         yield from self.edit(roles=new_roles) |         yield from self.edit(roles=new_roles, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def remove_roles(self, *roles): |     def remove_roles(self, *roles, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Removes :class:`Role`\s from this member. |         Removes :class:`Role`\s from this member. | ||||||
| @@ -506,6 +512,8 @@ class Member(discord.abc.Messageable): | |||||||
|         ----------- |         ----------- | ||||||
|         \*roles |         \*roles | ||||||
|             An argument list of :class:`Role`\s to remove from the member. |             An argument list of :class:`Role`\s to remove from the member. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for removing these roles. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -522,4 +530,4 @@ class Member(discord.abc.Messageable): | |||||||
|             except ValueError: |             except ValueError: | ||||||
|                 pass |                 pass | ||||||
|  |  | ||||||
|         yield from self.edit(roles=new_roles) |         yield from self.edit(roles=new_roles, reason=reason) | ||||||
|   | |||||||
| @@ -407,7 +407,7 @@ class Message: | |||||||
|                 return '{0.author.name} started a call \N{EM DASH} Join the call.'.format(self) |                 return '{0.author.name} started a call \N{EM DASH} Join the call.'.format(self) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def delete(self): |     def delete(self, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Deletes the message. |         Deletes the message. | ||||||
| @@ -416,6 +416,11 @@ class Message: | |||||||
|         delete other people's messages, you need the :attr:`Permissions.manage_messages` |         delete other people's messages, you need the :attr:`Permissions.manage_messages` | ||||||
|         permission. |         permission. | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ------------ | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for deleting this message. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------ |         ------ | ||||||
|         Forbidden |         Forbidden | ||||||
| @@ -423,7 +428,7 @@ class Message: | |||||||
|         HTTPException |         HTTPException | ||||||
|             Deleting the message failed. |             Deleting the message failed. | ||||||
|         """ |         """ | ||||||
|         yield from self._state.http.delete_message(self.channel.id, self.id) |         yield from self._state.http.delete_message(self.channel.id, self.id, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def edit(self, **fields): |     def edit(self, **fields): | ||||||
|   | |||||||
| @@ -160,7 +160,7 @@ class Role(Hashable): | |||||||
|         return [member for member in all_members if self in member.roles] |         return [member for member in all_members if self in member.roles] | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def _move(self, position): |     def _move(self, position, reason): | ||||||
|         if position <= 0: |         if position <= 0: | ||||||
|             raise InvalidArgument("Cannot move role to position 0 or below") |             raise InvalidArgument("Cannot move role to position 0 or below") | ||||||
|  |  | ||||||
| @@ -184,10 +184,10 @@ class Role(Hashable): | |||||||
|             roles.append(self.id) |             roles.append(self.id) | ||||||
|  |  | ||||||
|         payload = [{"id": z[0], "position": z[1]} for z in zip(roles, change_range)] |         payload = [{"id": z[0], "position": z[1]} for z in zip(roles, change_range)] | ||||||
|         yield from http.move_role_position(self.guild.id, payload) |         yield from http.move_role_position(self.guild.id, payload, reason=reason) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def edit(self, **fields): |     def edit(self, *, reason=None, **fields): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Edits the role. |         Edits the role. | ||||||
| @@ -212,6 +212,8 @@ class Role(Hashable): | |||||||
|         position: int |         position: int | ||||||
|             The new role's position. This must be below your top role's |             The new role's position. This must be below your top role's | ||||||
|             position or it will fail. |             position or it will fail. | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for editing this role. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         ------- |         ------- | ||||||
| @@ -226,7 +228,7 @@ class Role(Hashable): | |||||||
|  |  | ||||||
|         position = fields.get('position') |         position = fields.get('position') | ||||||
|         if position is not None: |         if position is not None: | ||||||
|             yield from self._move(position) |             yield from self._move(position, reason=reason) | ||||||
|             self.position = position |             self.position = position | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
| @@ -242,11 +244,11 @@ class Role(Hashable): | |||||||
|             'mentionable': fields.get('mentionable', self.mentionable) |             'mentionable': fields.get('mentionable', self.mentionable) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         data = yield from self._state.http.edit_role(self.guild.id, self.id, **payload) |         data = yield from self._state.http.edit_role(self.guild.id, self.id, reason=reason, **payload) | ||||||
|         self._update(data) |         self._update(data) | ||||||
|  |  | ||||||
|     @asyncio.coroutine |     @asyncio.coroutine | ||||||
|     def delete(self): |     def delete(self, *, reason=None): | ||||||
|         """|coro| |         """|coro| | ||||||
|  |  | ||||||
|         Deletes the role. |         Deletes the role. | ||||||
| @@ -254,6 +256,11 @@ class Role(Hashable): | |||||||
|         You must have the :attr:`Permissions.manage_roles` permission to |         You must have the :attr:`Permissions.manage_roles` permission to | ||||||
|         use this. |         use this. | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ----------- | ||||||
|  |         reason: Optional[str] | ||||||
|  |             The reason for deleting this role. Shows up on the audit log. | ||||||
|  |  | ||||||
|         Raises |         Raises | ||||||
|         -------- |         -------- | ||||||
|         Forbidden |         Forbidden | ||||||
| @@ -262,4 +269,4 @@ class Role(Hashable): | |||||||
|             Deleting the role failed. |             Deleting the role failed. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         yield from self._state.http.delete_role(self.guild.id, self.id) |         yield from self._state.http.delete_role(self.guild.id, self.id, reason=reason) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user