aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2019-06-06 22:30:02 -0400
committerRapptz <[email protected]>2019-06-06 22:30:02 -0400
commit320dbc06182ce404af3fcc9749dc26428e6459eb (patch)
tree651d46786d5d022078f28e0587dcc0c80a98b755
parentFix stray colon in Asset related docstrings (diff)
downloaddiscord.py-320dbc06182ce404af3fcc9749dc26428e6459eb.tar.xz
discord.py-320dbc06182ce404af3fcc9749dc26428e6459eb.zip
Add support for system channel flags
-rw-r--r--discord/__init__.py2
-rw-r--r--discord/guild.py131
-rw-r--r--discord/http.py3
-rw-r--r--docs/api.rst7
4 files changed, 140 insertions, 3 deletions
diff --git a/discord/__init__.py b/discord/__init__.py
index 5a26c069..4586be59 100644
--- a/discord/__init__.py
+++ b/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
diff --git a/discord/guild.py b/discord/guild.py
index ae7140fa..fc8d22b9 100644
--- a/discord/guild.py
+++ b/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)
@@ -406,6 +522,11 @@ class Guild(Hashable):
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."""
more_emoji = 200 if 'MORE_EMOJI' in self.features else 50
@@ -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):
diff --git a/discord/http.py b/discord/http.py
index bfbb4201..d3ef0b87 100644
--- a/discord/http.py
+++ b/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
diff --git a/docs/api.rst b/docs/api.rst
index 2464ffee..55ce36b2 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -2311,6 +2311,13 @@ PermissionOverwrite
.. autoclass:: PermissionOverwrite
:members:
+SystemChannelFlags
+~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: SystemChannelFlags
+ :members:
+
+
Exceptions
------------