Skip to content

Commit

Permalink
Merge branch 'master' into ft/voice_states
Browse files Browse the repository at this point in the history
  • Loading branch information
Snipy7374 authored Nov 28, 2024
2 parents d0d88fb + d24e1de commit b20c888
Show file tree
Hide file tree
Showing 11 changed files with 139 additions and 24 deletions.
2 changes: 1 addition & 1 deletion changelog/1113.feature.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ Support application subscriptions and one-time purchases (see the :ddocs:`offici
- New types: :class:`SKU`, :class:`Entitlement`.
- New :attr:`Interaction.entitlements` attribute, and :meth:`InteractionResponse.require_premium` response type.
- New events: :func:`on_entitlement_create`, :func:`on_entitlement_update`, :func:`on_entitlement_delete`.
- New :class:`Client` methods: :meth:`~Client.skus`, :meth:`~Client.entitlements`, :meth:`~Client.create_entitlement`.
- New :class:`Client` methods: :meth:`~Client.skus`, :meth:`~Client.entitlements`, :meth:`~Client.fetch_entitlement`, :meth:`~Client.create_entitlement`.
2 changes: 1 addition & 1 deletion changelog/1186.feature.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ Support application subscriptions and one-time purchases (see the :ddocs:`offici
- New types: :class:`SKU`, :class:`Entitlement`.
- New :attr:`Interaction.entitlements` attribute, and :meth:`InteractionResponse.require_premium` response type.
- New events: :func:`on_entitlement_create`, :func:`on_entitlement_update`, :func:`on_entitlement_delete`.
- New :class:`Client` methods: :meth:`~Client.skus`, :meth:`~Client.entitlements`, :meth:`~Client.create_entitlement`.
- New :class:`Client` methods: :meth:`~Client.skus`, :meth:`~Client.entitlements`, :meth:`~Client.fetch_entitlement`, :meth:`~Client.create_entitlement`.
1 change: 1 addition & 0 deletions changelog/1245.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement :attr:`~MemberFlags.is_guest`, :attr:`~MemberFlags.started_home_actions`, :attr:`~MemberFlags.completed_home_actions`, :attr:`~MemberFlags.automod_quarantined_username`, :attr:`~MemberFlags.dm_settings_upsell_acknowledged` new member flags.
5 changes: 5 additions & 0 deletions changelog/1249.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Support application subscriptions and one-time purchases (see the :ddocs:`official docs <monetization/overview>` for more info).
- New types: :class:`SKU`, :class:`Entitlement`.
- New :attr:`Interaction.entitlements` attribute, and :meth:`InteractionResponse.require_premium` response type.
- New events: :func:`on_entitlement_create`, :func:`on_entitlement_update`, :func:`on_entitlement_delete`.
- New :class:`Client` methods: :meth:`~Client.skus`, :meth:`~Client.entitlements`, :meth:`~Client.fetch_entitlement`, :meth:`~Client.create_entitlement`.
1 change: 1 addition & 0 deletions changelog/1252.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Fix incorrect exception when using the :func:`~ext.commands.default_member_permissions` decorator on a :func:`~ext.commands.user_command` while also using the cog-level ``user_command_attrs`` field.
34 changes: 34 additions & 0 deletions disnake/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3147,6 +3147,7 @@ def entitlements(
guild: Optional[Snowflake] = None,
skus: Optional[Sequence[Snowflake]] = None,
exclude_ended: bool = False,
exclude_deleted: bool = True,
oldest_first: bool = False,
) -> EntitlementIterator:
"""Retrieves an :class:`.AsyncIterator` that enables receiving entitlements for the application.
Expand Down Expand Up @@ -3186,6 +3187,8 @@ def entitlements(
The SKUs for which entitlements are retrieved.
exclude_ended: :class:`bool`
Whether to exclude ended/expired entitlements. Defaults to ``False``.
exclude_deleted: :class:`bool`
Whether to exclude deleted entitlements. Defaults to ``True``.
oldest_first: :class:`bool`
If set to ``True``, return entries in oldest->newest order. Defaults to ``False``.
Expand All @@ -3209,9 +3212,40 @@ def entitlements(
guild_id=guild.id if guild is not None else None,
sku_ids=[sku.id for sku in skus] if skus else None,
exclude_ended=exclude_ended,
exclude_deleted=exclude_deleted,
oldest_first=oldest_first,
)

async def fetch_entitlement(self, entitlement_id: int, /) -> Entitlement:
"""|coro|
Retrieves a :class:`.Entitlement` for the given ID.
.. note::
This method is an API call. To get the entitlements of the invoking user/guild
in interactions, consider using :attr:`.Interaction.entitlements`.
.. versionadded:: 2.10
Parameters
----------
entitlement_id: :class:`int`
The ID of the entitlement to retrieve.
Raises
------
HTTPException
Retrieving the entitlement failed.
Returns
-------
:class:`.Entitlement`
The retrieved entitlement.
"""
data = await self.http.get_entitlement(self.application_id, entitlement_id=entitlement_id)
return Entitlement(data=data, state=self._connection)

async def create_entitlement(
self, sku: Snowflake, owner: Union[abc.User, Guild]
) -> Entitlement:
Expand Down
8 changes: 1 addition & 7 deletions disnake/ext/commands/ctx_menus_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,9 @@ def __init__(
self.auto_sync: bool = True if auto_sync is None else auto_sync

try:
default_perms: int = func.__default_member_permissions__
default_member_permissions = func.__default_member_permissions__
except AttributeError:
pass
else:
if default_member_permissions is not None:
raise ValueError(
"Cannot set `default_member_permissions` in both parameter and decorator"
)
default_member_permissions = default_perms

dm_permission = True if dm_permission is None else dm_permission

Expand Down
45 changes: 45 additions & 0 deletions disnake/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -2343,9 +2343,14 @@ class MemberFlags(BaseFlags):
def __init__(
self,
*,
automod_quarantined_username: bool = ...,
bypasses_verification: bool = ...,
completed_home_actions: bool = ...,
completed_onboarding: bool = ...,
did_rejoin: bool = ...,
dm_settings_upsell_acknowledged: bool = ...,
is_guest: bool = ...,
started_home_actions: bool = ...,
started_onboarding: bool = ...,
) -> None:
...
Expand All @@ -2370,6 +2375,46 @@ def started_onboarding(self):
""":class:`bool`: Returns ``True`` if the member has started onboarding."""
return 1 << 3

@flag_value
def is_guest(self):
""":class:`bool`: Returns ``True`` if the member is a guest and can only access the voice channel they were invited to.
.. versionadded:: 2.10
"""
return 1 << 4

@flag_value
def started_home_actions(self):
""":class:`bool`: Returns ``True`` if the member has started the Server Guide actions.
.. versionadded:: 2.10
"""
return 1 << 5

@flag_value
def completed_home_actions(self):
""":class:`bool`: Returns ``True`` if the member has completed the Server Guide actions.
.. versionadded:: 2.10
"""
return 1 << 6

@flag_value
def automod_quarantined_username(self):
""":class:`bool`: Returns ``True`` if the member's username, display name, or nickname is blocked by AutoMod.
.. versionadded:: 2.10
"""
return 1 << 7

@flag_value
def dm_settings_upsell_acknowledged(self):
""":class:`bool`: Returns ``True`` if the member has dismissed the DM settings upsell.
.. versionadded:: 2.10
"""
return 1 << 9


class RoleFlags(BaseFlags):
"""Wraps up Discord Role flags.
Expand Down
14 changes: 14 additions & 0 deletions disnake/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -2376,10 +2376,12 @@ def get_entitlements(
guild_id: Optional[Snowflake] = None,
sku_ids: Optional[SnowflakeList] = None,
exclude_ended: bool = False,
exclude_deleted: bool = False,
) -> Response[List[entitlement.Entitlement]]:
params: Dict[str, Any] = {
"limit": limit,
"exclude_ended": int(exclude_ended),
"exclude_deleted": int(exclude_deleted),
}
if before is not None:
params["before"] = before
Expand All @@ -2397,6 +2399,18 @@ def get_entitlements(
)
return self.request(r, params=params)

def get_entitlement(
self, application_id: Snowflake, entitlement_id: int
) -> Response[entitlement.Entitlement]:
return self.request(
Route(
"GET",
"/applications/{application_id}/entitlements/{entitlement_id}",
application_id=application_id,
entitlement_id=entitlement_id,
)
)

def create_test_entitlement(
self,
application_id: Snowflake,
Expand Down
4 changes: 4 additions & 0 deletions disnake/iterators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,7 @@ def __init__(
before: Optional[Union[Snowflake, datetime.datetime]] = None,
after: Optional[Union[Snowflake, datetime.datetime]] = None,
exclude_ended: bool = False,
exclude_deleted: bool = True,
oldest_first: bool = False,
) -> None:
if isinstance(before, datetime.datetime):
Expand All @@ -1059,6 +1060,7 @@ def __init__(
self.guild_id: Optional[int] = guild_id
self.sku_ids: Optional[List[int]] = sku_ids
self.exclude_ended: bool = exclude_ended
self.exclude_deleted: bool = exclude_deleted

self.state: ConnectionState = state
self.request = state.http.get_entitlements
Expand Down Expand Up @@ -1116,6 +1118,7 @@ async def _before_strategy(self, retrieve: int) -> List[EntitlementPayload]:
user_id=self.user_id,
guild_id=self.guild_id,
exclude_ended=self.exclude_ended,
exclude_deleted=self.exclude_deleted,
)

if len(data):
Expand All @@ -1133,6 +1136,7 @@ async def _after_strategy(self, retrieve: int) -> List[EntitlementPayload]:
user_id=self.user_id,
guild_id=self.guild_id,
exclude_ended=self.exclude_ended,
exclude_deleted=self.exclude_deleted,
)

if len(data):
Expand Down
47 changes: 32 additions & 15 deletions tests/ext/commands/test_base_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,33 @@
from disnake.ext import commands


class DecoratorMeta:
def __init__(self, type: str) -> None:
self.decorator = {
"slash": commands.slash_command,
"user": commands.user_command,
"message": commands.message_command,
}[type]
self.attr_key = f"{type}_command_attrs"


class TestDefaultPermissions:
def test_decorator(self) -> None:
@pytest.fixture(params=["slash", "user", "message"])
def meta(self, request):
return DecoratorMeta(request.param)

def test_decorator(self, meta: DecoratorMeta) -> None:
class Cog(commands.Cog):
@commands.slash_command(default_member_permissions=64)
@meta.decorator(default_member_permissions=64)
async def cmd(self, _) -> None:
...

@commands.default_member_permissions(64)
@commands.slash_command()
@meta.decorator()
async def above(self, _) -> None:
...

@commands.slash_command()
@meta.decorator()
@commands.default_member_permissions(64)
async def below(self, _) -> None:
...
Expand All @@ -29,52 +43,55 @@ async def below(self, _) -> None:
assert c.above.default_member_permissions == Permissions(64)
assert c.below.default_member_permissions == Permissions(64)

def test_decorator_overwrite(self) -> None:
def test_decorator_overwrite(self, meta: DecoratorMeta) -> None:
# putting the decorator above should fail
with pytest.raises(ValueError, match="Cannot set `default_member_permissions`"):

class Cog(commands.Cog):
@commands.default_member_permissions(32)
@commands.slash_command(default_member_permissions=64)
@meta.decorator(default_member_permissions=64)
async def above(self, _) -> None:
...

# putting the decorator below shouldn't fail
# (this is a side effect of how command copying works,
# putting the decorator below shouldn't fail, for now
# FIXME: (this is a side effect of how command copying works,
# and while this *should* probably fail, we're just testing
# for regressions for now)
class Cog2(commands.Cog):
@commands.slash_command(default_member_permissions=64)
@meta.decorator(default_member_permissions=64)
@commands.default_member_permissions(32)
async def below(self, _) -> None:
...

for c in (Cog2, Cog2()):
assert c.below.default_member_permissions == Permissions(32)

def test_attrs(self) -> None:
class Cog(commands.Cog, slash_command_attrs={"default_member_permissions": 32}):
@commands.slash_command()
def test_attrs(self, meta: DecoratorMeta) -> None:
kwargs = {meta.attr_key: {"default_member_permissions": 32}}

class Cog(commands.Cog, **kwargs):
@meta.decorator()
async def no_overwrite(self, _) -> None:
...

@commands.slash_command(default_member_permissions=64)
@meta.decorator(default_member_permissions=64)
async def overwrite(self, _) -> None:
...

@commands.default_member_permissions(64)
@commands.slash_command()
@meta.decorator()
async def overwrite_decorator_above(self, _) -> None:
...

@commands.slash_command()
@meta.decorator()
@commands.default_member_permissions(64)
async def overwrite_decorator_below(self, _) -> None:
...

assert Cog.no_overwrite.default_member_permissions is None
assert Cog().no_overwrite.default_member_permissions == Permissions(32)

# all of these should overwrite the cog-level attr
assert Cog.overwrite.default_member_permissions == Permissions(64)
assert Cog().overwrite.default_member_permissions == Permissions(64)

Expand Down

0 comments on commit b20c888

Please sign in to comment.