Browse Source

Add support for system channel flags

pull/2203/head
Rapptz 6 years ago
parent
commit
320dbc0618
  1. 2
      discord/__init__.py
  2. 131
      discord/guild.py
  3. 3
      discord/http.py
  4. 7
      docs/api.rst

2
discord/__init__.py

@ -26,7 +26,7 @@ from .user import User, ClientUser, Profile
from .emoji import Emoji, PartialEmoji
from .activity import *
from .channel import *
from .guild import Guild
from .guild import Guild, SystemChannelFlags
from .relationship import Relationship
from .member import Member, VoiceState
from .message import Message, Attachment

131
discord/guild.py

@ -48,6 +48,121 @@ from .asset import Asset
BanEntry = namedtuple('BanEntry', 'reason user')
_GuildLimit = namedtuple('_GuildLimit', 'emoji bitrate filesize')
class _flag_descriptor:
def __init__(self, func):
self.flag = func(None)
self.__doc__ = func.__doc__
def __get__(self, instance, owner):
return instance._has_flag(self.flag)
def __set__(self, instance, value):
instance._set_flag(self.flag, value)
def fill_with_flags(cls):
cls.VALID_FLAGS = {
name: value.flag
for name, value in cls.__dict__.items()
if isinstance(value, _flag_descriptor)
}
max_bits = max(cls.VALID_FLAGS.values()).bit_length()
cls.ALL_OFF_VALUE = -1 + (2 ** max_bits)
return cls
@fill_with_flags
class SystemChannelFlags:
r"""Wraps up a Discord system channel flag value.
Similar to :class:`Permissions`\, the properties provided are two way.
You can set and retrieve individual bits using the properties as if they
were regular bools. This allows you to edit the system flags easily.
To construct an object you can pass keyword arguments denoting the flags
to enable or disable.
.. container:: operations
.. describe:: x == y
Checks if two flags are equal.
.. describe:: x != y
Checks if two flags are not equal.
.. describe:: hash(x)
Return the flag's hash.
.. describe:: iter(x)
Returns an iterator of ``(name, value)`` pairs. This allows it
to be, for example, constructed as a dict or a list of pairs.
Attributes
-----------
value: :class`int`
The raw value. This value is a bit array field of a 53-bit integer
representing the currently available flags. You should query
flags via the properties rather than using this raw value.
"""
__slots__ = ('value',)
def __init__(self, **kwargs):
self.value = self.ALL_OFF_VALUE
for key, value in kwargs.items():
if key not in self.VALID_FLAGS:
raise TypeError('%r is not a valid flag name.' % key)
setattr(self, key, value)
@classmethod
def _from_value(cls, value):
self = cls.__new__(cls)
self.value = value
return self
def __eq__(self, other):
return isinstance(other, SystemChannelFlags) and self.value == other.value
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.value)
def __repr__(self):
return '<SystemChannelFlags value=%s>' % self.value
def __iter__(self):
for name, value in self.__class__.__dict__.items():
if isinstance(value, _flag_descriptor):
yield (name, self._has_flag(value.flag))
# For some reason the flags in the Discord API are "inverted"
# ergo, if they're set then it means "suppress" (off in the GUI toggle)
# Since this is counter-intuitive from an API perspective and annoying
# these will be inverted automatically
def _has_flag(self, o):
return (self.value & o) != o
def _set_flag(self, o, toggle):
if toggle is True:
self.value &= ~o
elif toggle is False:
self.value |= o
else:
raise TypeError('Value to set for SystemChannelFlags must be a bool.')
@_flag_descriptor
def join_notifications(self):
""":class:`bool`: Returns True if the system channel is used for member join notifications."""
return 1
@_flag_descriptor
def premium_subscriptions(self):
""":class:`bool`: Returns True if the system channel is used for Nitro boosting notifications."""
return 2
class Guild(Hashable):
"""Represents a Discord guild.
@ -139,7 +254,7 @@ class Guild(Hashable):
'verification_level', 'explicit_content_filter', 'splash',
'_voice_states', '_system_channel_id', 'default_notifications',
'description', 'max_presences', 'max_members', 'premium_tier',
'premium_subscription_count')
'premium_subscription_count', '_system_channel_flags')
_PREMIUM_GUILD_LIMITS = {
None: _GuildLimit(emoji=50, bitrate=96e3, filesize=8388608),
@ -259,6 +374,7 @@ class Guild(Hashable):
self.max_members = guild.get('max_members')
self.premium_tier = guild.get('premium_tier', 0)
self.premium_subscription_count = guild.get('premium_subscription_count', 0)
self._system_channel_flags = guild.get('system_channel_flags', 0)
for mdata in guild.get('members', []):
member = Member(data=mdata, guild=self, state=state)
@ -405,6 +521,11 @@ class Guild(Hashable):
channel_id = self._system_channel_id
return channel_id and self._channels.get(channel_id)
@property
def system_channel_flags(self):
""":class:`SystemChannelFlags`: Returns the guild's system channel settings."""
return SystemChannelFlags._from_value(self._system_channel_flags)
@property
def emoji_limit(self):
""":class:`int`: The maximum number of emoji slots this guild has."""
@ -869,6 +990,8 @@ class Guild(Hashable):
The new vanity code for the guild.
system_channel: Optional[:class:`TextChannel`]
The new channel that is used for the system channel. Could be ``None`` for no system channel.
system_channel_flags: :class:`SystemChannelFlags`
The new system channel settings to use with the new system channel.
reason: Optional[:class:`str`]
The reason for editing this guild. Shows up on the audit log.
@ -973,6 +1096,12 @@ class Guild(Hashable):
raise InvalidArgument('explicit_content_filter field must be of type ContentFilter')
fields['explicit_content_filter'] = explicit_content_filter.value
system_channel_flags = fields.get('system_channel_flags', self.system_channel_flags)
if not isinstance(system_channel_flags, SystemChannelFlags):
raise InvalidArgument('system_channel_flags field must be of type SystemChannelFlags')
fields['system_channel_flags'] = system_channel_flags.value
await http.edit_guild(self.id, reason=reason, **fields)
async def fetch_member(self, member_id):

3
discord/http.py

@ -592,7 +592,8 @@ class HTTPClient:
valid_keys = ('name', 'region', 'icon', 'afk_timeout', 'owner_id',
'afk_channel_id', 'splash', 'verification_level',
'system_channel_id', 'default_message_notifications',
'description', 'explicit_content_filter', 'banner')
'description', 'explicit_content_filter', 'banner',
'system_channel_flags')
payload = {
k: v for k, v in fields.items() if k in valid_keys

7
docs/api.rst

@ -2311,6 +2311,13 @@ PermissionOverwrite
.. autoclass:: PermissionOverwrite
:members:
SystemChannelFlags
~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemChannelFlags
:members:
Exceptions
------------

Loading…
Cancel
Save