From de117fec609b391e28ddd8fba83e4b47569156be Mon Sep 17 00:00:00 2001 From: UK <41271523+NeloBlivion@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:18:01 +0100 Subject: [PATCH] feat: implement MemberFlags (#2489) --- CHANGELOG.md | 3 ++ discord/flags.py | 74 +++++++++++++++++++++++++++++++++++++++ discord/member.py | 31 ++++++++++++++++ discord/types/member.py | 1 + docs/api/data_classes.rst | 5 +++ 5 files changed, 114 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c75a9b1e1..13a0bafdd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,9 @@ These changes are available on the `master` branch, but have not yet been releas ([#2438](https://github.com/Pycord-Development/pycord/pull/2438)) - Added `Attachment.title`. ([#2486](https://github.com/Pycord-Development/pycord/pull/2486)) +- Added `MemberFlags`. ([#2489](https://github.com/Pycord-Development/pycord/pull/2489)) +- Added `bypass_verification` parameter to `Member.edit`. + ([#2489](https://github.com/Pycord-Development/pycord/pull/2489)) ### Fixed diff --git a/discord/flags.py b/discord/flags.py index 37fd8baa24..df521eca1f 100644 --- a/discord/flags.py +++ b/discord/flags.py @@ -39,6 +39,7 @@ "ApplicationFlags", "ChannelFlags", "SKUFlags", + "MemberFlags", ) FV = TypeVar("FV", bound="flag_value") @@ -1684,3 +1685,76 @@ def guild_subscription(self): def user_subscription(self): """:class:`bool`: Returns ``True`` if the SKU is a user subscription.""" return 1 << 8 + + +@fill_with_flags() +class MemberFlags(BaseFlags): + r"""Wraps up the Discord Member flags. + + .. container:: operations + + .. describe:: x == y + + Checks if two MemberFlags are equal. + .. describe:: x != y + + Checks if two MemberFlags are not equal. + .. describe:: x + y + + Adds two flags together. Equivalent to ``x | y``. + .. describe:: x - y + + Subtracts two flags from each other. + .. describe:: x | y + + Returns the union of two flags. Equivalent to ``x + y``. + .. describe:: x & y + + Returns the intersection of two flags. + .. describe:: ~x + + Returns the inverse of a flag. + .. 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. + Note that aliases are not shown. + + .. versionadded:: 2.6 + + Attributes + ----------- + value: :class:`int` + The raw value. You should query flags via the properties + rather than using this raw value. + """ + + __slots__ = () + + @flag_value + def did_rejoin(self): + """:class:`bool`: Returns ``True`` if the member left and rejoined the guild.""" + return 1 << 0 + + @flag_value + def completed_onboarding(self): + """:class:`bool`: Returns ``True`` if the member has completed onboarding.""" + return 1 << 1 + + @flag_value + def bypasses_verification(self): + """:class:`bool`: Returns ``True`` if the member is exempt from verification requirements. + + .. note:: + + This can be edited through :func:`~discord.Member.edit`. + """ + return 1 << 2 + + @flag_value + def started_onboarding(self): + """:class:`bool`: Returns ``True`` if the member has started onboarding.""" + return 1 << 3 diff --git a/discord/member.py b/discord/member.py index 57c04b2936..18ebf1267f 100644 --- a/discord/member.py +++ b/discord/member.py @@ -39,6 +39,7 @@ from .asset import Asset from .colour import Colour from .enums import Status, try_enum +from .flags import MemberFlags from .object import Object from .permissions import Permissions from .user import BaseUser, User, _UserTag @@ -269,6 +270,10 @@ class Member(discord.abc.Messageable, _UserTag): An aware datetime object that specifies the date and time in UTC when the member will be removed from timeout. .. versionadded:: 2.0 + flags: :class:`MemberFlags` + Extra attributes of the member. + + .. versionadded:: 2.6 """ __slots__ = ( @@ -284,6 +289,7 @@ class Member(discord.abc.Messageable, _UserTag): "_state", "_avatar", "communication_disabled_until", + "flags", ) if TYPE_CHECKING: @@ -325,6 +331,7 @@ def __init__( self.communication_disabled_until: datetime.datetime | None = utils.parse_time( data.get("communication_disabled_until") ) + self.flags: MemberFlags = MemberFlags._from_value(data.get("flags", 0)) def __str__(self) -> str: return str(self._user) @@ -400,6 +407,7 @@ def _copy(cls: type[M], member: M) -> M: self._state = member._state self._avatar = member._avatar self.communication_disabled_until = member.communication_disabled_until + self.flags = member.flags # Reference will not be copied unless necessary by PRESENCE_UPDATE # See below @@ -429,6 +437,7 @@ def _update(self, data: MemberPayload) -> None: self.communication_disabled_until = utils.parse_time( data.get("communication_disabled_until") ) + self.flags = MemberFlags._from_value(data.get("flags", 0)) def _presence_update( self, data: PartialPresenceUpdate, user: UserPayload @@ -729,6 +738,7 @@ async def edit( voice_channel: VocalGuildChannel | None = MISSING, reason: str | None = None, communication_disabled_until: datetime.datetime | None = MISSING, + bypass_verification: bool | None = MISSING, ) -> Member | None: """|coro| @@ -751,6 +761,18 @@ async def edit( +------------------------------+--------------------------------------+ | communication_disabled_until | :attr:`Permissions.moderate_members` | +------------------------------+--------------------------------------+ + | bypass_verification | See note below | + +------------------------------+--------------------------------------+ + + .. note:: + + `bypass_verification` may be edited under three scenarios: + + - Client has :attr:`Permissions.manage_guild` + + - Client has :attr:`Permissions.manage_roles` + + - Client has ALL THREE of :attr:`Permissions.moderate_members`, :attr:`Permissions.kick_members`, and :attr:`Permissions.ban_members` All parameters are optional. @@ -785,6 +807,10 @@ async def edit( from timeout. .. versionadded:: 2.0 + bypass_verification: Optional[:class:`bool`] + Indicates if the member should bypass the guild's verification requirements. + + .. versionadded:: 2.6 Returns ------- @@ -849,6 +875,11 @@ async def edit( else: payload["communication_disabled_until"] = communication_disabled_until + if bypass_verification is not MISSING: + flags = MemberFlags._from_value(self.flags.value) + flags.bypasses_verification = bypass_verification + payload["flags"] = flags.value + if payload: data = await http.edit_member(guild_id, self.id, reason=reason, **payload) return Member(data=data, guild=self.guild, state=self._state) diff --git a/discord/types/member.py b/discord/types/member.py index c6fdf6183a..0bc1071fb1 100644 --- a/discord/types/member.py +++ b/discord/types/member.py @@ -48,6 +48,7 @@ class Member(PartialMember, total=False): pending: bool permissions: str communication_disabled_until: str + flags: int class _OptionalMemberWithUser(PartialMember, total=False): diff --git a/docs/api/data_classes.rst b/docs/api/data_classes.rst index f0508ac09b..4c4de34e5a 100644 --- a/docs/api/data_classes.rst +++ b/docs/api/data_classes.rst @@ -166,6 +166,11 @@ Flags .. autoclass:: SKUFlags() :members: +.. attributetable:: MemberFlags + +.. autoclass:: MemberFlags() + :members: + Colour ------