Skip to content

Commit

Permalink
feat: add more raw events (#1880)
Browse files Browse the repository at this point in the history
* feat: add raw_member_remove event

* feat: add raw_member_remove event

* docs: document on_raw_member_remove

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: fix docs for raw_member_remove

* fix(docs): add versionadded for on_raw_member_remove

* feat: add raw_thread_update event

* fix(docs): fix rst syntax

* 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.

* fix(docs): fix url & syntax for gateway link

* Add raw_thread_member_remove event

* fix name typo

* docs(changelog): add changelog entry

---------

Co-authored-by: Dorukyum <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 10, 2023
1 parent 44ad1a9 commit 4b84447
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 15 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions discord/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,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`
Expand Down
85 changes: 85 additions & 0 deletions discord/raw_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -43,13 +44,16 @@
from .types.raw_models import (
BulkMessageDeleteEvent,
IntegrationDeleteEvent,
MemberRemoveEvent,
MessageDeleteEvent,
MessageUpdateEvent,
ReactionActionEvent,
ReactionClearEmojiEvent,
ReactionClearEvent,
ScheduledEventSubscription,
ThreadDeleteEvent,
ThreadMembersUpdateEvent,
ThreadUpdateEvent,
TypingEvent,
)

Expand All @@ -62,10 +66,13 @@
"RawReactionClearEvent",
"RawReactionClearEmojiEvent",
"RawIntegrationDeleteEvent",
"RawThreadUpdateEvent",
"RawThreadDeleteEvent",
"RawTypingEvent",
"RawMemberRemoveEvent",
"RawScheduledEventSubscription",
"AutoModActionExecutionEvent",
"RawThreadMembersUpdateEvent",
)


Expand Down Expand Up @@ -305,6 +312,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 <https://discord.com/developers/docs/topics/gateway-events#thread-update>`_.
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.
Expand Down Expand Up @@ -370,6 +409,26 @@ def __init__(self, data: TypingEvent) -> None:
self.guild_id: int | None = None


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"])


class RawScheduledEventSubscription(_RawReprMixin):
"""Represents the payload for a :func:`raw_scheduled_event_user_add` or
:func:`raw_scheduled_event_user_remove` event.
Expand Down Expand Up @@ -516,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 RawThreadMembersUpdateEvent(_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 <https://discord.com/developers/docs/topics/gateway-events#thread-members-update>`_.
"""

__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
35 changes: 23 additions & 12 deletions discord/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,23 +969,28 @@ 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

thread_id = int(data["id"])
thread = guild.get_thread(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)
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:
guild_id = int(data["guild_id"])
Expand Down Expand Up @@ -1084,6 +1089,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(
(
Expand All @@ -1108,6 +1114,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:
Expand All @@ -1134,23 +1141,27 @@ 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:
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:
raw.user = member
guild._remove_member(member) # type: ignore
self.dispatch("member_remove", member)
else:
_log.debug(
"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"]))
Expand Down
18 changes: 18 additions & 0 deletions discord/types/raw_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
from .emoji import PartialEmoji
from .member import Member
from .snowflake import Snowflake
from .threads import Thread, ThreadMember
from .user import User


class _MessageEventOptional(TypedDict, total=False):
Expand Down Expand Up @@ -79,6 +81,9 @@ class IntegrationDeleteEvent(TypedDict):
guild_id: Snowflake


ThreadUpdateEvent = Thread


class ThreadDeleteEvent(TypedDict, total=False):
thread_id: Snowflake
thread_type: int
Expand Down Expand Up @@ -112,3 +117,16 @@ class AutoModActionExecutionEvent(TypedDict):
rule_trigger_type: AutoModTriggerType
user_id: Snowflake
content: str


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]]
65 changes: 62 additions & 3 deletions docs/api/events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -581,15 +581,40 @@ 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.

This requires :attr:`Intents.members` to be enabled.

.. versionadded:: 2.4

: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.
Expand Down Expand Up @@ -1102,19 +1127,53 @@ 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.

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.
:type before: :class:`Thread`
: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)
Expand Down
17 changes: 17 additions & 0 deletions docs/api/models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,23 @@ Events
.. autoclass:: RawScheduledEventSubscription()
:members:

.. attributetable:: RawMemberRemoveEvent

.. autoclass:: RawMemberRemoveEvent()
:members:

.. attributetable:: RawThreadUpdateEvent

.. autoclass:: RawThreadUpdateEvent()
:members:

.. attributetable:: RawThreadMembersUpdateEvent

.. autoclass:: RawThreadMembersUpdateEvent()
:members:



Webhooks
--------

Expand Down

0 comments on commit 4b84447

Please sign in to comment.