From 2869d8000dabaa0b1e0421c26d8ee5b76d2f382c Mon Sep 17 00:00:00 2001 From: Rapptz Date: Thu, 12 Jan 2023 18:16:36 -0500 Subject: [PATCH] Add support for on_audit_log_entry_create event --- discord/audit_logs.py | 8 ++++++-- discord/flags.py | 14 ++++++++++++-- discord/state.py | 18 ++++++++++++++++++ discord/types/gateway.py | 5 +++++ docs/api.rst | 26 ++++++++++++++++++++++++-- 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/discord/audit_logs.py b/discord/audit_logs.py index f1520d352..165b4213a 100644 --- a/discord/audit_logs.py +++ b/discord/audit_logs.py @@ -544,6 +544,10 @@ class AuditLogEntry(Hashable): user: :class:`abc.User` The user who initiated this action. Usually a :class:`Member`\, unless gone then it's a :class:`User`. + user_id: :class:`int` + The user ID who initiated this action. + + .. versionadded:: 2.2 id: :class:`int` The entry ID. target: Any @@ -666,8 +670,8 @@ class AuditLogEntry(Hashable): # into meaningful data when requested self._changes = data.get('changes', []) - user_id = utils._get_as_snowflake(data, 'user_id') - self.user: Optional[Union[User, Member]] = self._get_member(user_id) + self.user_id = utils._get_as_snowflake(data, 'user_id') + self.user: Optional[Union[User, Member]] = self._get_member(self.user_id) self._target_id = utils._get_as_snowflake(data, 'target_id') def _get_member(self, user_id: Optional[int]) -> Union[Member, User, None]: diff --git a/discord/flags.py b/discord/flags.py index a886ca735..ed5b92fe3 100644 --- a/discord/flags.py +++ b/discord/flags.py @@ -777,18 +777,28 @@ class Intents(BaseFlags): return 1 << 1 @flag_value - def bans(self): - """:class:`bool`: Whether guild ban related events are enabled. + def moderation(self): + """:class:`bool`: Whether guild moderation related events are enabled. This corresponds to the following events: - :func:`on_member_ban` - :func:`on_member_unban` + - :func:`on_audit_log_entry_create` This does not correspond to any attributes or classes in the library in terms of cache. """ return 1 << 2 + @alias_flag_value + def bans(self): + """:class:`bool`: An alias of :attr:`moderation`. + + .. versionchanged:: 2.2 + Changed to an alias. + """ + return 1 << 2 + @flag_value def emojis(self): """:class:`bool`: Alias of :attr:`.emojis_and_stickers`. diff --git a/discord/state.py b/discord/state.py index 94d2cfa97..24eb70301 100644 --- a/discord/state.py +++ b/discord/state.py @@ -74,6 +74,7 @@ from .stage_instance import StageInstance from .threads import Thread, ThreadMember from .sticker import GuildSticker from .automod import AutoModRule, AutoModAction +from .audit_logs import AuditLogEntry if TYPE_CHECKING: from .abc import PrivateChannel @@ -1096,6 +1097,23 @@ class ConnectionState: guild.stickers = tuple(map(lambda d: self.store_sticker(guild, d), data['stickers'])) self.dispatch('guild_stickers_update', guild, before_stickers, guild.stickers) + def parse_guild_audit_log_entry_create(self, data: gw.GuildAuditLogEntryCreate) -> None: + guild = self._get_guild(int(data['guild_id'])) + if guild is None: + _log.debug('GUILD_AUDIT_LOG_ENTRY_CREATE referencing an unknown guild ID: %s. Discarding.', data['guild_id']) + return + + entry = AuditLogEntry( + users=self._users, # type: ignore + integrations={}, + app_commands={}, + automod_rules={}, + data=data, + guild=guild, + ) + + self.dispatch('audit_log_entry_create', entry) + def parse_auto_moderation_rule_create(self, data: AutoModerationRule) -> None: guild = self._get_guild(int(data['guild_id'])) if guild is None: diff --git a/discord/types/gateway.py b/discord/types/gateway.py index f5b9fbdfc..d0be80f6f 100644 --- a/discord/types/gateway.py +++ b/discord/types/gateway.py @@ -43,6 +43,7 @@ from .guild import Guild, UnavailableGuild from .user import User from .threads import Thread, ThreadMember from .scheduled_event import GuildScheduledEvent +from .audit_log import AuditLogEntry class SessionStartLimit(TypedDict): @@ -337,3 +338,7 @@ class AutoModerationActionExecution(TypedDict): content: str matched_keyword: Optional[str] matched_content: Optional[str] + + +class GuildAuditLogEntryCreate(AuditLogEntry): + guild_id: Snowflake diff --git a/docs/api.rst b/docs/api.rst index 037fb23c9..a1d0bc1fa 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -619,6 +619,28 @@ Guilds :param after: A list of stickers after the update. :type after: Sequence[:class:`GuildSticker`] +.. function:: on_audit_log_entry_create(entry) + + Called when a :class:`Guild` gets a new audit log entry. + You must have :attr:`~Permissions.view_audit_log` to receive this. + + This requires :attr:`Intents.moderation` to be enabled. + + .. versionadded:: 2.2 + + .. warning:: + + Audit log entries received through the gateway are subject to data retrieval + from cache rather than REST. This means that some data might not be present + when you expect it to be. For example, the :attr:`AuditLogEntry.target` + attribute will usually be a :class:`discord.Object` and the + :attr:`AuditLogEntry.user` attribute will depend on user and member cache. + + To get the user ID of entry, :attr:`AuditLogEntry.user_id` can be used instead. + + :param entry: The audit log entry that was created. + :type entry: :class:`AuditLogEntry` + .. function:: on_invite_create(invite) Called when an :class:`Invite` is created. @@ -813,7 +835,7 @@ Members Called when user gets banned from a :class:`Guild`. - This requires :attr:`Intents.bans` to be enabled. + This requires :attr:`Intents.moderation` to be enabled. :param guild: The guild the user got banned from. :type guild: :class:`Guild` @@ -826,7 +848,7 @@ Members Called when a :class:`User` gets unbanned from a :class:`Guild`. - This requires :attr:`Intents.bans` to be enabled. + This requires :attr:`Intents.moderation` to be enabled. :param guild: The guild the user got unbanned from. :type guild: :class:`Guild`