Skip to content

Commit 231ff62

Browse files
committed
Add application intent request
1 parent 6276a9a commit 231ff62

File tree

3 files changed

+172
-12
lines changed

3 files changed

+172
-12
lines changed

discord/application.py

Lines changed: 143 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@
7474
from .types.application import (
7575
EULA as EULAPayload,
7676
Achievement as AchievementPayload,
77-
ActivityStatistics as ActivityStatisticsPayload,
7877
Application as ApplicationPayload,
78+
ApplicationActivityStatistics as ApplicationActivityStatisticsPayload,
7979
ApplicationExecutable as ApplicationExecutablePayload,
8080
ApplicationInstallParams as ApplicationInstallParamsPayload,
8181
Asset as AssetPayload,
@@ -94,6 +94,7 @@
9494
PartialApplication as PartialApplicationPayload,
9595
ThirdPartySKU as ThirdPartySKUPayload,
9696
UnverifiedApplication as UnverifiedApplicationPayload,
97+
UserActivityStatistics as UserActivityStatisticsPayload,
9798
WhitelistedUser as WhitelistedUserPayload,
9899
)
99100
from .types.user import PartialUser as PartialUserPayload
@@ -1018,6 +1019,10 @@ class ApplicationActivityStatistics:
10181019
10191020
.. versionadded:: 2.0
10201021
1022+
.. versionchanged:: 2.1
1023+
1024+
``updated_at`` was renamed to ``last_played_at``.
1025+
10211026
Attributes
10221027
-----------
10231028
application_id: :class:`int`
@@ -1026,18 +1031,25 @@ class ApplicationActivityStatistics:
10261031
The ID of the user.
10271032
duration: :class:`int`
10281033
How long the user has ever played the game in seconds.
1034+
This will be the last session duration for global statistics, and the total duration otherwise.
10291035
sku_duration: :class:`int`
1030-
How long the user has ever played the game on Discord in seconds.
1031-
updated_at: :class:`datetime.datetime`
1036+
How long the user has ever played the game through Discord in seconds.
1037+
Only provided for the current user.
1038+
first_played_at: Optional[:class:`datetime.datetime`]
1039+
When the user first played the game.
1040+
Only provided for the current user.
1041+
1042+
.. versionadded:: 2.1
1043+
last_played_at: :class:`datetime.datetime`
10321044
When the user last played the game.
10331045
"""
10341046

1035-
__slots__ = ('application_id', 'user_id', 'duration', 'sku_duration', 'updated_at', '_state')
1047+
__slots__ = ('application_id', 'user_id', 'duration', 'sku_duration', 'first_played_at', 'last_played_at', '_state')
10361048

10371049
def __init__(
10381050
self,
10391051
*,
1040-
data: Union[ActivityStatisticsPayload, GlobalActivityStatisticsPayload],
1052+
data: Union[ApplicationActivityStatisticsPayload, GlobalActivityStatisticsPayload, UserActivityStatisticsPayload],
10411053
state: ConnectionState,
10421054
application_id: Optional[int] = None,
10431055
) -> None:
@@ -1046,10 +1058,13 @@ def __init__(
10461058
self.user_id: int = int(data['user_id']) if 'user_id' in data else state.self_id # type: ignore
10471059
self.duration: int = data.get('total_duration', data.get('duration', 0))
10481060
self.sku_duration: int = data.get('total_discord_sku_duration', 0)
1049-
self.updated_at: datetime = utils.parse_time(data.get('last_played_at', data.get('updated_at'))) or utils.utcnow()
1061+
self.first_played_at: Optional[datetime] = utils.parse_time(data.get('first_played_at'))
1062+
self.last_played_at: datetime = (
1063+
utils.parse_time(data.get('last_played_at', data.get('updated_at'))) or utils.utcnow()
1064+
)
10501065

10511066
def __repr__(self) -> str:
1052-
return f'<ApplicationActivityStatistics user_id={self.user_id} duration={self.duration} last_played_at={self.updated_at!r}>'
1067+
return f'<ApplicationActivityStatistics user_id={self.user_id} duration={self.duration} last_played_at={self.last_played_at!r}>'
10531068

10541069
@property
10551070
def user(self) -> Optional[User]:
@@ -1063,7 +1078,7 @@ async def application(self) -> PartialApplication:
10631078
10641079
Raises
10651080
------
1066-
HTTPException
1081+
HTTPExceptionq
10671082
Fetching the application failed.
10681083
"""
10691084
state = self._state
@@ -2935,6 +2950,126 @@ async def edit_bot(
29352950

29362951
return self.bot
29372952

2953+
@overload
2954+
async def request_intents(
2955+
self,
2956+
intents: ApplicationFlags,
2957+
description: str,
2958+
*,
2959+
presence_use_case: str = ...,
2960+
presence_supplemental_material: str = ...,
2961+
presence_store_off_platform: bool = ...,
2962+
presence_retention: bool = ...,
2963+
presence_encrypted: bool = ...,
2964+
presence_opt_out_stored: bool = ...,
2965+
presence_contact_deletion: str = ...,
2966+
guild_members_use_case: str = ...,
2967+
guild_members_supplemental_material: str = ...,
2968+
guild_members_store_off_platform: bool = ...,
2969+
guild_members_retention: bool = ...,
2970+
guild_members_encrypted: bool = ...,
2971+
guild_members_contact_deletion: str = ...,
2972+
message_content_use_case: str = ...,
2973+
message_content_supplemental_material: str = ...,
2974+
message_content_store_off_platform: bool = ...,
2975+
message_content_retention: bool = ...,
2976+
message_content_encrypted: bool = ...,
2977+
message_content_opt_out_stored: bool = ...,
2978+
message_content_ai_training: bool = ...,
2979+
message_content_privacy_policy_public: bool = ...,
2980+
message_content_privacy_policy_location: str = ...,
2981+
message_content_privacy_policy_example: str = ...,
2982+
message_content_contact_deletion: str = ...,
2983+
) -> None:
2984+
...
2985+
2986+
@overload
2987+
async def request_intents(self, intents: ApplicationFlags, description: str) -> None:
2988+
...
2989+
2990+
async def request_intents(self, intents: ApplicationFlags, description: str, **kwargs: Any) -> None:
2991+
"""|coro|
2992+
2993+
Requests the specified Gateway intents for this application.
2994+
2995+
.. versionadded:: 2.1
2996+
2997+
Parameters
2998+
-----------
2999+
intents: :class:`ApplicationFlags`
3000+
The intents to request.
3001+
description: :class:`str`
3002+
The description of the application (50-2000 characters).
3003+
presence_use_case: :class:`str`
3004+
The use case for requesting the presence intent (50-2000 characters).
3005+
Required if requesting :attr:`ApplicationFlags.gateway_presence`.
3006+
presence_supplemental_material: :class:`str`
3007+
The supplemental material for the requested presence intent (5-2000 characters).
3008+
Required if requesting :attr:`ApplicationFlags.gateway_presence`.
3009+
presence_store_off_platform: :class:`bool`
3010+
Whether the application stores presence data off-platform.
3011+
Required if requesting :attr:`ApplicationFlags.gateway_presence`.
3012+
presence_retention: :class:`bool`
3013+
Whether the application retains presence data for 30 days or less.
3014+
presence_encrypted: :class:`bool`
3015+
Whether the application encrypts stored presence data at rest.
3016+
presence_opt_out_stored: :class:`bool`
3017+
Whether application users can opt out of having their presence data stored.
3018+
presence_contact_deletion: :class:`str`
3019+
How application users can request the deletion of their presence data (25-2000 characters).
3020+
guild_members_use_case: :class:`str`
3021+
The use case for requesting the guild members intent (50-2000 characters).
3022+
Required if requesting :attr:`ApplicationFlags.gateway_guild_members`.
3023+
guild_members_supplemental_material: :class:`str`
3024+
The supplemental material for the requested guild members intent (5-2000 characters).
3025+
Required if requesting :attr:`ApplicationFlags.gateway_guild_members`.
3026+
guild_members_store_off_platform: :class:`bool`
3027+
Whether the application stores guild member data off-platform.
3028+
Required if requesting :attr:`ApplicationFlags.gateway_guild_members`.
3029+
guild_members_retention: :class:`bool`
3030+
Whether the application retains guild member data for 30 days or less.
3031+
guild_members_encrypted: :class:`bool`
3032+
Whether the application encrypts stored guild member data at rest.
3033+
guild_members_contact_deletion: :class:`str`
3034+
How application users can request the deletion of their guild member data (25-2000 characters).
3035+
message_content_use_case: :class:`str`
3036+
The use case for requesting the message content intent (50-2000 characters).
3037+
Required if requesting :attr:`ApplicationFlags.gateway_message_content`.
3038+
message_content_supplemental_material: :class:`str`
3039+
The supplemental material for the requested message content intent (5-2000 characters).
3040+
Required if requesting :attr:`ApplicationFlags.gateway_message_content`.
3041+
message_content_store_off_platform: :class:`bool`
3042+
Whether the application stores message content data off-platform.
3043+
Required if requesting :attr:`ApplicationFlags.gateway_message_content`.
3044+
message_content_retention: :class:`bool`
3045+
Whether the application retains message content data for 30 days or less.
3046+
message_content_encrypted: :class:`bool`
3047+
Whether the application encrypts stored message content data at rest.
3048+
message_content_opt_out_stored: :class:`bool`
3049+
Whether application users can opt out of having their message content data stored.
3050+
message_content_ai_training: :class:`bool`
3051+
Whether the application uses message content data for AI training.
3052+
message_content_privacy_policy_public: :class:`bool`
3053+
Whether the application has a public privacy policy detailing how message content data is used.
3054+
message_content_privacy_policy_location: :class:`str`
3055+
Where the application's privacy policy can be found (25-2000 characters).
3056+
message_content_privacy_policy_example: :class:`str`
3057+
A link to or screenshots of the application's privacy policy (25-2000 characters).
3058+
message_content_contact_deletion: :class:`str`
3059+
How application users can request the deletion of their message content data (25-2000 characters).
3060+
"""
3061+
payload = {'application_description': description, 'intents_flags_requested': intents._to_intents()}
3062+
for key, value in kwargs.items():
3063+
if value in (MISSING, None):
3064+
continue
3065+
if key.endswith('use_case'):
3066+
key += '_description'
3067+
elif key.endswith('supplemental_material'):
3068+
key = key.replace('supplemental_material', 'use_case_supplemental_material_description')
3069+
payload[f'intents_gateway_{key}'] = value
3070+
3071+
await self._state.http.request_app_intents(self.id, payload)
3072+
29383073
async def whitelisted(self) -> List[ApplicationTester]:
29393074
"""|coro|
29403075

discord/flags.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,19 @@ class ApplicationFlags(BaseFlags):
12971297

12981298
__slots__ = ()
12991299

1300+
def _to_intents(self) -> int:
1301+
# Start with a base value of 0
1302+
intents = 0
1303+
1304+
if self.gateway_presence_limited or self.gateway_presence:
1305+
intents |= 1 << 12
1306+
if self.gateway_guild_members_limited or self.gateway_guild_members:
1307+
intents |= 1 << 14
1308+
if self.gateway_message_content_limited or self.gateway_message_content:
1309+
intents |= 1 << 18
1310+
1311+
return intents
1312+
13001313
@flag_value
13011314
def embedded_released(self):
13021315
""":class:`bool`: Returns ``True`` if the embedded application is released to the public."""
@@ -2771,6 +2784,11 @@ def thread(self):
27712784
""":class:`bool`: Returns ``True`` if the read state is for a thread."""
27722785
return 1 << 1
27732786

2787+
@flag_value
2788+
def mention_low_importance(self):
2789+
""":class:`bool`: Returns ``True`` if the read state's badge is of low importance."""
2790+
return 1 << 2
2791+
27742792

27752793
@fill_with_flags()
27762794
class InviteFlags(BaseFlags):

discord/types/application.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,14 +250,21 @@ class Manifest(TypedDict):
250250
url: Optional[str]
251251

252252

253-
class ActivityStatistics(TypedDict):
254-
application_id: NotRequired[Snowflake]
255-
user_id: NotRequired[Snowflake]
253+
class _BaseActivityStatistics(TypedDict):
256254
total_duration: int
257-
total_discord_sku_duration: NotRequired[int]
258255
last_played_at: str
259256

260257

258+
class UserActivityStatistics(_BaseActivityStatistics):
259+
application_id: Snowflake
260+
total_discord_sku_duration: NotRequired[int]
261+
first_played_at: Optional[str]
262+
263+
264+
class ApplicationActivityStatistics(_BaseActivityStatistics):
265+
user_id: Snowflake
266+
267+
261268
class GlobalActivityStatistics(TypedDict):
262269
application_id: Snowflake
263270
user_id: Snowflake

0 commit comments

Comments
 (0)