Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into feature/user-apps-v2
Browse files Browse the repository at this point in the history
  • Loading branch information
shiftinv committed Dec 13, 2024
2 parents 432ca57 + 08b2bea commit 10279d0
Show file tree
Hide file tree
Showing 20 changed files with 488 additions and 20 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/1187.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for message forwarding. New :class:`ForwardedMessage`, new enum :class:`MessageReferenceType`, new method :func:`Message.forward`, edited :class:`MessageReference` to support message forwarding.
1 change: 1 addition & 0 deletions changelog/1200.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
|commands| Fix usage of :attr:`~ext.commands.BucketType.role`\-type cooldowns in threads, which incorrectly operated on a per-channel basis instead.
1 change: 1 addition & 0 deletions changelog/1216.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :meth:`Guild.fetch_voice_state` to fetch the :class:`VoiceState` of a member.
1 change: 1 addition & 0 deletions changelog/1238.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for ``BaseFlags`` to allow comparison with ``flag_values`` and vice versa.
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`.
6 changes: 6 additions & 0 deletions disnake/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1604,6 +1604,12 @@ async def send(
.. versionadded:: 1.6
.. note::
Passing a :class:`.Message` or :class:`.PartialMessage` will only allow replies. To forward a message
you must explicitly transform the message to a :class:`.MessageReference` using :meth:`.Message.to_reference` and specify the :class:`.MessageReferenceType`,
or use :meth:`.Message.forward`.
mention_author: Optional[:class:`bool`]
If set, overrides the :attr:`.AllowedMentions.replied_user` attribute of ``allowed_mentions``.
Expand Down
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: 8 additions & 0 deletions disnake/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"EntitlementType",
"PollLayoutType",
"VoiceChannelEffectAnimationType",
"MessageReferenceType",
)


Expand Down Expand Up @@ -1415,6 +1416,13 @@ class VoiceChannelEffectAnimationType(Enum):
basic = 1


class MessageReferenceType(Enum):
default = 0
"""A standard message reference used in message replies."""
forward = 1
"""Reference used to point to a message at a point in time (forward)."""


T = TypeVar("T")


Expand Down
10 changes: 4 additions & 6 deletions disnake/ext/commands/cooldowns.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from collections import deque
from typing import TYPE_CHECKING, Any, Callable, Deque, Dict, Optional

from disnake.abc import PrivateChannel
from disnake.enums import Enum
from disnake.member import Member

from .errors import MaxConcurrencyReached

Expand Down Expand Up @@ -47,11 +47,9 @@ def get_key(self, msg: Message) -> Any:
elif self is BucketType.category:
return (msg.channel.category or msg.channel).id # type: ignore
elif self is BucketType.role:
# we return the channel id of a private-channel as there are only roles in guilds
# and that yields the same result as for a guild with only the @everyone role
# NOTE: PrivateChannel doesn't actually have an id attribute but we assume we are
# recieving a DMChannel or GroupChannel which inherit from PrivateChannel and do
return (msg.channel if isinstance(msg.channel, PrivateChannel) else msg.author.top_role).id # type: ignore
# if author is not a Member we are in a private-channel context; returning its id
# yields the same result as for a guild with only the @everyone role
return (msg.author.top_role if isinstance(msg.author, Member) else msg.channel).id

def __call__(self, msg: Message) -> Any:
return self.get_key(msg)
Expand Down
27 changes: 26 additions & 1 deletion disnake/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ def __init__(self, func: Callable[[Any], int]) -> None:
self.__doc__ = func.__doc__
self._parent: Type[T] = MISSING

def __eq__(self, other: Any) -> bool:
if isinstance(other, flag_value):
return self.flag == other.flag
if isinstance(other, BaseFlags):
return self._parent is other.__class__ and self.flag == other.value
return False

def __ne__(self, other: Any) -> bool:
return not self.__eq__(other)

def __or__(self, other: Union[flag_value[T], T]) -> T:
if isinstance(other, BaseFlags):
if self._parent is not other.__class__:
Expand Down Expand Up @@ -150,7 +160,11 @@ def _from_value(cls, value: int) -> Self:
return self

def __eq__(self, other: Any) -> bool:
return isinstance(other, self.__class__) and self.value == other.value
if isinstance(other, self.__class__):
return self.value == other.value
if isinstance(other, flag_value):
return self.__class__ is other._parent and self.value == other.flag
return False

def __ne__(self, other: Any) -> bool:
return not self.__eq__(other)
Expand Down Expand Up @@ -588,6 +602,7 @@ def __init__(
crossposted: bool = ...,
ephemeral: bool = ...,
failed_to_mention_roles_in_thread: bool = ...,
has_snapshot: bool = ...,
has_thread: bool = ...,
is_crossposted: bool = ...,
is_voice_message: bool = ...,
Expand Down Expand Up @@ -680,6 +695,16 @@ def is_voice_message(self):
"""
return 1 << 13

@flag_value
def has_snapshot(self):
""":class:`bool`: Returns ``True`` if the message is a forward message.
Messages with this flag will have only the forward data, and no other content.
.. versionadded:: 2.10
"""
return 1 << 14


class PublicUserFlags(BaseFlags):
"""Wraps up the Discord User Public flags.
Expand Down
40 changes: 40 additions & 0 deletions disnake/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -4673,6 +4673,46 @@ async def fetch_voice_regions(self) -> List[VoiceRegion]:
data = await self._state.http.get_guild_voice_regions(self.id)
return [VoiceRegion(data=region) for region in data]

async def fetch_voice_state(self, member_id: int, /) -> VoiceState:
"""|coro|
Fetches the :class:`VoiceState` of a member.
.. note::
This method is an API call. For general usage, consider :attr:`Member.voice` instead.
.. versionadded:: 2.10
Parameters
----------
member_id: :class:`int`
The ID of the member.
Raises
------
NotFound
The member for which you tried to fetch a voice state is not
connected to a channel in this guild.
Forbidden
You do not have permission to fetch the member's voice state.
HTTPException
Fetching the voice state failed.
Returns
-------
:class:`VoiceState`
The voice state of the member.
"""
if member_id == self.me.id:
data = await self._state.http.get_my_voice_state(self.id)
else:
data = await self._state.http.get_voice_state(self.id, member_id)

channel_id = utils._get_as_snowflake(data, "channel_id")
channel: Optional[VocalGuildChannel] = self.get_channel(channel_id) # type: ignore
return VoiceState(data=data, channel=channel)

async def change_voice_state(
self, *, channel: Optional[Snowflake], self_mute: bool = False, self_deaf: bool = False
) -> None:
Expand Down
25 changes: 25 additions & 0 deletions disnake/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,17 @@ def change_nickname(
}
return self.request(r, json=payload, reason=reason)

def get_my_voice_state(self, guild_id: Snowflake) -> Response[voice.GuildVoiceState]:
return self.request(Route("GET", "/guilds/{guild_id}/voice-states/@me", guild_id=guild_id))

def get_voice_state(
self, guild_id: Snowflake, user_id: Snowflake
) -> Response[voice.GuildVoiceState]:
r = Route(
"GET", "/guilds/{guild_id}/voice-states/{user_id}", guild_id=guild_id, user_id=user_id
)
return self.request(r)

def edit_my_voice_state(self, guild_id: Snowflake, payload: Dict[str, Any]) -> Response[None]:
r = Route("PATCH", "/guilds/{guild_id}/voice-states/@me", guild_id=guild_id)
return self.request(r, json=payload)
Expand Down Expand Up @@ -2365,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 @@ -2386,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
8 changes: 6 additions & 2 deletions disnake/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,11 +387,15 @@ def _update_from_message(self, data: MemberPayload) -> None:

@classmethod
def _try_upgrade(
cls, *, data: UserWithMemberPayload, guild: Guild, state: ConnectionState
cls,
*,
data: Union[UserPayload, UserWithMemberPayload],
guild: Guild,
state: ConnectionState,
) -> Union[User, Self]:
# A User object with a 'member' key
try:
member_data = data.pop("member")
member_data = data.pop("member") # type: ignore
except KeyError:
return state.create_user(data)
else:
Expand Down
Loading

0 comments on commit 10279d0

Please sign in to comment.