From ab0b9b897d4426ddca160399396894fbd0d9bfda Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Fri, 6 Jan 2023 15:44:49 -0600 Subject: [PATCH 01/13] feat: add raw_member_remove event --- discord/raw_models.py | 23 +++++++++++++++++++++++ discord/state.py | 9 +++++++-- discord/types/raw_models.py | 6 ++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/discord/raw_models.py b/discord/raw_models.py index 3353c4c17e..a7a5bf82c2 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -30,6 +30,7 @@ from .automod import AutoModAction, AutoModTriggerType from .enums import ChannelType, try_enum +from .types.user import User if TYPE_CHECKING: from .abc import MessageableChannel @@ -42,6 +43,7 @@ from .types.raw_models import AutoModActionExecutionEvent as AutoModActionExecution from .types.raw_models import ( BulkMessageDeleteEvent, + GuildMemberRemoveEvent, IntegrationDeleteEvent, MessageDeleteEvent, MessageUpdateEvent, @@ -64,6 +66,7 @@ "RawIntegrationDeleteEvent", "RawThreadDeleteEvent", "RawTypingEvent", + "RawMemberRemoveEvent", "RawScheduledEventSubscription", "AutoModActionExecutionEvent", ) @@ -370,6 +373,26 @@ def __init__(self, data: TypingEvent) -> None: self.guild_id: int | None = None +class RawMemberRemoveEvent(_RawReprMixin): + """Represents the payload for a :func:`on_raw_member_remove` event. + + .. versionadded:: 2.0 + + Attributes + ---------- + user: Union[:class:`discord.User`, :class:`discord.Member`] + The user that left the guild. + guild_id: :class:`int` + The ID of the guild the user left. + """ + + __slots__ = ("user", "guild_id") + + def __init__(self, data: GuildMemberRemoveEvent, user: User, /) -> None: + self.user: User | Member = user + self.guild_id: int = int(data["guild_id"]) + + class RawScheduledEventSubscription(_RawReprMixin): """Represents the payload for a :func:`raw_scheduled_event_user_add` or :func:`raw_scheduled_event_user_remove` event. diff --git a/discord/state.py b/discord/state.py index 6cd46ba3ca..9547aacc9b 100644 --- a/discord/state.py +++ b/discord/state.py @@ -61,6 +61,7 @@ from .object import Object from .partial_emoji import PartialEmoji from .raw_models import * +from .raw_models import RawMemberRemoveEvent from .role import Role from .scheduled_events import ScheduledEvent from .stage_instance import StageInstance @@ -1128,6 +1129,9 @@ def parse_guild_member_add(self, data) -> None: self.dispatch("member_join", member) def parse_guild_member_remove(self, data) -> None: + user = self.store_user(data["user"]) + raw = RawMemberRemoveEvent(data, user) + guild = self._get_guild(int(data["guild_id"])) if guild is not None: try: @@ -1135,9 +1139,9 @@ def parse_guild_member_remove(self, data) -> None: except AttributeError: pass - user_id = int(data["user"]["id"]) - member = guild.get_member(user_id) + member = guild.get_member(user.id) if member is not None: + raw.user = member guild._remove_member(member) # type: ignore self.dispatch("member_remove", member) else: @@ -1145,6 +1149,7 @@ def parse_guild_member_remove(self, data) -> None: "GUILD_MEMBER_REMOVE referencing an unknown guild ID: %s. Discarding.", data["guild_id"], ) + self.dispatch("raw_member_remove", raw) def parse_guild_member_update(self, data) -> None: guild = self._get_guild(int(data["guild_id"])) diff --git a/discord/types/raw_models.py b/discord/types/raw_models.py index d8e64531f5..e2a8d3bf51 100644 --- a/discord/types/raw_models.py +++ b/discord/types/raw_models.py @@ -29,6 +29,7 @@ from .emoji import PartialEmoji from .member import Member from .snowflake import Snowflake +from .user import User class _MessageEventOptional(TypedDict, total=False): @@ -94,6 +95,11 @@ class TypingEvent(TypedDict): timestamp: int +class GuildMemberRemoveEvent(TypedDict): + guild_id: Snowflake + user: User + + class ScheduledEventSubscription(TypedDict, total=False): event_id: Snowflake user_id: Snowflake From 780e96268abf3bda6ab2aa44df1e0cf80ffa01da Mon Sep 17 00:00:00 2001 From: Dorukyum Date: Sat, 7 Jan 2023 20:25:12 +0300 Subject: [PATCH 02/13] feat: add raw_member_remove event --- discord/raw_models.py | 24 ++++++++++++++++++++++++ discord/state.py | 11 +++++++---- discord/types/raw_models.py | 7 +++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/discord/raw_models.py b/discord/raw_models.py index 3353c4c17e..4013d5708a 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -42,6 +42,7 @@ from .types.raw_models import AutoModActionExecutionEvent as AutoModActionExecution from .types.raw_models import ( BulkMessageDeleteEvent, + MemberRemoveEvent, IntegrationDeleteEvent, MessageDeleteEvent, MessageUpdateEvent, @@ -52,6 +53,7 @@ ThreadDeleteEvent, TypingEvent, ) + from .user import User __all__ = ( @@ -66,6 +68,7 @@ "RawTypingEvent", "RawScheduledEventSubscription", "AutoModActionExecutionEvent", + "RawMemberRemoveEvent", ) @@ -516,3 +519,24 @@ def __repr__(self) -> str: f"rule_id={self.rule_id!r} guild_id={self.guild_id!r} " f"user_id={self.user_id!r}>" ) + + +class RawMemberRemoveEvent(_RawReprMixin): + """Represents the payload for an .func:`on_raw_member_remove` event. + + .. versionadded:: 2.4 + + Attributes + ---------- + user: :class:`discord.User` + The user that left the guild. + guild_id: :class:`int` + The ID of the guild the user left. + """ + + __slots__ = ("user", "guild_id") + + def __init__(self, data: MemberRemoveEvent, user: User): + self.user: User = user + self.guild_id: int = int(data["guild_id"]) + diff --git a/discord/state.py b/discord/state.py index 6cd46ba3ca..c1b9b36560 100644 --- a/discord/state.py +++ b/discord/state.py @@ -1128,17 +1128,20 @@ def parse_guild_member_add(self, data) -> None: self.dispatch("member_join", member) def parse_guild_member_remove(self, data) -> None: - guild = self._get_guild(int(data["guild_id"])) + user = User(data=data["user"], state=self) + raw = RawMemberRemoveEvent(data, user) + self.dispatch("raw_member_remove", raw) + + guild = self._get_guild(raw.guild_id) if guild is not None: try: guild._member_count -= 1 except AttributeError: pass - user_id = int(data["user"]["id"]) - member = guild.get_member(user_id) + member = guild.get_member(user.id) if member is not None: - guild._remove_member(member) # type: ignore + guild._remove_member(member) self.dispatch("member_remove", member) else: _log.debug( diff --git a/discord/types/raw_models.py b/discord/types/raw_models.py index d8e64531f5..ad2dcde54e 100644 --- a/discord/types/raw_models.py +++ b/discord/types/raw_models.py @@ -29,6 +29,7 @@ from .emoji import PartialEmoji from .member import Member from .snowflake import Snowflake +from .user import User class _MessageEventOptional(TypedDict, total=False): @@ -112,3 +113,9 @@ class AutoModActionExecutionEvent(TypedDict): rule_trigger_type: AutoModTriggerType user_id: Snowflake content: str + + +class MemberRemoveEvent(TypedDict): + guild_id: Snowflake + user: User + From 72ae48cebfda2acd7802f95af5d229f8f0a1a46c Mon Sep 17 00:00:00 2001 From: Dorukyum Date: Sat, 7 Jan 2023 20:33:50 +0300 Subject: [PATCH 03/13] docs: document on_raw_member_remove --- discord/flags.py | 1 + docs/api/events.rst | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/discord/flags.py b/discord/flags.py index a378cd2437..6594514752 100644 --- a/discord/flags.py +++ b/discord/flags.py @@ -678,6 +678,7 @@ def members(self): - :func:`on_member_join` - :func:`on_member_remove` + - :func:`on_raw_member_remove` - :func:`on_member_update` - :func:`on_user_update` diff --git a/docs/api/events.rst b/docs/api/events.rst index c4b3af6d8e..abff313990 100644 --- a/docs/api/events.rst +++ b/docs/api/events.rst @@ -590,6 +590,16 @@ Members/Users :param member: The member who joined or left. :type member: :class:`Member` +.. function:: on_raw_member_remove(payload) + + Called when a :class:`Member` leaves a :class:`Guild`. Unlike :func:`on_member_remove`, this is + called regardless of the state of the internal member cache. + + This requires :attr:`Intents.members` to be enabled. + + :param payload: The raw event payload data. + :type payload: :class:`RawMemberRemoveEvent` + .. function:: on_member_update(before, after) Called when a :class:`Member` updates their profile. From ffd84e61d2cb88d04f925d0d88f009d08680b1c3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 7 Jan 2023 17:35:38 +0000 Subject: [PATCH 04/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- discord/raw_models.py | 3 +-- discord/types/raw_models.py | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/discord/raw_models.py b/discord/raw_models.py index 4013d5708a..b02b925390 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -42,8 +42,8 @@ from .types.raw_models import AutoModActionExecutionEvent as AutoModActionExecution from .types.raw_models import ( BulkMessageDeleteEvent, - MemberRemoveEvent, IntegrationDeleteEvent, + MemberRemoveEvent, MessageDeleteEvent, MessageUpdateEvent, ReactionActionEvent, @@ -539,4 +539,3 @@ class RawMemberRemoveEvent(_RawReprMixin): def __init__(self, data: MemberRemoveEvent, user: User): self.user: User = user self.guild_id: int = int(data["guild_id"]) - diff --git a/discord/types/raw_models.py b/discord/types/raw_models.py index ad2dcde54e..aaba1bf32d 100644 --- a/discord/types/raw_models.py +++ b/discord/types/raw_models.py @@ -118,4 +118,3 @@ class AutoModActionExecutionEvent(TypedDict): class MemberRemoveEvent(TypedDict): guild_id: Snowflake user: User - From 6366e1348f62764194cb0318ddd4a077f02fff9e Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:29:46 -0600 Subject: [PATCH 05/13] fix: fix docs for raw_member_remove --- docs/api/events.rst | 23 ++++++++++++++++++----- docs/api/models.rst | 5 +++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/api/events.rst b/docs/api/events.rst index abff313990..b7a554e527 100644 --- a/docs/api/events.rst +++ b/docs/api/events.rst @@ -581,19 +581,32 @@ Invites Members/Users ------------- .. function:: on_member_join(member) - on_member_remove(member) - Called when a :class:`Member` leaves or joins a :class:`Guild`. + Called when a :class:`Member` joins a :class:`Guild`. This requires :attr:`Intents.members` to be enabled. - :param member: The member who joined or left. + :param member: The member who joined. + :type member: :class:`Member` + +.. function:: on_member_remove(member) + + Called when a :class:`Member` leaves a :class:`Guild`. + + If the guild or member could not be found in the internal cache, this event will not + be called. Alternatively, :func:`on_raw_member_remove` is called regardless of the + internal cache. + + This requires :attr:`Intents.members` to be enabled. + + :param member: The member who left. :type member: :class:`Member` .. function:: on_raw_member_remove(payload) - Called when a :class:`Member` leaves a :class:`Guild`. Unlike :func:`on_member_remove`, this is - called regardless of the state of the internal member cache. + Called when a :class:`Member` leaves a :class:`Guild`. Unlike + :func:`on_member_remove`, this is called regardless of the state of the internal + member cache. This requires :attr:`Intents.members` to be enabled. diff --git a/docs/api/models.rst b/docs/api/models.rst index d4520da8b2..14373e1fe0 100644 --- a/docs/api/models.rst +++ b/docs/api/models.rst @@ -502,6 +502,11 @@ Events .. autoclass:: RawScheduledEventSubscription() :members: +.. attributetable:: RawMemberRemoveEvent + +.. autoclass:: RawMemberRemoveEvent() + :members: + Webhooks -------- From 6c88517980ab934b48b168aa33a10f611c3d7d81 Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:36:30 -0600 Subject: [PATCH 06/13] fix(docs): add versionadded for on_raw_member_remove --- docs/api/events.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/api/events.rst b/docs/api/events.rst index b7a554e527..2df5498cc4 100644 --- a/docs/api/events.rst +++ b/docs/api/events.rst @@ -610,6 +610,8 @@ Members/Users This requires :attr:`Intents.members` to be enabled. + .. versionadded:: 2.4 + :param payload: The raw event payload data. :type payload: :class:`RawMemberRemoveEvent` From b01ba0b9f81b61ef2098c9ea9bd693a2896698b2 Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:37:38 -0600 Subject: [PATCH 07/13] feat: add raw_thread_update event --- discord/raw_models.py | 34 ++++++++++++++++++++++++++++++++++ discord/state.py | 7 ++++--- discord/types/raw_models.py | 4 ++++ docs/api/events.rst | 19 +++++++++++++++++++ docs/api/models.rst | 5 +++++ 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/discord/raw_models.py b/discord/raw_models.py index c1c4c64881..41fcc8ae88 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -52,6 +52,7 @@ ReactionClearEvent, ScheduledEventSubscription, ThreadDeleteEvent, + ThreadUpdateEvent, TypingEvent, ) @@ -64,6 +65,7 @@ "RawReactionClearEvent", "RawReactionClearEmojiEvent", "RawIntegrationDeleteEvent", + "RawThreadUpdateEvent", "RawThreadDeleteEvent", "RawTypingEvent", "RawMemberRemoveEvent", @@ -308,6 +310,38 @@ def __init__(self, data: IntegrationDeleteEvent) -> None: self.application_id: int | None = None +class RawThreadUpdateEvent(_RawReprMixin): + """Represents the payload for an :func:`on_raw_thread_update` event. + + .. versionadded:: 2.4 + + Attributes + ---------- + thread_id: :class:`int` + The ID of the updated thread. + thread_type: :class:`discord.ChannelType` + The channel type of the updated thread. + guild_id: :class:`int` + The ID of the guild the thread belongs to. + parent_id: :class:`int` + The ID of the channel the thread belongs to. + data: :class:`dict` + The raw data given by the gateway `_ + thread: :class:`discord.Thread` | None + The thread, if it could be found in the internal cache. + """ + + __slots__ = ("thread_id", "thread_type", "parent_id", "guild_id", "data", "thread") + + def __init__(self, data: ThreadUpdateEvent) -> None: + self.thread_id: int = int(data["id"]) + self.thread_type: ChannelType = try_enum(ChannelType, data["type"]) + self.guild_id: int = int(data["guild_id"]) + self.parent_id: int = int(data["parent_id"]) + self.data: ThreadUpdateEvent = data + self.thread: Thread | None = None + + class RawThreadDeleteEvent(_RawReprMixin): """Represents the payload for :func:`on_raw_thread_delete` event. diff --git a/discord/state.py b/discord/state.py index 9547aacc9b..c549b0a5cb 100644 --- a/discord/state.py +++ b/discord/state.py @@ -61,7 +61,6 @@ from .object import Object from .partial_emoji import PartialEmoji from .raw_models import * -from .raw_models import RawMemberRemoveEvent from .role import Role from .scheduled_events import ScheduledEvent from .stage_instance import StageInstance @@ -973,8 +972,8 @@ def parse_thread_update(self, data) -> None: ) return - thread_id = int(data["id"]) - thread = guild.get_thread(thread_id) + raw = RawThreadUpdateEvent(data) + thread = guild.get_thread(raw.thread_id) if thread is not None: old = copy.copy(thread) thread._update(data) @@ -983,6 +982,8 @@ def parse_thread_update(self, data) -> None: thread = Thread(guild=guild, state=guild._state, data=data) guild._add_thread(thread) self.dispatch("thread_join", thread) + raw.thread = thread + self.dispatch("raw_thread_update", raw) def parse_thread_delete(self, data) -> None: guild_id = int(data["guild_id"]) diff --git a/discord/types/raw_models.py b/discord/types/raw_models.py index aaba1bf32d..a45a001034 100644 --- a/discord/types/raw_models.py +++ b/discord/types/raw_models.py @@ -29,6 +29,7 @@ from .emoji import PartialEmoji from .member import Member from .snowflake import Snowflake +from .threads import Thread from .user import User @@ -80,6 +81,9 @@ class IntegrationDeleteEvent(TypedDict): guild_id: Snowflake +ThreadUpdateEvent = Thread + + class ThreadDeleteEvent(TypedDict, total=False): thread_id: Snowflake thread_type: int diff --git a/docs/api/events.rst b/docs/api/events.rst index 2df5498cc4..aef9f7d433 100644 --- a/docs/api/events.rst +++ b/docs/api/events.rst @@ -1133,6 +1133,10 @@ Threads This requires :attr:`Intents.guilds` to be enabled. + If the thread could not be found in the internal cache, this event will not be called. + Threads will not be in the cache if they are archived. Alternatively, + :func:`on_raw_thread_update` is called regardless of the internal cache. + .. versionadded:: 2.0 :param before: The updated thread's old info. @@ -1140,6 +1144,21 @@ Threads :param after: The updated thread's new info. :type after: :class:`Thread` + +.. function:: on_raw_thread_update(payload) + + Called whenever a thread is updated. + + Unlike :func:`on_thread_update` this is called regardless of if the thread is in the + internal thread cache or not. + + This requires :attr:`Intents.guilds` to be enabled. + + .. versionadded:: 2.4 + + :param payload: The raw event payload data. + :type payload: :class:`RawThreadUpdateEvent` + Typing ------ .. function:: on_typing(channel, user, when) diff --git a/docs/api/models.rst b/docs/api/models.rst index 14373e1fe0..aeb9ec01da 100644 --- a/docs/api/models.rst +++ b/docs/api/models.rst @@ -507,6 +507,11 @@ Events .. autoclass:: RawMemberRemoveEvent() :members: +.. attributetable:: RawThreadUpdateEvent + +.. autoclass:: RawThreadUpdateEvent() + :members: + Webhooks -------- From 2e038bc5dcec76affc80f23c992eb5444a09e630 Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:39:00 -0600 Subject: [PATCH 08/13] fix(docs): fix rst syntax --- discord/raw_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/raw_models.py b/discord/raw_models.py index 41fcc8ae88..4566c84e17 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -408,7 +408,7 @@ def __init__(self, data: TypingEvent) -> None: class RawMemberRemoveEvent(_RawReprMixin): - """Represents the payload for an .func:`on_raw_member_remove` event. + """Represents the payload for an :func:`on_raw_member_remove` event. .. versionadded:: 2.4 From 8c272b22546771ab5d823c70567c9ad9c32fda00 Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:45:48 -0600 Subject: [PATCH 09/13] fix: improve parse_thread_update method 1. Changed so raw_thread_update will be dispatched even when an unknown guild is referenced 2. Added handling to remove archived threads from the cache. --- discord/state.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/discord/state.py b/discord/state.py index c549b0a5cb..9b3d153a6f 100644 --- a/discord/state.py +++ b/discord/state.py @@ -965,24 +965,27 @@ def parse_thread_create(self, data) -> None: def parse_thread_update(self, data) -> None: guild_id = int(data["guild_id"]) guild = self._get_guild(guild_id) + raw = RawThreadUpdateEvent(data) if guild is None: _log.debug( "THREAD_UPDATE referencing an unknown guild ID: %s. Discarding", guild_id, ) return - - raw = RawThreadUpdateEvent(data) - thread = guild.get_thread(raw.thread_id) - if thread is not None: - old = copy.copy(thread) - thread._update(data) - self.dispatch("thread_update", old, thread) else: - thread = Thread(guild=guild, state=guild._state, data=data) - guild._add_thread(thread) - self.dispatch("thread_join", thread) - raw.thread = thread + thread = guild.get_thread(raw.thread_id) + if thread is not None: + old = copy.copy(thread) + thread._update(data) + if thread.archived: + guild._remove_thread(thread) + self.dispatch("thread_update", old, thread) + else: + thread = Thread(guild=guild, state=guild._state, data=data) + if not thread.archived: + guild._add_thread(thread) + self.dispatch("thread_join", thread) + raw.thread = thread self.dispatch("raw_thread_update", raw) def parse_thread_delete(self, data) -> None: From 0e530d0dbb45394db52dc23159f875b787d18938 Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:50:45 -0600 Subject: [PATCH 10/13] fix(docs): fix url & syntax for gateway link --- discord/raw_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/raw_models.py b/discord/raw_models.py index 4566c84e17..1b23acf1f3 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -326,7 +326,7 @@ class RawThreadUpdateEvent(_RawReprMixin): parent_id: :class:`int` The ID of the channel the thread belongs to. data: :class:`dict` - The raw data given by the gateway `_ + The raw data given by the `gateway `_. thread: :class:`discord.Thread` | None The thread, if it could be found in the internal cache. """ From b73548a7b81fcaea08dec0b05caa6804b4ea8174 Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:34:45 -0600 Subject: [PATCH 11/13] Add raw_thread_member_remove event --- discord/raw_models.py | 28 ++++++++++++++++++++++++++++ discord/state.py | 2 ++ discord/types/raw_models.py | 10 +++++++++- docs/api/events.rst | 15 +++++++++++++++ docs/api/models.rst | 7 +++++++ 5 files changed, 61 insertions(+), 1 deletion(-) diff --git a/discord/raw_models.py b/discord/raw_models.py index 1b23acf1f3..8245958cd4 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -52,6 +52,7 @@ ReactionClearEvent, ScheduledEventSubscription, ThreadDeleteEvent, + ThreadMembersUpdateEvent, ThreadUpdateEvent, TypingEvent, ) @@ -71,6 +72,7 @@ "RawMemberRemoveEvent", "RawScheduledEventSubscription", "AutoModActionExecutionEvent", + "RawThreadMembersUpdateEvent", ) @@ -573,3 +575,29 @@ def __repr__(self) -> str: f"rule_id={self.rule_id!r} guild_id={self.guild_id!r} " f"user_id={self.user_id!r}>" ) + + +class RawThreadMembersUpdate(_RawReprMixin): + """Represents the payload for an :func:`on_raw_thread_member_remove` event. + + .. versionadded:: 2.4 + + Attributes + ---------- + thread_id: :class:`int` + The ID of the thread that was updated. + guild_id: :class:`int` + The ID of the guild the thread is in. + member_count: :class:`int` + The approximate number of members in the thread. Maximum of 50. + data: :class:`dict` + The raw data given by the `gateway `_. + """ + + __slots__ = ("thread_id", "guild_id", "member_count", "data") + + def __init__(self, data: ThreadMembersUpdateEvent) -> None: + self.thread_id = int(data["id"]) + self.guild_id = int(data["guild_id"]) + self.member_count = int(data["member_count"]) + self.data = data diff --git a/discord/state.py b/discord/state.py index 9b3d153a6f..dffdad1f0e 100644 --- a/discord/state.py +++ b/discord/state.py @@ -1085,6 +1085,7 @@ def parse_thread_members_update(self, data) -> None: thread_id = int(data["id"]) thread: Thread | None = guild.get_thread(thread_id) + raw = RawThreadMembersUpdateEvent(data) if thread is None: _log.debug( "THREAD_MEMBERS_UPDATE referencing an unknown thread ID: %s." @@ -1107,6 +1108,7 @@ def parse_thread_members_update(self, data) -> None: for member_id in removed_member_ids: if member_id != self_id: member = thread._pop_member(member_id) + self.dispatch("raw_thread_member_remove", raw) if member is not None: self.dispatch("thread_member_remove", member) else: diff --git a/discord/types/raw_models.py b/discord/types/raw_models.py index a45a001034..930ed47557 100644 --- a/discord/types/raw_models.py +++ b/discord/types/raw_models.py @@ -29,7 +29,7 @@ from .emoji import PartialEmoji from .member import Member from .snowflake import Snowflake -from .threads import Thread +from .threads import Thread, ThreadMember from .user import User @@ -122,3 +122,11 @@ class AutoModActionExecutionEvent(TypedDict): class MemberRemoveEvent(TypedDict): guild_id: Snowflake user: User + + +class ThreadMembersUpdateEvent(TypedDict): + id: Snowflake + guild_id: Snowflake + member_count: int + added_members: NotRequired[list[ThreadMember]] + removed_member_ids: NotRequired[list[Snowflake]] diff --git a/docs/api/events.rst b/docs/api/events.rst index aef9f7d433..8151b572e8 100644 --- a/docs/api/events.rst +++ b/docs/api/events.rst @@ -1127,6 +1127,21 @@ Threads :param member: The member who joined or left. :type member: :class:`ThreadMember` + +.. function:: on_raw_thread_member_remove(payload) + + Called when a :class:`ThreadMember` leaves a :class:`Thread`. Unlike :func:`on_thread_member_remove` this + is called regardless of the member being in the thread's internal cache of members or not. + + This requires :attr:`Intents.members` to be enabled. + + .. versionadded:: 2.4 + + :param payload: The raw event payload data. + :type member: :class:`RawThreadMembersUpdateEvent` + + + .. function:: on_thread_update(before, after) Called whenever a thread is updated. diff --git a/docs/api/models.rst b/docs/api/models.rst index aeb9ec01da..b445702468 100644 --- a/docs/api/models.rst +++ b/docs/api/models.rst @@ -512,6 +512,13 @@ Events .. autoclass:: RawThreadUpdateEvent() :members: +.. attributetable:: RawThreadMembersUpdateEvent + +.. autoclass:: RawThreadMembersUpdateEvent() + :members: + + + Webhooks -------- From be19f32e9d68925428b14b1a1595e9b460a5b455 Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:41:12 -0600 Subject: [PATCH 12/13] fix name typo --- discord/raw_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/raw_models.py b/discord/raw_models.py index 8245958cd4..22b1341aaa 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -577,7 +577,7 @@ def __repr__(self) -> str: ) -class RawThreadMembersUpdate(_RawReprMixin): +class RawThreadMembersUpdateEvent(_RawReprMixin): """Represents the payload for an :func:`on_raw_thread_member_remove` event. .. versionadded:: 2.4 From ae6e960bf22ca95e1c919e9642186ec036678956 Mon Sep 17 00:00:00 2001 From: BobDotCom <71356958+BobDotCom@users.noreply.github.com> Date: Fri, 10 Feb 2023 12:31:56 -0600 Subject: [PATCH 13/13] docs(changelog): add changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68682018c3..54405cab08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ These changes are available on the `master` branch, but have not yet been releas ([#1912](https://github.com/Pycord-Development/pycord/pull/1912)) - Added GIF sticker format type to the `StickerFormatType` enum. ([#1915](https://github.com/Pycord-Development/pycord/pull/1915)) +- Added new raw events: `raw_member_remove`, `raw_thread_update`, and + `raw_thread_member_remove`. + ([#1880](https://github.com/Pycord-Development/pycord/pull/1880)) ### Changed