Add category support.

This adds:

* CategoryChannel, which represents a category
* Guild.by_category() which traverses the channels grouping by category
* Guild.categories to get a list of categories
* abc.GuildChannel.category to get the category a channel belongs to
* sync_permissions keyword argument to abc.GuildChannel.edit to sync
  permissions with a pre-existing or new category
* category keyword argument to abc.GuildChannel.edit to move a channel
  to a category
This commit is contained in:
Rapptz
2017-09-13 09:38:05 -04:00
parent e24914be0b
commit 53b4890435
8 changed files with 249 additions and 32 deletions

View File

@ -250,11 +250,11 @@ class Guild(Hashable):
channels = data['channels']
for c in channels:
if c['type'] == ChannelType.text.value:
channel = TextChannel(guild=self, data=c, state=self._state)
self._add_channel(channel)
self._add_channel(TextChannel(guild=self, data=c, state=self._state))
elif c['type'] == ChannelType.voice.value:
channel = VoiceChannel(guild=self, data=c, state=self._state)
self._add_channel(channel)
self._add_channel(VoiceChannel(guild=self, data=c, state=self._state))
elif c['type'] == ChannelType.category.value:
self._add_channel(CategoryChannel(guild=self, data=c, state=self._state))
@property
@ -309,6 +309,52 @@ class Guild(Hashable):
r.sort(key=lambda c: c.position)
return r
@property
def categories(self):
"""List[:class:`CategoryChannel`]: A list of categories that belongs to this guild.
This is sorted by the position and are in UI order from top to bottom.
"""
r = [ch for ch in self._channels.values() if isinstance(ch, CategoryChannel)]
r.sort(key=lambda c: c.position)
return r
def by_category(self):
"""Returns every :class:`CategoryChannel` and their associated channels.
These channels and categories are sorted in the official Discord UI order.
If the channels do not have a category, then the first element of the tuple is
``None``.
Returns
--------
List[Tuple[Optional[:class:`CategoryChannel`], List[:class:`abc.GuildChannel`]]]:
The categories and their associated channels.
"""
grouped = {}
for channel in self._channels.values():
if isinstance(channel, CategoryChannel):
continue
try:
channels = grouped[channel.category_id]
except KeyError:
channels = grouped[channel.category_id] = []
channels.append(channel)
def key(t):
k, v = t
return (k.position if k else -1, v)
_get = self._channels.get
as_list = [(_get(k), v) for k, v in grouped.items()]
as_list.sort(key=key)
for _, channels in as_list:
channels.sort(key=lambda c: c.position)
return as_list
def get_channel(self, channel_id):
"""Returns a :class:`abc.GuildChannel` with the given ID. If not found, returns None."""
return self._channels.get(channel_id)