From 08d7f918f3de2c6e60eb57ac46e7bc98fb094a73 Mon Sep 17 00:00:00 2001 From: baronkobama Date: Thu, 30 Jun 2022 07:29:25 -0500 Subject: [PATCH] New `discord.Thread` additions (#1447) * First additions * Update state.py --- discord/message.py | 16 +++++++++++++++- discord/state.py | 3 +++ discord/threads.py | 28 ++++++++++++++++++++++++---- discord/types/message.py | 2 ++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/discord/message.py b/discord/message.py index 0b02da3752..b8e33a115d 100644 --- a/discord/message.py +++ b/discord/message.py @@ -657,6 +657,10 @@ class Message(Hashable): The guild that the message belongs to, if applicable. interaction: Optional[:class:`MessageInteraction`] The interaction associated with the message, if applicable. + thread: Optional[:class:`Thread`] + The thread created from this message, if applicable. + + .. versionadded:: 2.0 """ __slots__ = ( @@ -691,6 +695,7 @@ class Message(Hashable): "components", "guild", "interaction", + "thread", ) if TYPE_CHECKING: @@ -766,6 +771,12 @@ def __init__( except KeyError: self.interaction = None + self.thread: Optional[Thread] + try: + self.thread = Thread(guild=self.guild, state=self._state, data=data["thread"]) + except KeyError: + self.thread = None + for handler in ("author", "member", "mentions", "mention_roles"): try: getattr(self, f"_handle_{handler}")(data[handler]) @@ -1590,13 +1601,16 @@ async def create_thread(self, *, name: str, auto_archive_duration: ThreadArchive default_auto_archive_duration: ThreadArchiveDuration = getattr( self.channel, "default_auto_archive_duration", 1440 ) + data = await self._state.http.start_thread_with_message( self.channel.id, self.id, name=name, auto_archive_duration=auto_archive_duration or default_auto_archive_duration, ) - return Thread(guild=self.guild, state=self._state, data=data) + + self.thread = Thread(guild=self.guild, state=self._state, data=data) + return self.thread async def reply(self, content: Optional[str] = None, **kwargs) -> Message: """|coro| diff --git a/discord/state.py b/discord/state.py index c1571d9255..9e4707c2de 100644 --- a/discord/state.py +++ b/discord/state.py @@ -948,6 +948,9 @@ def parse_thread_delete(self, data) -> None: guild._remove_thread(thread) # type: ignore self.dispatch("thread_delete", thread) + if (msg := thread.starting_message) is not None: + msg.thread = None + def parse_thread_list_sync(self, data) -> None: guild_id = int(data["guild_id"]) guild: Optional[Guild] = self._get_guild(guild_id) diff --git a/discord/threads.py b/discord/threads.py index 84cf14d627..b88e5c3c50 100644 --- a/discord/threads.py +++ b/discord/threads.py @@ -86,6 +86,10 @@ class Thread(Messageable, Hashable): The guild the thread belongs to. id: :class:`int` The thread ID. + + .. note:: + This ID is the same as the thread starting message ID. + parent_id: :class:`int` The parent :class:`TextChannel` ID this thread belongs to. owner_id: :class:`int` @@ -260,7 +264,7 @@ def members(self) -> List[ThreadMember]: @property def last_message(self) -> Optional[Message]: - """Fetches the last message from this channel in cache. + """Returns the last message from this thread in cache. The message might not be valid or point to an existing message. @@ -273,7 +277,7 @@ def last_message(self) -> Optional[Message]: attribute. Returns - --------- + -------- Optional[:class:`Message`] The last message in this channel or ``None`` if not found. """ @@ -289,7 +293,7 @@ def category(self) -> Optional[CategoryChannel]: The parent channel was not cached and returned ``None``. Returns - ------- + -------- Optional[:class:`CategoryChannel`] The parent channel's category. """ @@ -309,7 +313,7 @@ def category_id(self) -> Optional[int]: The parent channel was not cached and returned ``None``. Returns - ------- + -------- Optional[:class:`int`] The parent channel's category ID. """ @@ -319,6 +323,22 @@ def category_id(self) -> Optional[int]: raise ClientException("Parent channel not found") return parent.category_id + @property + def starting_message(self) -> Optional[Message]: + """Returns the message that started this thread. + + The message might not be valid or point to an existing message. + + .. note:: + The ID for this message is the same as the thread ID. + + Returns + -------- + Optional[:class:`Message`] + The message that started this thread or ``None`` if not found in the cache. + """ + return self._state._get_message(self.id) + def is_private(self) -> bool: """:class:`bool`: Whether the thread is a private thread. diff --git a/discord/types/message.py b/discord/types/message.py index 9aa0d3ef28..9837e9ea9b 100644 --- a/discord/types/message.py +++ b/discord/types/message.py @@ -34,6 +34,7 @@ from .member import Member, UserWithMember from .snowflake import Snowflake, SnowflakeList from .sticker import StickerItem +from .threads import Thread from .user import User if TYPE_CHECKING: @@ -110,6 +111,7 @@ class _MessageOptional(TypedDict, total=False): referenced_message: Optional[Message] interaction: MessageInteraction components: List[Component] + thread: Optional[Thread] MessageType = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 20, 21]