Skip to content

Commit

Permalink
Application permissions v2 (#1148)
Browse files Browse the repository at this point in the history
  • Loading branch information
davfsa authored Jun 21, 2022
1 parent a408ba0 commit 5529b64
Show file tree
Hide file tree
Showing 22 changed files with 712 additions and 464 deletions.
3 changes: 3 additions & 0 deletions changes/1148.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Removal of all application commands v1 related fields and endpoints.
- Discord has completely disabled some endpoints, so we unfortunately can't
deprecate them instead of removing them
4 changes: 4 additions & 0 deletions changes/1148.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Implement application commands permission v2.
- New `default_member_permissions` and `is_dm_enabled` related fields.
- Added `hikari.events.application_events.ApplicationCommandPermissionsUpdate`.
- Added `APPLICATION_COMMAND_PERMISSION_UPDATE` audit log entry
24 changes: 24 additions & 0 deletions hikari/api/event_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from hikari import users as user_models
from hikari import voices as voices_models
from hikari.api import shard as gateway_shard
from hikari.events import application_events
from hikari.events import channel_events
from hikari.events import guild_events
from hikari.events import interaction_events
Expand All @@ -61,6 +62,29 @@ class EventFactory(abc.ABC):

__slots__: typing.Sequence[str] = ()

######################
# APPLICATION EVENTS #
######################

@abc.abstractmethod
def deserialize_application_command_permission_update_event(
self, shard: gateway_shard.GatewayShard, payload: data_binding.JSONObject
) -> application_events.ApplicationCommandPermissionsUpdateEvent:
"""Parse a raw payload from Discord into an application command permissions update event object.
Parameters
----------
shard : hikari.api.shard.GatewayShard
The shard that emitted this event.
payload : hikari.internal.data_binding.JSONObject
The dict payload to parse.
Returns
-------
hikari.events.application_events.ApplicationCommandPermissionsUpdateEvent
The parsed application command permissions update event.
"""

##################
# CHANNEL EVENTS #
##################
Expand Down
187 changes: 50 additions & 137 deletions hikari/api/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3275,6 +3275,9 @@ async def add_user_to_guild(
Requires the `MANAGE_NICKNAMES` permission on the guild.
nick : hikari.undefined.UndefinedOr[builtins.str]
Deprecated alias for `nickname`.
.. deprecated:: 2.0.0.dev106
Use `nickname` instead.
roles : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole]]
If provided, the roles to add to the user when he joins the guild.
This may be a collection objects or IDs of existing roles.
Expand Down Expand Up @@ -4995,6 +4998,9 @@ async def edit_member(
Requires the `MANAGE_NICKNAMES` permission.
nick : hikari.undefined.UndefinedOr[builtins.str]
Deprecated alias for `nickname`.
.. deprecated:: 2.0.0.dev104
Use `nickname` instead.
roles : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole]]
If provided, the new roles for the member.
Expand Down Expand Up @@ -6808,77 +6814,6 @@ async def fetch_application_commands(
If an internal error occurs on Discord while handling the request.
"""

@abc.abstractmethod
async def create_application_command(
self,
application: snowflakes.SnowflakeishOr[guilds.PartialApplication],
name: str,
description: str,
guild: undefined.UndefinedOr[snowflakes.SnowflakeishOr[guilds.PartialGuild]] = undefined.UNDEFINED,
*,
options: undefined.UndefinedOr[typing.Sequence[commands.CommandOption]] = undefined.UNDEFINED,
default_permission: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
) -> commands.SlashCommand:
r"""Create an application slash command.
.. deprecated:: 2.0.0.dev106
Use `RESTClient.create_slash_command` instead.
Parameters
----------
application: hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialApplication]
Object or ID of the application to create a command for.
name : builtins.str
The command's name. This should match the regex `^[\w-]{1,32}$` in
Unicode mode and be lowercase.
description : builtins.str
The description to set for the command.
This should be inclusively between 1-100 characters in length.
guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild]
Object or ID of the specific guild this should be made for.
If left as `hikari.undefined.UNDEFINED` then this call will create
a global command rather than a guild specific one.
Other Parameters
----------------
options : hikari.undefined.UndefinedOr[typing.Sequence[hikari.commands.CommandOption]]
A sequence of up to 10 options for this command.
default_permission : hikari.undefined.UndefinedOr[builtins.bool]
Whether this command should be enabled by default (without any
permissions) when added to a guild.
Defaults to `builtins.True`.
Returns
-------
hikari.commands.SlashCommand
Object of the created command.
Raises
------
hikari.errors.ForbiddenError
If you cannot access the provided application's commands.
hikari.errors.NotFoundError
If the provided application isn't found.
hikari.errors.BadRequestError
If any of the fields that are passed have an invalid value.
hikari.errors.UnauthorizedError
If you are unauthorized to make the request (invalid/missing token).
hikari.errors.RateLimitTooLongError
Raised in the event that a rate limit occurs that is
longer than `max_rate_limit` when making a request.
hikari.errors.RateLimitedError
Usually, Hikari will handle and retry on hitting
rate-limits automatically. This includes most bucket-specific
rate-limits and global rate-limits. In some rare edge cases,
however, Discord implements other undocumented rules for
rate-limiting, such as limits per attribute. These cannot be
detected or handled normally by Hikari due to their undocumented
nature, and will trigger this exception if they occur.
hikari.errors.InternalServerError
If an internal error occurs on Discord while handling the request.
"""

@abc.abstractmethod
async def create_slash_command(
self,
Expand All @@ -6888,7 +6823,10 @@ async def create_slash_command(
*,
guild: undefined.UndefinedOr[snowflakes.SnowflakeishOr[guilds.PartialGuild]] = undefined.UNDEFINED,
options: undefined.UndefinedOr[typing.Sequence[commands.CommandOption]] = undefined.UNDEFINED,
default_permission: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
default_member_permissions: typing.Union[
undefined.UndefinedType, int, permissions_.Permissions
] = undefined.UNDEFINED,
dm_enabled: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
) -> commands.SlashCommand:
r"""Create an application command.
Expand All @@ -6911,11 +6849,15 @@ async def create_slash_command(
a global command rather than a guild specific one.
options : hikari.undefined.UndefinedOr[typing.Sequence[hikari.commands.CommandOption]]
A sequence of up to 10 options for this command.
default_permission : hikari.undefined.UndefinedOr[builtins.bool]
Whether this command should be enabled by default (without any
permissions) when added to a guild.
default_member_permissions : typing.Union[hikari.undefined.UndefinedType, int, hikari.permissions.Permissions]
Member permissions necessary to utilize this command by default.
If `0`, then it will be available for all members. Note that this doesn't affect
administrators of the guild and overwrites.
dm_enabled : hikari.undefined.UndefinedOr[builtins.bool]
Whether this command is enabled in DMs with the bot.
Defaults to `builtins.True`.
This can only be applied to non-guild commands.
Returns
-------
Expand Down Expand Up @@ -6955,7 +6897,10 @@ async def create_context_menu_command(
name: str,
*,
guild: undefined.UndefinedOr[snowflakes.SnowflakeishOr[guilds.PartialGuild]] = undefined.UNDEFINED,
default_permission: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
default_member_permissions: typing.Union[
undefined.UndefinedType, int, permissions_.Permissions
] = undefined.UNDEFINED,
dm_enabled: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
) -> commands.ContextMenuCommand:
r"""Create an application command.
Expand All @@ -6977,11 +6922,15 @@ async def create_context_menu_command(
Object or ID of the specific guild this should be made for.
If left as `hikari.undefined.UNDEFINED` then this call will create
a global command rather than a guild specific one.
default_permission : hikari.undefined.UndefinedOr[builtins.bool]
Whether this command should be enabled by default (without any
permissions) when added to a guild.
default_member_permissions : typing.Union[hikari.undefined.UndefinedType, int, hikari.permissions.Permissions]
Member permissions necessary to utilize this command by default.
If `0`, then it will be available for all members. Note that this doesn't affect
administrators of the guild and overwrites.
dm_enabled : hikari.undefined.UndefinedOr[builtins.bool]
Whether this command is enabled in DMs with the bot.
Defaults to `builtins.True`.
This can only be applied to non-guild commands.
Returns
-------
Expand Down Expand Up @@ -7081,6 +7030,10 @@ async def edit_application_command(
name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
description: undefined.UndefinedOr[str] = undefined.UNDEFINED,
options: undefined.UndefinedOr[typing.Sequence[commands.CommandOption]] = undefined.UNDEFINED,
default_member_permissions: typing.Union[
undefined.UndefinedType, int, permissions_.Permissions
] = undefined.UNDEFINED,
dm_enabled: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
) -> commands.PartialCommand:
"""Edit a registered application command.
Expand All @@ -7106,6 +7059,15 @@ async def edit_application_command(
options : hikari.undefined.UndefinedOr[typing.Sequence[hikari.commands.CommandOption]]
A sequence of up to 10 options to set for this command. Leave this as
`hikari.undefined.UNDEFINED` to not change.
default_member_permissions : typing.Union[hikari.undefined.UndefinedType, int, hikari.permissions.Permissions]
Member permissions necessary to utilize this command by default.
If `0`, then it will be available for all members. Note that this doesn't affect
administrators of the guild and overwrites.
dm_enabled : hikari.undefined.UndefinedOr[builtins.bool]
Whether this command is enabled in DMs with the bot.
This can only be applied to non-guild commands.
Returns
-------
Expand Down Expand Up @@ -7272,62 +7234,7 @@ async def fetch_application_command_permissions(
If an internal error occurs on Discord while handling the request.
"""

@abc.abstractmethod
async def set_application_guild_commands_permissions(
self,
application: snowflakes.SnowflakeishOr[guilds.PartialApplication],
guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
permissions: typing.Mapping[
snowflakes.SnowflakeishOr[commands.PartialCommand], typing.Sequence[commands.CommandPermission]
],
) -> typing.Sequence[commands.GuildCommandPermissions]:
"""Set permissions in a guild for multiple commands.
!!! note
This overwrites any previously set permissions for the specified
commands.
Parameters
----------
application: hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialApplication]
Object or ID of the application to set the command permissions for.
guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild]]
Object or ID of the guild to set the command permissions for.
permissions : typing.Mapping[hikari.snowflakes.SnowflakeishOr[hikari.commands.PartialCommand], typing.Sequence[hikari.commands.CommandPermission]]
Mapping of objects and/or IDs of commands to sequences of the commands
to set for the specified guild.
!!! warning
Only a maximum of up to 10 permissions can be set per command.
Returns
-------
typing.Sequence[hikari.commands.GuildCommandPermissions]
Sequence of the set guild command permissions.
Raises
------
hikari.errors.ForbiddenError
If you cannot access the provided application's commands or guild.
hikari.errors.NotFoundError
If the provided application or command isn't found.
hikari.errors.UnauthorizedError
If you are unauthorized to make the request (invalid/missing token).
hikari.errors.RateLimitTooLongError
Raised in the event that a rate limit occurs that is
longer than `max_rate_limit` when making a request.
hikari.errors.RateLimitedError
Usually, Hikari will handle and retry on hitting
rate-limits automatically. This includes most bucket-specific
rate-limits and global rate-limits. In some rare edge cases,
however, Discord implements other undocumented rules for
rate-limiting, such as limits per attribute. These cannot be
detected or handled normally by Hikari due to their undocumented
nature, and will trigger this exception if they occur.
hikari.errors.InternalServerError
If an internal error occurs on Discord while handling the request.
""" # noqa: E501 - Line too long

# THIS IS AN OAUTH2 FLOW ONLY
@abc.abstractmethod
async def set_application_command_permissions(
self,
Expand All @@ -7338,6 +7245,12 @@ async def set_application_command_permissions(
) -> commands.GuildCommandPermissions:
"""Set permissions for a specific command.
!!! note
This requires the `access_token` to have the
`hikari.applications.OAuth2Scope.APPLICATIONS_COMMANDS_PERMISSION_UPDATE`
scope enabled along with the authorization of a Bot which has `MANAGE_INVITES`
permission within the target guild.
!!! note
This overwrites any previously set permissions.
Expand Down
44 changes: 34 additions & 10 deletions hikari/api/special_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,15 +977,19 @@ def id(self) -> undefined.UndefinedOr[snowflakes.Snowflake]:

@property
@abc.abstractmethod
def default_permission(self) -> undefined.UndefinedOr[bool]:
"""Whether the command should be enabled by default (without any permissions).
def default_member_permissions(self) -> typing.Union[undefined.UndefinedType, permissions_.Permissions, int]:
"""Member permissions necessary to utilize this command by default.
Defaults to `builtins.bool`.
If `0`, then it will be available for all members. Note that this doesn't affect
administrators of the guild and overwrites.
"""

Returns
-------
undefined.UndefinedOr[builtins.bool]
Whether the command should be enabled by default (without any permissions).
@property
@abc.abstractmethod
def is_dm_enabled(self) -> undefined.UndefinedOr[bool]:
"""Whether this command is enabled in DMs with the bot.
Only applicable to globally-scoped commands.
"""

@abc.abstractmethod
Expand All @@ -1004,13 +1008,33 @@ def set_id(self: _T, id_: undefined.UndefinedOr[snowflakes.Snowflakeish], /) ->
"""

@abc.abstractmethod
def set_default_permission(self: _T, state: undefined.UndefinedOr[bool], /) -> _T:
"""Whether this command should be enabled by default (without any permissions).
def set_default_member_permissions(
self: _T, default_member_permissions: typing.Union[undefined.UndefinedType, int, permissions_.Permissions], /
) -> _T:
"""Set the member permissions necessary to utilize this command by default.
Parameters
----------
default_member_permissions : hikari.undefined.UndefinedOr[builtins.bool]
The default member permissions to utilize this command by default.
If `0`, then it will be available for all members. Note that this doesn't affect
administrators of the guild and overwrites.
Returns
-------
CommandBuilder
Object of this command builder for chained calls.
"""

@abc.abstractmethod
def set_is_dm_enabled(self: _T, state: undefined.UndefinedOr[bool], /) -> _T:
"""Set whether this command will be enabled in DMs with the bot.
Parameters
----------
state : hikari.undefined.UndefinedOr[builtins.bool]
Whether this command should be enabled by default.
Whether this command is enabled in DMs with the bot.
Returns
-------
Expand Down
7 changes: 5 additions & 2 deletions hikari/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,18 @@ class OAuth2Scope(str, enums.Enum):
"""

APPLICATIONS_COMMANDS = "applications.commands"
"""Allows your application's (slash) commands to be used in a guild.
"""Allows your application's commands to be used in a guild.
This is used in Discord's special Bot Authorization Flow like
`OAuth2Scope.BOT` in-order to join an application into a guild as an
application command providing integration.
"""

APPLICATIONS_COMMANDS_UPDATE = "applications.commands.update"
"""Allows your application to update it's (slash) commands via a bearer token."""
"""Allows your application to update its commands via a bearer token."""

APPLICATIONS_COMMANDS_PERMISSION_UPDATE = "applications.commands.permissions.update"
"""Allows your application to update its commands permissions via a bearer token."""

APPLICATIONS_ENTITLEMENTS = "applications.entitlements"
"""Enables reading entitlements for a user's applications."""
Expand Down
Loading

1 comment on commit 5529b64

@GoogolGenius
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

Please sign in to comment.