From 56c67d396720bbb052913e4eeb0d2aaf17c508e0 Mon Sep 17 00:00:00 2001 From: Andrin <65789180+Puncher1@users.noreply.github.com> Date: Mon, 20 Nov 2023 10:33:56 +0100 Subject: [PATCH] Implement editing application info --- discord/appinfo.py | 148 +++++++++++++++++++++++++++++++++++++++ discord/http.py | 16 +++++ discord/types/appinfo.py | 7 +- 3 files changed, 167 insertions(+), 4 deletions(-) diff --git a/discord/appinfo.py b/discord/appinfo.py index 129e543cb..79be2035f 100644 --- a/discord/appinfo.py +++ b/discord/appinfo.py @@ -30,8 +30,11 @@ from . import utils from .asset import Asset from .flags import ApplicationFlags from .permissions import Permissions +from .utils import MISSING if TYPE_CHECKING: + from typing import Dict, Any + from .guild import Guild from .types.appinfo import ( AppInfo as AppInfoPayload, @@ -131,6 +134,15 @@ class AppInfo: a verification method in the guild's role verification configuration. .. versionadded:: 2.2 + interactions_endpoint_url: Optional[:class:`str`] + The interactions endpoint url of the application to receive interactions over this endpoint rather than + over the gateway, if configured. + + .. versionadded:: 2.4 + redirect_uris: List[:class:`str`] + A list of authentication redirect URIs. + + .. versionadded:: 2.4 """ __slots__ = ( @@ -156,6 +168,8 @@ class AppInfo: 'custom_install_url', 'install_params', 'role_connections_verification_url', + 'interactions_endpoint_url', + 'redirect_uris', ) def __init__(self, state: ConnectionState, data: AppInfoPayload): @@ -190,6 +204,8 @@ class AppInfo: params = data.get('install_params') self.install_params: Optional[AppInstallParams] = AppInstallParams(params) if params else None + self.interactions_endpoint_url: Optional[str] = data.get('interactions_endpoint_url') + self.redirect_uris: List[str] = data.get('redirect_uris', []) def __repr__(self) -> str: return ( @@ -232,6 +248,138 @@ class AppInfo: """ return ApplicationFlags._from_value(self._flags) + async def edit( + self, + *, + reason: Optional[str] = MISSING, + custom_install_url: Optional[str] = MISSING, + description: Optional[str] = MISSING, + role_connections_verification_url: Optional[str] = MISSING, + install_params_scopes: Optional[List[str]] = MISSING, + install_params_permissions: Optional[Permissions] = MISSING, + flags: Optional[ApplicationFlags] = MISSING, + icon: Optional[bytes] = MISSING, + cover_image: Optional[bytes] = MISSING, + interactions_endpoint_url: Optional[str] = MISSING, + tags: Optional[List[str]] = MISSING, + ) -> AppInfo: + r"""|coro| + + Edits the application info. + + .. versionadded:: 2.4 + + Parameters + ---------- + custom_install_url: Optional[:class:`str`] + The new custom authorization URL for the application. Can be ``None`` to remove the URL. + description: Optional[:class:`str`] + The new application description. Can be ``None`` to remove the description. + role_connections_verification_url: Optional[:class:`str`] + The new application’s connection verification URL which will render the application + as a verification method in the guild’s role verification configuration. Can be ``None`` to remove the URL. + install_params_scopes: Optional[List[:class:`str`]] + The new list of :ddocs:`OAuth2 scopes ` of + the :attr:`~install_params`. Can be ``None`` to remove the scopes. + install_params_permissions: Optional[:class:`Permissions`] + The new permissions of the :attr:`~install_params`. Can be ``None`` to remove the permissions. + flags: Optional[:class:`ApplicationFlags`] + The new application’s flags. Only limited intent flags (:attr:`~ApplicationFlags.gateway_presence_limited`, + :attr:`~ApplicationFlags.gateway_guild_members_limited`, :attr:`~ApplicationFlags.gateway_message_content_limited`) + can be edited. Can be ``None`` to remove the flags. + + .. warning:: + + Editing the limited intent flags leads to the termination of the bot. + + icon: Optional[:class:`bytes`] + The new application’s icon as a :term:`py:bytes-like object`. Can be ``None`` to remove the icon. + cover_image: Optional[:class:`bytes`] + The new application’s cover image as a :term:`py:bytes-like object` on a store embed. + The cover image is only available if the application is a game sold on Discord. + Can be ``None`` to remove the image. + interactions_endpoint_url: Optional[:class:`str`] + The new interactions endpoint url of the application to receive interactions over this endpoint rather than + over the gateway. Can be ``None`` to remove the URL. + tags: Optional[List[:class:`str`]] + The new list of tags describing the functionality of the application. Can be ``None`` to remove the tags. + reason: Optional[:class:`str`] + The reason for editing the application. Shows up on the audit log. + + Raises + ------- + HTTPException + Editing the application failed + ValueError + The image format passed in to ``icon`` or ``cover_image`` is invalid. This is also raised + when ``install_params_scopes`` and ``install_params_permissions`` are incompatible with each other. + + Returns + ------- + :class:`AppInfo` + The newly updated application info. + """ + payload: Dict[str, Any] = {} + + if custom_install_url is not MISSING: + payload['custom_install_url'] = custom_install_url + + if description is not MISSING: + payload['description'] = description + + if role_connections_verification_url is not MISSING: + payload['role_connections_verification_url'] = role_connections_verification_url + + if install_params_scopes is not MISSING: + install_params: Optional[Dict[str, Any]] = {} + if install_params_scopes is None: + install_params = None + else: + if "bot" not in install_params_scopes and install_params_permissions is not MISSING: + raise ValueError("'bot' must be in install_params_scopes if install_params_permissions is set") + + install_params['scopes'] = install_params_scopes + + if install_params_permissions is MISSING: + install_params['permissions'] = 0 + else: + if install_params_permissions is None: + install_params['permissions'] = 0 + else: + install_params['permissions'] = install_params_permissions.value + + payload['install_params'] = install_params + + else: + if install_params_permissions is not MISSING: + raise ValueError("install_params_scopes must be set if install_params_permissions is set") + + if flags is not MISSING: + if flags is None: + payload['flags'] = flags + else: + payload['flags'] = flags.value + + if icon is not MISSING: + if icon is None: + payload['icon'] = icon + else: + payload['icon'] = utils._bytes_to_base64_data(icon) + + if cover_image is not MISSING: + if cover_image is None: + payload['cover_image'] = cover_image + else: + payload['cover_image'] = utils._bytes_to_base64_data(cover_image) + + if interactions_endpoint_url is not MISSING: + payload['interactions_endpoint_url'] = interactions_endpoint_url + + if tags is not MISSING: + payload['tags'] = tags + data = await self._state.http.edit_application_info(reason=reason, payload=payload) + return AppInfo(data=data, state=self._state) + class PartialAppInfo: """Represents a partial AppInfo given by :func:`~discord.abc.GuildChannel.create_invite` diff --git a/discord/http.py b/discord/http.py index 764d26fcf..05d4b53ea 100644 --- a/discord/http.py +++ b/discord/http.py @@ -2456,6 +2456,22 @@ class HTTPClient: def application_info(self) -> Response[appinfo.AppInfo]: return self.request(Route('GET', '/oauth2/applications/@me')) + def edit_application_info(self, *, reason: Optional[str], payload: Any) -> Response[appinfo.AppInfo]: + valid_keys = ( + 'custom_install_url', + 'description', + 'role_connections_verification_url', + 'install_params', + 'flags', + 'icon', + 'cover_image', + 'interactions_endpoint_url ', + 'tags', + ) + + payload = {k: v for k, v in payload.items() if k in valid_keys} + return self.request(Route('PATCH', '/applications/@me'), json=payload, reason=reason) + async def get_gateway(self, *, encoding: str = 'json', zlib: bool = True) -> str: try: data = await self.request(Route('GET', '/gateway')) diff --git a/discord/types/appinfo.py b/discord/types/appinfo.py index 87bafc6d2..e291babfa 100644 --- a/discord/types/appinfo.py +++ b/discord/types/appinfo.py @@ -49,6 +49,9 @@ class BaseAppInfo(TypedDict): terms_of_service_url: NotRequired[str] privacy_policy_url: NotRequired[str] rpc_origins: NotRequired[List[str]] + interactions_endpoint_url: NotRequired[Optional[str]] + redirect_uris: NotRequired[List[str]] + role_connections_verification_url: NotRequired[Optional[str]] class AppInfo(BaseAppInfo): @@ -64,16 +67,12 @@ class AppInfo(BaseAppInfo): tags: NotRequired[List[str]] install_params: NotRequired[InstallParams] custom_install_url: NotRequired[str] - role_connections_verification_url: NotRequired[str] class PartialAppInfo(BaseAppInfo, total=False): hook: bool max_participants: int approximate_guild_count: int - redirect_uris: List[str] - interactions_endpoint_url: Optional[str] - role_connections_verification_url: Optional[str] class GatewayAppInfo(TypedDict):