Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement MemberFlags #2489

Merged
merged 11 commits into from
Jun 30, 2024
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ These changes are available on the `master` branch, but have not yet been releas
([#2409](https://github.com/Pycord-Development/pycord/pull/2409)
- Added support for one-time purchases for Discord monetization.
([#2438](https://github.com/Pycord-Development/pycord/pull/2438))
- Added `MemberFlags`, and adds `bypass_verification` param to `Member.edit`
([#2489](https://github.com/Pycord-Development/pycord/pull/2489))

### Fixed

Expand Down
74 changes: 74 additions & 0 deletions discord/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"ApplicationFlags",
"ChannelFlags",
"SKUFlags",
"MemberFlags",
)

FV = TypeVar("FV", bound="flag_value")
Expand Down Expand Up @@ -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 SKUFlags are equal.
.. describe:: x != y

Checks if two SKUFlags 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.5

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 with :func:`~discord.Member.edit` to change if a member can bypass requirements.
"""
return 1 << 2

@flag_value
def started_onboarding(self):
""":class:`bool`: Returns ``True`` if the member has started onboarding."""
return 1 << 3
31 changes: 31 additions & 0 deletions discord/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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__ = (
Expand All @@ -284,6 +289,7 @@ class Member(discord.abc.Messageable, _UserTag):
"_state",
"_avatar",
"communication_disabled_until",
"flags",
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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|

Expand All @@ -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.

Expand Down Expand Up @@ -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
-------
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions discord/types/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Member(PartialMember, total=False):
pending: bool
permissions: str
communication_disabled_until: str
flags: int


class _OptionalMemberWithUser(PartialMember, total=False):
Expand Down
5 changes: 5 additions & 0 deletions docs/api/data_classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ Flags
.. autoclass:: SKUFlags()
:members:

.. attributetable:: MemberFlags

.. autoclass:: MemberFlags()
:members:

Colour
------

Expand Down
Loading