Browse Source

Add missing application fields, update Application.create_bot return type, add Application.edit_bot

pull/10109/head
dolfies 2 years ago
parent
commit
91035c97cc
  1. 164
      discord/application.py
  2. 2
      discord/http.py
  3. 31
      discord/types/application.py

164
discord/application.py

@ -587,15 +587,9 @@ class ApplicationBot(User):
----------- -----------
application: :class:`Application` application: :class:`Application`
The application that the bot is attached to. The application that the bot is attached to.
public: :class:`bool`
Whether the bot can be invited by anyone or if it is locked
to the application owner.
require_code_grant: :class:`bool`
Whether the bot requires the completion of the full OAuth2 code
grant flow to join.
""" """
__slots__ = ('application', 'public', 'require_code_grant') __slots__ = ('application',)
def __init__(self, *, data: PartialUserPayload, state: ConnectionState, application: Application): def __init__(self, *, data: PartialUserPayload, state: ConnectionState, application: Application):
super().__init__(state=state, data=data) super().__init__(state=state, data=data)
@ -603,12 +597,20 @@ class ApplicationBot(User):
def _update(self, data: PartialUserPayload) -> None: def _update(self, data: PartialUserPayload) -> None:
super()._update(data) super()._update(data)
self.public: bool = data.get('public', True)
self.require_code_grant: bool = data.get('require_code_grant', False)
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<ApplicationBot id={self.id} name={self.name!r} discriminator={self.discriminator!r} public={self.public} require_code_grant={self.require_code_grant}>' return f'<ApplicationBot id={self.id} name={self.name!r} discriminator={self.discriminator!r} public={self.public} require_code_grant={self.require_code_grant}>'
@property
def public(self) -> bool:
""":class:`bool`: Whether the bot can be invited by anyone or if it is locked to the application owner."""
return self.application.public
@property
def require_code_grant(self) -> bool:
""":class:`bool`: Whether the bot requires the completion of the full OAuth2 code grant flow to join."""
return self.application.require_code_grant
@property @property
def bio(self) -> Optional[str]: def bio(self) -> Optional[str]:
"""Optional[:class:`str`]: Returns the bot's 'about me' section.""" """Optional[:class:`str`]: Returns the bot's 'about me' section."""
@ -645,12 +647,12 @@ class ApplicationBot(User):
Parameters Parameters
----------- -----------
username: :class:`str` username: :class:`str`
The new username you wish to change your bot to. The new username you wish to change the bot to.
avatar: Optional[:class:`bytes`] avatar: Optional[:class:`bytes`]
A :term:`py:bytes-like object` representing the image to upload. A :term:`py:bytes-like object` representing the image to upload.
Could be ``None`` to denote no avatar. Could be ``None`` to denote no avatar.
bio: Optional[:class:`str`] bio: Optional[:class:`str`]
Your bot's 'about me' section. This is just the application description. The bot's 'about me' section. This is just the application description.
Could be ``None`` to represent no 'about me'. Could be ``None`` to represent no 'about me'.
public: :class:`bool` public: :class:`bool`
Whether the bot is public or not. Whether the bot is public or not.
@ -675,8 +677,6 @@ class ApplicationBot(User):
if payload: if payload:
data = await self._state.http.edit_bot(self.application.id, payload) data = await self._state.http.edit_bot(self.application.id, payload)
data['public'] = self.public # type: ignore
data['require_code_grant'] = self.require_code_grant # type: ignore
self._update(data) self._update(data)
payload = {} payload = {}
@ -691,7 +691,7 @@ class ApplicationBot(User):
data = await self._state.http.edit_application(self.application.id, payload) data = await self._state.http.edit_application(self.application.id, payload)
self.application._update(data) self.application._update(data)
async def token(self) -> None: async def token(self) -> str:
"""|coro| """|coro|
Gets the bot's token. Gets the bot's token.
@ -1657,6 +1657,10 @@ class PartialApplication(Hashable):
The application's terms of service URL, if set. The application's terms of service URL, if set.
privacy_policy_url: Optional[:class:`str`] privacy_policy_url: Optional[:class:`str`]
The application's privacy policy URL, if set. The application's privacy policy URL, if set.
deeplink_uri: Optional[:class:`str`]
The application's deeplink URI, if set.
.. versionadded:: 2.1
public: :class:`bool` public: :class:`bool`
Whether the integration can be invited by anyone or if it is locked Whether the integration can be invited by anyone or if it is locked
to the application owner. to the application owner.
@ -1723,6 +1727,7 @@ class PartialApplication(Hashable):
'verify_key', 'verify_key',
'terms_of_service_url', 'terms_of_service_url',
'privacy_policy_url', 'privacy_policy_url',
'deeplink_uri',
'_icon', '_icon',
'_flags', '_flags',
'_cover_image', '_cover_image',
@ -1771,7 +1776,7 @@ class PartialApplication(Hashable):
self.id: int = int(data['id']) self.id: int = int(data['id'])
self.name: str = data['name'] self.name: str = data['name']
self.description: str = data['description'] self.description: str = data['description']
self.rpc_origins: Optional[List[str]] = data.get('rpc_origins') or [] self.rpc_origins: List[str] = data.get('rpc_origins') or []
self.verify_key: str = data['verify_key'] self.verify_key: str = data['verify_key']
self.aliases: List[str] = data.get('aliases', []) self.aliases: List[str] = data.get('aliases', [])
@ -1789,6 +1794,7 @@ class PartialApplication(Hashable):
self.terms_of_service_url: Optional[str] = data.get('terms_of_service_url') self.terms_of_service_url: Optional[str] = data.get('terms_of_service_url')
self.privacy_policy_url: Optional[str] = data.get('privacy_policy_url') self.privacy_policy_url: Optional[str] = data.get('privacy_policy_url')
self.deeplink_uri: Optional[str] = data.get('deeplink_uri')
self._flags: int = data.get('flags', 0) self._flags: int = data.get('flags', 0)
self.type: Optional[ApplicationType] = try_enum(ApplicationType, data['type']) if data.get('type') else None self.type: Optional[ApplicationType] = try_enum(ApplicationType, data['type']) if data.get('type') else None
self.hook: bool = data.get('hook', False) self.hook: bool = data.get('hook', False)
@ -2143,6 +2149,10 @@ class Application(PartialApplication):
The approval state of the RPC usage application. The approval state of the RPC usage application.
discoverability_state: :class:`ApplicationDiscoverabilityState` discoverability_state: :class:`ApplicationDiscoverabilityState`
The discoverability (app directory) state of the application. The discoverability (app directory) state of the application.
approximate_guild_count: Optional[:class:`int`]
The approximate number of guilds this application is in, if available.
.. versionadded:: 2.1
""" """
__slots__ = ( __slots__ = (
@ -2156,6 +2166,7 @@ class Application(PartialApplication):
'rpc_application_state', 'rpc_application_state',
'discoverability_state', 'discoverability_state',
'_discovery_eligibility_flags', '_discovery_eligibility_flags',
'approximate_guild_count',
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@ -2177,15 +2188,13 @@ class Application(PartialApplication):
self.rpc_application_state = try_enum(RPCApplicationState, data.get('rpc_application_state', 0)) self.rpc_application_state = try_enum(RPCApplicationState, data.get('rpc_application_state', 0))
self.discoverability_state = try_enum(ApplicationDiscoverabilityState, data.get('discoverability_state', 1)) self.discoverability_state = try_enum(ApplicationDiscoverabilityState, data.get('discoverability_state', 1))
self._discovery_eligibility_flags = data.get('discovery_eligibility_flags', 0) self._discovery_eligibility_flags = data.get('discovery_eligibility_flags', 0)
self.approximate_guild_count: Optional[int] = data.get('approximate_guild_count')
state = self._state state = self._state
# Hacky, but I want these to be persisted # Hacky, but I want these to be persisted
existing = getattr(self, 'bot', None) existing = getattr(self, 'bot', None)
bot = data.get('bot') bot = data.get('bot')
if bot:
bot['public'] = data.get('bot_public', self.public) # type: ignore
bot['require_code_grant'] = data.get('bot_require_code_grant', self.require_code_grant) # type: ignore
if existing is not None: if existing is not None:
existing._update(bot) existing._update(bot)
else: else:
@ -2215,11 +2224,14 @@ class Application(PartialApplication):
tags: Sequence[str] = MISSING, tags: Sequence[str] = MISSING,
terms_of_service_url: Optional[str] = MISSING, terms_of_service_url: Optional[str] = MISSING,
privacy_policy_url: Optional[str] = MISSING, privacy_policy_url: Optional[str] = MISSING,
deeplink_uri: Optional[str] = MISSING,
interactions_endpoint_url: Optional[str] = MISSING, interactions_endpoint_url: Optional[str] = MISSING,
role_connections_verification_url: Optional[str] = MISSING,
redirect_uris: Sequence[str] = MISSING, redirect_uris: Sequence[str] = MISSING,
rpc_origins: Sequence[str] = MISSING, rpc_origins: Sequence[str] = MISSING,
public: bool = MISSING, public: bool = MISSING,
require_code_grant: bool = MISSING, require_code_grant: bool = MISSING,
max_participants: Optional[int] = MISSING,
flags: ApplicationFlags = MISSING, flags: ApplicationFlags = MISSING,
custom_install_url: Optional[str] = MISSING, custom_install_url: Optional[str] = MISSING,
install_params: Optional[ApplicationInstallParams] = MISSING, install_params: Optional[ApplicationInstallParams] = MISSING,
@ -2250,8 +2262,16 @@ class Application(PartialApplication):
The URL to the terms of service of the application. The URL to the terms of service of the application.
privacy_policy_url: Optional[:class:`str`] privacy_policy_url: Optional[:class:`str`]
The URL to the privacy policy of the application. The URL to the privacy policy of the application.
deeplink_uri: Optional[:class:`str`]
The deeplink URI of the application.
.. versionadded:: 2.1
interactions_endpoint_url: Optional[:class:`str`] interactions_endpoint_url: Optional[:class:`str`]
The URL interactions will be sent to, if set. The URL interactions will be sent to, if set.
role_connections_verification_url: Optional[:class:`str`]
The connection verification URL for the application.
.. versionadded:: 2.1
redirect_uris: List[:class:`str`] redirect_uris: List[:class:`str`]
A list of redirect URIs authorized for this application. A list of redirect URIs authorized for this application.
rpc_origins: List[:class:`str`] rpc_origins: List[:class:`str`]
@ -2260,6 +2280,11 @@ class Application(PartialApplication):
Whether the application is public or not. Whether the application is public or not.
require_code_grant: :class:`bool` require_code_grant: :class:`bool`
Whether the application requires a code grant or not. Whether the application requires a code grant or not.
max_participants: Optional[:class:`int`]
The max number of people that can participate in the activity.
Only available for embedded activities.
.. versionadded:: 2.1
flags: :class:`ApplicationFlags` flags: :class:`ApplicationFlags`
The flags of the application. The flags of the application.
developers: List[:class:`Company`] developers: List[:class:`Company`]
@ -2299,8 +2324,12 @@ class Application(PartialApplication):
payload['terms_of_service_url'] = terms_of_service_url or '' payload['terms_of_service_url'] = terms_of_service_url or ''
if privacy_policy_url is not MISSING: if privacy_policy_url is not MISSING:
payload['privacy_policy_url'] = privacy_policy_url or '' payload['privacy_policy_url'] = privacy_policy_url or ''
if deeplink_uri is not MISSING:
payload['deeplink_uri'] = deeplink_uri or ''
if interactions_endpoint_url is not MISSING: if interactions_endpoint_url is not MISSING:
payload['interactions_endpoint_url'] = interactions_endpoint_url or '' payload['interactions_endpoint_url'] = interactions_endpoint_url or ''
if role_connections_verification_url is not MISSING:
payload['role_connections_verification_url'] = role_connections_verification_url or ''
if redirect_uris is not MISSING: if redirect_uris is not MISSING:
payload['redirect_uris'] = redirect_uris payload['redirect_uris'] = redirect_uris
if rpc_origins is not MISSING: if rpc_origins is not MISSING:
@ -2315,6 +2344,8 @@ class Application(PartialApplication):
payload['bot_require_code_grant'] = require_code_grant payload['bot_require_code_grant'] = require_code_grant
else: else:
payload['integration_require_code_grant'] = require_code_grant payload['integration_require_code_grant'] = require_code_grant
if max_participants is not MISSING:
payload['max_participants'] = max_participants
if flags is not MISSING: if flags is not MISSING:
payload['flags'] = flags.value payload['flags'] = flags.value
if custom_install_url is not MISSING: if custom_install_url is not MISSING:
@ -2354,9 +2385,6 @@ class Application(PartialApplication):
The bot attached to this application. The bot attached to this application.
""" """
data = await self._state.http.edit_bot(self.id, {}) data = await self._state.http.edit_bot(self.id, {})
data['public'] = self.public # type: ignore
data['require_code_grant'] = self.require_code_grant # type: ignore
if not self.bot: if not self.bot:
self.bot = ApplicationBot(data=data, state=self._state, application=self) self.bot = ApplicationBot(data=data, state=self._state, application=self)
else: else:
@ -2364,11 +2392,17 @@ class Application(PartialApplication):
return self.bot return self.bot
async def create_bot(self) -> ApplicationBot: async def create_bot(self) -> Optional[str]:
"""|coro| """|coro|
Creates a bot attached to this application. Creates a bot attached to this application.
.. versionchanged:: 2.1
This now returns the bot token (if applicable)
instead of implicitly refetching the application
to return the :class:`ApplicationBot`.
Raises Raises
------ ------
Forbidden Forbidden
@ -2378,17 +2412,87 @@ class Application(PartialApplication):
Returns Returns
------- -------
:class:`ApplicationBot` Optional[:class:`str`]
The bot that was created. The bot's token.
This is only returned if a bot does not already exist.
""" """
state = self._state state = self._state
await state.http.botify_app(self.id) data = await state.http.botify_app(self.id)
return data.get('token')
# The endpoint no longer returns the bot so we fetch ourselves async def edit_bot(
# This is fine, the dev portal does the same self,
data = await state.http.get_my_application(self.id) *,
self._update(data) username: str = MISSING,
return self.bot # type: ignore avatar: Optional[bytes] = MISSING,
bio: Optional[str] = MISSING,
public: bool = MISSING,
require_code_grant: bool = MISSING,
) -> ApplicationBot:
"""|coro|
Edits the application's bot.
All parameters are optional.
.. versionadded:: 2.1
Parameters
-----------
username: :class:`str`
The new username you wish to change the bot to.
avatar: Optional[:class:`bytes`]
A :term:`py:bytes-like object` representing the image to upload.
Could be ``None`` to denote no avatar.
bio: Optional[:class:`str`]
The bot's 'about me' section. This is just the application description.
Could be ``None`` to represent no 'about me'.
public: :class:`bool`
Whether the bot is public or not.
require_code_grant: :class:`bool`
Whether the bot requires a code grant or not.
Raises
------
Forbidden
You are not allowed to edit this bot.
HTTPException
Editing the bot failed.
Returns
--------
:class:`ApplicationBot`
The newly edited bot.
"""
payload = {}
if username is not MISSING:
payload['username'] = username
if avatar is not MISSING:
if avatar is not None:
payload['avatar'] = _bytes_to_base64_data(avatar)
else:
payload['avatar'] = None
if payload or not self.bot: # Ensure we get a bot object
data = await self._state.http.edit_bot(self.id, payload)
if not self.bot:
self.bot = ApplicationBot(data=data, state=self._state, application=self)
else:
self.bot._update(data)
payload = {}
if public is not MISSING:
payload['bot_public'] = public
if require_code_grant is not MISSING:
payload['bot_require_code_grant'] = require_code_grant
if bio is not MISSING:
payload['description'] = bio
if payload:
data = await self._state.http.edit_application(self.id, payload)
self._update(data)
return self.bot
async def whitelisted(self) -> List[ApplicationTester]: async def whitelisted(self) -> List[ApplicationTester]:
"""|coro| """|coro|

2
discord/http.py

@ -3207,7 +3207,7 @@ class HTTPClient:
super_properties_to_track=True, super_properties_to_track=True,
) )
def botify_app(self, app_id: Snowflake) -> Response[None]: def botify_app(self, app_id: Snowflake) -> Response[application.Token]:
return self.request( return self.request(
Route('POST', '/applications/{app_id}/bot', app_id=app_id), json={}, super_properties_to_track=True Route('POST', '/applications/{app_id}/bot', app_id=app_id), json={}, super_properties_to_track=True
) )

31
discord/types/application.py

@ -30,7 +30,12 @@ from typing_extensions import NotRequired
from .guild import PartialGuild from .guild import PartialGuild
from .snowflake import Snowflake from .snowflake import Snowflake
from .team import Team from .team import Team
from .user import PartialUser from .user import APIUser, PartialUser
class Token(TypedDict):
# Missing if a bot already exists 😭
token: Optional[str]
class BaseApplication(TypedDict): class BaseApplication(TypedDict):
@ -44,16 +49,17 @@ class BaseApplication(TypedDict):
summary: NotRequired[Literal['']] summary: NotRequired[Literal['']]
class MetadataApplication(BaseApplication): class RoleConnectionApplication(BaseApplication):
bot: NotRequired[PartialUser] bot: NotRequired[PartialUser]
class IntegrationApplication(MetadataApplication): class IntegrationApplication(BaseApplication):
bot: NotRequired[APIUser]
role_connections_verification_url: NotRequired[Optional[str]] role_connections_verification_url: NotRequired[Optional[str]]
class PartialApplication(BaseApplication): class PartialApplication(BaseApplication):
owner: NotRequired[PartialUser] # Not actually ever present in partial app owner: NotRequired[APIUser] # Not actually ever present in partial app
team: NotRequired[Team] team: NotRequired[Team]
verify_key: str verify_key: str
description: str description: str
@ -96,6 +102,8 @@ class Application(PartialApplication, IntegrationApplication, ApplicationDiscove
rpc_application_state: int rpc_application_state: int
creator_monetization_state: int creator_monetization_state: int
role_connections_verification_url: NotRequired[Optional[str]] role_connections_verification_url: NotRequired[Optional[str]]
# GET /applications/{application.id} only
approximate_guild_count: NotRequired[int]
class WhitelistedUser(TypedDict): class WhitelistedUser(TypedDict):
@ -218,17 +226,22 @@ class GlobalActivityStatistics(TypedDict):
EmbeddedActivityPlatform = Literal['web', 'android', 'ios'] EmbeddedActivityPlatform = Literal['web', 'android', 'ios']
EmbeddedActivityPlatformLabelType = Literal[0, 1, 2]
EmbedddedActivityPlatformReleasePhase = Literal[
'in_development', 'activities_team', 'employee_release', 'soft_launch', 'global_launch'
]
class ClientPlatformConfig(TypedDict): class EmbeddedActivityPlatformConfig(TypedDict):
label_type: int label_type: EmbeddedActivityPlatformLabelType
label_until: Optional[str] label_until: Optional[str]
release_phase: str release_phase: EmbedddedActivityPlatformReleasePhase
class EmbeddedActivityConfig(TypedDict): class EmbeddedActivityConfig(TypedDict):
application_id: NotRequired[Snowflake]
activity_preview_video_asset_id: NotRequired[Optional[Snowflake]] activity_preview_video_asset_id: NotRequired[Optional[Snowflake]]
client_platform_config: Dict[EmbeddedActivityPlatform, ClientPlatformConfig] client_platform_config: Dict[EmbeddedActivityPlatform, EmbeddedActivityPlatformConfig]
default_orientation_lock_state: Literal[1, 2, 3] default_orientation_lock_state: Literal[1, 2, 3]
tablet_default_orientation_lock_state: Literal[1, 2, 3] tablet_default_orientation_lock_state: Literal[1, 2, 3]
free_period_ends_at: NotRequired[Optional[str]] free_period_ends_at: NotRequired[Optional[str]]
@ -269,5 +282,5 @@ class PartialRoleConnection(TypedDict):
class RoleConnection(PartialRoleConnection): class RoleConnection(PartialRoleConnection):
application: MetadataApplication application: RoleConnectionApplication
application_metadata: List[RoleConnectionMetadata] application_metadata: List[RoleConnectionMetadata]

Loading…
Cancel
Save