Skip to content

Commit

Permalink
Add support for getting and editing integration_types_config applicat…
Browse files Browse the repository at this point in the history
…ion field
  • Loading branch information
Soheab authored Feb 18, 2025
1 parent 6ab747f commit fa158a5
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 4 deletions.
129 changes: 126 additions & 3 deletions discord/appinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from __future__ import annotations

from typing import List, TYPE_CHECKING, Optional
from typing import List, TYPE_CHECKING, Literal, Optional

from . import utils
from .asset import Asset
Expand All @@ -41,6 +41,7 @@
PartialAppInfo as PartialAppInfoPayload,
Team as TeamPayload,
InstallParams as InstallParamsPayload,
AppIntegrationTypeConfig as AppIntegrationTypeConfigPayload,
)
from .user import User
from .state import ConnectionState
Expand All @@ -49,6 +50,7 @@
'AppInfo',
'PartialAppInfo',
'AppInstallParams',
'IntegrationTypeConfig',
)


Expand Down Expand Up @@ -180,6 +182,7 @@ class AppInfo:
'redirect_uris',
'approximate_guild_count',
'approximate_user_install_count',
'_integration_types_config',
)

def __init__(self, state: ConnectionState, data: AppInfoPayload):
Expand Down Expand Up @@ -218,6 +221,9 @@ def __init__(self, state: ConnectionState, data: AppInfoPayload):
self.redirect_uris: List[str] = data.get('redirect_uris', [])
self.approximate_guild_count: int = data.get('approximate_guild_count', 0)
self.approximate_user_install_count: Optional[int] = data.get('approximate_user_install_count')
self._integration_types_config: Dict[Literal['0', '1'], AppIntegrationTypeConfigPayload] = data.get(
'integration_types_config', {}
)

def __repr__(self) -> str:
return (
Expand Down Expand Up @@ -260,6 +266,36 @@ def flags(self) -> ApplicationFlags:
"""
return ApplicationFlags._from_value(self._flags)

@property
def guild_integration_config(self) -> Optional[IntegrationTypeConfig]:
"""Optional[:class:`IntegrationTypeConfig`]: The default settings for the
application's installation context in a guild.
.. versionadded:: 2.5
"""
if not self._integration_types_config:
return None

try:
return IntegrationTypeConfig(self._integration_types_config['0'])
except KeyError:
return None

@property
def user_integration_config(self) -> Optional[IntegrationTypeConfig]:
"""Optional[:class:`IntegrationTypeConfig`]: The default settings for the
application's installation context as a user.
.. versionadded:: 2.5
"""
if not self._integration_types_config:
return None

try:
return IntegrationTypeConfig(self._integration_types_config['1'])
except KeyError:
return None

async def edit(
self,
*,
Expand All @@ -274,6 +310,10 @@ async def edit(
cover_image: Optional[bytes] = MISSING,
interactions_endpoint_url: Optional[str] = MISSING,
tags: Optional[List[str]] = MISSING,
guild_install_scopes: Optional[List[str]] = MISSING,
guild_install_permissions: Optional[Permissions] = MISSING,
user_install_scopes: Optional[List[str]] = MISSING,
user_install_permissions: Optional[Permissions] = MISSING,
) -> AppInfo:
r"""|coro|
Expand Down Expand Up @@ -315,6 +355,24 @@ async def edit(
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.
guild_install_scopes: Optional[List[:class:`str`]]
The new list of :ddocs:`OAuth2 scopes <topics/oauth2#shared-resources-oauth2-scopes>` of
the default guild installation context. Can be ``None`` to remove the scopes.
.. versionadded: 2.5
guild_install_permissions: Optional[:class:`Permissions`]
The new permissions of the default guild installation context. Can be ``None`` to remove the permissions.
.. versionadded: 2.5
user_install_scopes: Optional[List[:class:`str`]]
The new list of :ddocs:`OAuth2 scopes <topics/oauth2#shared-resources-oauth2-scopes>` of
the default user installation context. Can be ``None`` to remove the scopes.
.. versionadded: 2.5
user_install_permissions: Optional[:class:`Permissions`]
The new permissions of the default user installation context. Can be ``None`` to remove the permissions.
.. versionadded: 2.5
reason: Optional[:class:`str`]
The reason for editing the application. Shows up on the audit log.
Expand All @@ -324,7 +382,8 @@ async def edit(
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.
when ``install_params_scopes`` and ``install_params_permissions`` are incompatible with each other,
or when ``guild_install_scopes`` and ``guild_install_permissions`` are incompatible with each other.
Returns
-------
Expand Down Expand Up @@ -364,7 +423,7 @@ async def edit(

else:
if install_params_permissions is not MISSING:
raise ValueError("install_params_scopes must be set if install_params_permissions is set")
raise ValueError('install_params_scopes must be set if install_params_permissions is set')

if flags is not MISSING:
if flags is None:
Expand All @@ -389,6 +448,51 @@ async def edit(

if tags is not MISSING:
payload['tags'] = tags

integration_types_config: Dict[str, Any] = {}
if guild_install_scopes is not MISSING or guild_install_permissions is not MISSING:
guild_install_params: Optional[Dict[str, Any]] = {}
if guild_install_scopes in (None, MISSING):
guild_install_scopes = []

if 'bot' not in guild_install_scopes and guild_install_permissions is not MISSING:
raise ValueError("'bot' must be in guild_install_scopes if guild_install_permissions is set")

if guild_install_permissions in (None, MISSING):
guild_install_params['permissions'] = 0
else:
guild_install_params['permissions'] = guild_install_permissions.value

guild_install_params['scopes'] = guild_install_scopes

integration_types_config['0'] = {'oauth2_install_params': guild_install_params or None}
else:
if guild_install_permissions is not MISSING:
raise ValueError('guild_install_scopes must be set if guild_install_permissions is set')

if user_install_scopes is not MISSING or user_install_permissions is not MISSING:
user_install_params: Optional[Dict[str, Any]] = {}
if user_install_scopes in (None, MISSING):
user_install_scopes = []

if 'bot' not in user_install_scopes and user_install_permissions is not MISSING:
raise ValueError("'bot' must be in user_install_scopes if user_install_permissions is set")

if user_install_permissions in (None, MISSING):
user_install_params['permissions'] = 0
else:
user_install_params['permissions'] = user_install_permissions.value

user_install_params['scopes'] = user_install_scopes

integration_types_config['1'] = {'oauth2_install_params': user_install_params or None}
else:
if user_install_permissions is not MISSING:
raise ValueError('user_install_scopes must be set if user_install_permissions is set')

if integration_types_config:
payload['integration_types_config'] = integration_types_config

data = await self._state.http.edit_application_info(reason=reason, payload=payload)
return AppInfo(data=data, state=self._state)

Expand Down Expand Up @@ -520,3 +624,22 @@ class AppInstallParams:
def __init__(self, data: InstallParamsPayload) -> None:
self.scopes: List[str] = data.get('scopes', [])
self.permissions: Permissions = Permissions(int(data['permissions']))


class IntegrationTypeConfig:
"""Represents the default settings for the application's installation context.
.. versionadded:: 2.5
Attributes
----------
oauth2_install_params: Optional[:class:`AppInstallParams`]
The install params for this installation context's default in-app authorization link.
"""

def __init__(self, data: AppIntegrationTypeConfigPayload) -> None:
self.oauth2_install_params: Optional[AppInstallParams] = None
try:
self.oauth2_install_params = AppInstallParams(data['oauth2_install_params']) # type: ignore # EAFP

Check warning on line 643 in discord/appinfo.py

View workflow job for this annotation

GitHub Actions / check 3.x

Unnecessary "# type: ignore" comment
except KeyError:
pass
1 change: 1 addition & 0 deletions discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,7 @@ def edit_application_info(self, *, reason: Optional[str], payload: Any) -> Respo
'cover_image',
'interactions_endpoint_url ',
'tags',
'integration_types_config',
)

payload = {k: v for k, v in payload.items() if k in valid_keys}
Expand Down
7 changes: 6 additions & 1 deletion discord/types/appinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from __future__ import annotations

from typing import TypedDict, List, Optional
from typing import Literal, Dict, TypedDict, List, Optional
from typing_extensions import NotRequired

from .user import User
Expand All @@ -38,6 +38,10 @@ class InstallParams(TypedDict):
permissions: str


class AppIntegrationTypeConfig(TypedDict):
oauth2_install_params: NotRequired[InstallParams]


class BaseAppInfo(TypedDict):
id: Snowflake
name: str
Expand Down Expand Up @@ -69,6 +73,7 @@ class AppInfo(BaseAppInfo):
tags: NotRequired[List[str]]
install_params: NotRequired[InstallParams]
custom_install_url: NotRequired[str]
integration_types_config: NotRequired[Dict[Literal['0', '1'], AppIntegrationTypeConfig]]


class PartialAppInfo(BaseAppInfo, total=False):
Expand Down
8 changes: 8 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ AppInstallParams
.. autoclass:: AppInstallParams()
:members:

IntegrationTypeConfig
~~~~~~~~~~~~~~~~~~~~~~

.. attributetable:: IntegrationTypeConfig

.. autoclass:: IntegrationTypeConfig()
:members:

Team
~~~~~

Expand Down

0 comments on commit fa158a5

Please sign in to comment.