Browse Source

Parse remaining thread events.

feature/threads
Rapptz 4 years ago
parent
commit
bd369c76ea
  1. 16
      discord/guild.py
  2. 55
      discord/state.py
  3. 2
      discord/threads.py
  4. 50
      docs/api.rst

16
discord/guild.py

@ -26,7 +26,7 @@ from __future__ import annotations
import copy import copy
from collections import namedtuple from collections import namedtuple
from typing import Dict, List, Literal, Optional, TYPE_CHECKING, Union, overload from typing import Dict, List, Set, Literal, Optional, TYPE_CHECKING, Union, overload
from . import utils, abc from . import utils, abc
from .role import Role from .role import Role
@ -227,6 +227,20 @@ class Guild(Hashable):
def _remove_thread(self, thread): def _remove_thread(self, thread):
self._threads.pop(thread.id, None) self._threads.pop(thread.id, None)
def _clear_threads(self):
self._threads.clear()
def _remove_threads_by_channel(self, channel_id: int):
to_remove = [k for k, t in self._threads.items() if t.parent_id == channel_id]
for k in to_remove:
del self._threads[k]
def _filter_threads(self, channel_ids: Set[int]) -> Dict[int, Thread]:
to_remove: Dict[int, Thread] = {k: t for k, t in self._threads.items() if t.parent_id in channel_ids}
for k in to_remove:
del self._threads[k]
return to_remove
def __str__(self): def __str__(self):
return self.name or '' return self.name or ''

55
discord/state.py

@ -716,7 +716,7 @@ class ConnectionState:
thread = Thread(guild=guild, data=data) thread = Thread(guild=guild, data=data)
guild._add_thread(thread) guild._add_thread(thread)
self.dispatch('thread_create', thread) self.dispatch('thread_join', thread)
def parse_thread_update(self, data): def parse_thread_update(self, data):
guild_id = int(data['guild_id']) guild_id = int(data['guild_id'])
@ -752,6 +752,16 @@ class ConnectionState:
log.debug('THREAD_LIST_SYNC referencing an unknown guild ID: %s. Discarding', guild_id) log.debug('THREAD_LIST_SYNC referencing an unknown guild ID: %s. Discarding', guild_id)
return return
try:
channel_ids = set(data['channel_ids'])
except KeyError:
# If not provided, then the entire guild is being synced
# So all previous thread data should be overwritten
previous_threads = guild._threads.copy()
guild._clear_threads()
else:
previous_threads = guild._filter_threads(channel_ids)
threads = { threads = {
d['id']: guild._store_thread(d) d['id']: guild._store_thread(d)
for d in data.get('threads', []) for d in data.get('threads', [])
@ -766,7 +776,13 @@ class ConnectionState:
else: else:
thread._add_member(ThreadMember(thread, member)) thread._add_member(ThreadMember(thread, member))
# TODO: dispatch? for thread in threads.values():
old = previous_threads.pop(thread.id, None)
if old is None:
self.dispatch('thread_join', thread)
for thread in previous_threads.values():
self.dispatch('thread_remove', thread)
def parse_thread_member_update(self, data): def parse_thread_member_update(self, data):
guild_id = int(data['guild_id']) guild_id = int(data['guild_id'])
@ -776,15 +792,44 @@ class ConnectionState:
return return
thread_id = int(data['id']) thread_id = int(data['id'])
thread = guild.get_thread(thread_id) thread: Optional[Thread] = guild.get_thread(thread_id)
if thread is None: if thread is None:
log.debug('THREAD_MEMBER_UPDATE referencing an unknown thread ID: %s. Discarding', thread_id) log.debug('THREAD_MEMBER_UPDATE referencing an unknown thread ID: %s. Discarding', thread_id)
return return
member = ThreadMember(thread, data) member = ThreadMember(thread, data)
thread._add_member(member) thread.me = member
def parse_thread_members_update(self, data):
guild_id = int(data['guild_id'])
guild: Optional[Guild] = self._get_guild(guild_id)
if guild is None:
log.debug('THREAD_MEMBERS_UPDATE referencing an unknown guild ID: %s. Discarding', guild_id)
return
# TODO: dispatch thread_id = int(data['id'])
thread: Optional[Thread] = guild.get_thread(thread_id)
if thread is None:
log.debug('THREAD_MEMBERS_UPDATE referencing an unknown thread ID: %s. Discarding', thread_id)
return
added_members = [ThreadMember(thread, d) for d in data.get('added_members', [])]
removed_member_ids = data.get('removed_member_ids', [])
self_id = self.self_id
for member in added_members:
if member.id != self_id:
thread._add_member(member)
self.dispatch('thread_member_join', member)
else:
thread.me = member
self.dispatch('thread_join', thread)
for member_id in removed_member_ids:
if member_id != self_id:
member = thread._pop_member(member_id)
self.dispatch('thread_member_leave', member)
else:
self.dispatch('thread_remove', thread)
def parse_guild_member_add(self, data): def parse_guild_member_add(self, data):
guild = self._get_guild(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))

2
discord/threads.py

@ -383,6 +383,8 @@ class Thread(Messageable, Hashable):
def _add_member(self, member: ThreadMember) -> None: def _add_member(self, member: ThreadMember) -> None:
self._members[member.id] = member self._members[member.id] = member
def _pop_member(self, member_id: int) -> Optional[ThreadMember]:
return self._members.pop(member_id, None)
class ThreadMember(Hashable): class ThreadMember(Hashable):
"""Represents a Discord thread member. """Represents a Discord thread member.

50
docs/api.rst

@ -658,10 +658,42 @@ to handle it, which defaults to print a traceback and ignoring the exception.
:param last_pin: The latest message that was pinned as an aware datetime in UTC. Could be ``None``. :param last_pin: The latest message that was pinned as an aware datetime in UTC. Could be ``None``.
:type last_pin: Optional[:class:`datetime.datetime`] :type last_pin: Optional[:class:`datetime.datetime`]
.. function:: on_thread_join(thread)
Called whenever a thread is joined.
Note that you can get the guild from :attr:`Thread.guild`.
This requires :attr:`Intents.guilds` to be enabled.
.. versionadded:: 2.0
:param thread: The thread that got joined.
:type thread: :class:`Thread`
.. function:: on_thread_remove(thread)
Called whenever a thread is removed. This is different from a thread being deleted.
Note that you can get the guild from :attr:`Thread.guild`.
This requires :attr:`Intents.guilds` to be enabled.
.. warning::
Due to technical limitations, this event might not be called
as soon as one expects. Since the library tracks thread membership
locally, the API only sends updated thread membership status upon being
synced by joining a thread.
.. versionadded:: 2.0
:param thread: The thread that got removed.
:type thread: :class:`Thread`
.. function:: on_thread_delete(thread) .. function:: on_thread_delete(thread)
on_thread_create(thread)
Called whenever a thread is deleted or created. Called whenever a thread is deleted.
Note that you can get the guild from :attr:`Thread.guild`. Note that you can get the guild from :attr:`Thread.guild`.
@ -669,9 +701,21 @@ to handle it, which defaults to print a traceback and ignoring the exception.
.. versionadded:: 2.0 .. versionadded:: 2.0
:param thread: The thread that got created or deleted. :param thread: The thread that got deleted.
:type thread: :class:`Thread` :type thread: :class:`Thread`
.. function:: on_thread_member_join(member)
on_thread_member_remove(member)
Called when a :class:`ThreadMember` leaves or joins a :class:`Thread`.
You can get the thread a member belongs in by accessing :attr:`ThreadMember.thread`.
This requires :attr:`Intents.members` to be enabled.
:param member: The member who joined or left.
:type member: :class:`ThreadMember`
.. function:: on_thread_update(before, after) .. function:: on_thread_update(before, after)
Called whenever a thread is updated. Called whenever a thread is updated.

Loading…
Cancel
Save