Browse Source

Add application command permissions to audit log

pull/7983/head
z03h 3 years ago
committed by GitHub
parent
commit
619bc50e5d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      discord/app_commands/models.py
  2. 112
      discord/audit_logs.py
  3. 192
      discord/enums.py
  4. 39
      discord/guild.py
  5. 51
      discord/integrations.py
  6. 12
      discord/types/audit_log.py
  7. 2
      discord/types/command.py
  8. 1
      discord/types/integration.py
  9. 43
      docs/api.rst
  10. 8
      docs/interactions/api.rst

27
discord/app_commands/models.py

@ -39,6 +39,7 @@ __all__ = (
'AppCommandThread', 'AppCommandThread',
'Argument', 'Argument',
'Choice', 'Choice',
'AllChannels',
) )
ChoiceT = TypeVar('ChoiceT', str, int, float, Union[str, int, float]) ChoiceT = TypeVar('ChoiceT', str, int, float, Union[str, int, float])
@ -70,6 +71,32 @@ if TYPE_CHECKING:
ApplicationCommandParent = Union['AppCommand', 'AppCommandGroup'] ApplicationCommandParent = Union['AppCommand', 'AppCommandGroup']
class AllChannels:
"""Represents all channels for application command permissions.
.. versionadded:: 2.0
Attributes
-----------
id: :class:`int`
The guilds id - 1.
guild: :class:`~discord.Guild`
The guild the application command permission is for.
"""
__slots__ = (
'id',
'guild',
)
def __init__(self, guild: Guild):
self.id = guild.id - 1
self.guild = guild
def __repr__(self):
return f'<All Channels guild={self.guild}>'
class AppCommand(Hashable): class AppCommand(Hashable):
"""Represents a application command. """Represents a application command.

112
discord/audit_logs.py

@ -61,10 +61,13 @@ if TYPE_CHECKING:
from .types.invite import Invite as InvitePayload from .types.invite import Invite as InvitePayload
from .types.role import Role as RolePayload from .types.role import Role as RolePayload
from .types.snowflake import Snowflake from .types.snowflake import Snowflake
from .types.command import ApplicationCommandPermissions
from .user import User from .user import User
from .stage_instance import StageInstance from .stage_instance import StageInstance
from .sticker import GuildSticker from .sticker import GuildSticker
from .threads import Thread from .threads import Thread
from .integrations import PartialIntegration
from .app_commands import AppCommand
TargetType = Union[ TargetType = Union[
Guild, abc.GuildChannel, Member, User, Role, Invite, Emoji, StageInstance, GuildSticker, Thread, Object, None Guild, abc.GuildChannel, Member, User, Role, Invite, Emoji, StageInstance, GuildSticker, Thread, Object, None
@ -253,6 +256,24 @@ class AuditLogChanges:
self.before: AuditLogDiff = AuditLogDiff() self.before: AuditLogDiff = AuditLogDiff()
self.after: AuditLogDiff = AuditLogDiff() self.after: AuditLogDiff = AuditLogDiff()
if entry.action is enums.AuditLogAction.app_command_permission_update:
# special case entire process since each
# element in data is a different target
self.before.app_command_permissions = []
self.after.app_command_permissions = []
for d in data:
self._handle_app_command_permissions(
self.before,
self.after,
entry,
int(d['key']),
d.get('old_value'), # type: ignore # old value will be an ApplicationCommandPermissions if present
d.get('new_value'), # type: ignore # new value will be an ApplicationCommandPermissions if present
)
return
for elem in data: for elem in data:
attr = elem['key'] attr = elem['key']
@ -324,6 +345,52 @@ class AuditLogChanges:
setattr(second, 'roles', data) setattr(second, 'roles', data)
def _handle_app_command_permissions(
self,
before: AuditLogDiff,
after: AuditLogDiff,
entry: AuditLogEntry,
target_id: int,
old_value: Optional[ApplicationCommandPermissions],
new_value: Optional[ApplicationCommandPermissions],
):
guild = entry.guild
old_permission = new_permission = target = None
if target_id == (guild.id - 1):
# avoid circular import
from .app_commands import AllChannels
# all channels
target = AllChannels(guild)
else:
# get type and determine role, user or channel
_value = old_value or new_value
if _value is None:
return
permission_type = _value['type']
if permission_type == 1:
# role
target = guild.get_role(target_id)
elif permission_type == 2:
# user
target = entry._get_member(target_id)
elif permission_type == 3:
# channel
target = guild.get_channel(target_id)
if target is None:
target = Object(target_id)
if old_value is not None:
old_permission = old_value['permission']
before.app_command_permissions.append((target, old_permission))
if new_value is not None:
new_permission = new_value['permission']
after.app_command_permissions.append((target, new_permission))
class _AuditLogProxy: class _AuditLogProxy:
def __init__(self, **kwargs: Any) -> None: def __init__(self, **kwargs: Any) -> None:
@ -397,10 +464,20 @@ class AuditLogEntry(Hashable):
which actions have this field filled out. which actions have this field filled out.
""" """
def __init__(self, *, users: Dict[int, User], data: AuditLogEntryPayload, guild: Guild): def __init__(
self,
*,
users: Dict[int, User],
integrations: Dict[int, PartialIntegration],
app_commands: Dict[int, AppCommand],
data: AuditLogEntryPayload,
guild: Guild,
):
self._state: ConnectionState = guild._state self._state: ConnectionState = guild._state
self.guild: Guild = guild self.guild: Guild = guild
self._users: Dict[int, User] = users self._users: Dict[int, User] = users
self._integrations: Dict[int, PartialIntegration] = integrations
self._app_commands: Dict[int, AppCommand] = app_commands
self._from_data(data) self._from_data(data)
def _from_data(self, data: AuditLogEntryPayload) -> None: def _from_data(self, data: AuditLogEntryPayload) -> None:
@ -418,7 +495,7 @@ class AuditLogEntry(Hashable):
_AuditLogProxyMemberDisconnect, _AuditLogProxyMemberDisconnect,
_AuditLogProxyPinAction, _AuditLogProxyPinAction,
_AuditLogProxyStageInstanceAction, _AuditLogProxyStageInstanceAction,
Member, User, None, Member, User, None, PartialIntegration,
Role, Object Role, Object
] = None ] = None
# fmt: on # fmt: on
@ -463,6 +540,9 @@ class AuditLogEntry(Hashable):
self.extra = _AuditLogProxyStageInstanceAction( self.extra = _AuditLogProxyStageInstanceAction(
channel=self.guild.get_channel(channel_id) or Object(id=channel_id) channel=self.guild.get_channel(channel_id) or Object(id=channel_id)
) )
elif self.action.name.startswith('app_command'):
application_id = int(extra['application_id'])
self.extra = self._get_integration_by_app_id(application_id) or Object(application_id)
# this key is not present when the above is present, typically. # this key is not present when the above is present, typically.
# It's a list of { new_value: a, old_value: b, key: c } # It's a list of { new_value: a, old_value: b, key: c }
@ -481,6 +561,25 @@ class AuditLogEntry(Hashable):
return self.guild.get_member(user_id) or self._users.get(user_id) return self.guild.get_member(user_id) or self._users.get(user_id)
def _get_integration(self, integration_id: Optional[int]) -> Optional[PartialIntegration]:
if integration_id is None:
return None
return self._integrations.get(integration_id)
def _get_integration_by_app_id(self, application_id: Optional[int]) -> Optional[PartialIntegration]:
if application_id is None:
return None
# get PartialIntegration by application id
return utils.get(self._integrations.values(), application_id=application_id)
def _get_app_command(self, app_command_id: Optional[int]) -> Optional[AppCommand]:
if app_command_id is None:
return None
return self._app_commands.get(app_command_id)
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<AuditLogEntry id={self.id} action={self.action} user={self.user!r}>' return f'<AuditLogEntry id={self.id} action={self.action} user={self.user!r}>'
@ -575,3 +674,12 @@ class AuditLogEntry(Hashable):
def _convert_target_guild_scheduled_event(self, target_id: int) -> Union[ScheduledEvent, Object]: def _convert_target_guild_scheduled_event(self, target_id: int) -> Union[ScheduledEvent, Object]:
return self.guild.get_scheduled_event(target_id) or Object(id=target_id) return self.guild.get_scheduled_event(target_id) or Object(id=target_id)
def _convert_target_integration(self, target_id: int) -> Union[PartialIntegration, Object]:
return self._get_integration(target_id) or Object(target_id)
def _convert_target_app_command(self, target_id: int) -> Union[AppCommand, Object]:
return self._get_app_command(target_id) or Object(target_id)
def _convert_target_integration_or_app_command(self, target_id: int) -> Union[PartialIntegration, AppCommand, Object]:
return self._get_integration_by_app_id(target_id) or self._get_app_command(target_id) or Object(target_id)

192
discord/enums.py

@ -298,106 +298,108 @@ class AuditLogActionCategory(Enum):
class AuditLogAction(Enum): class AuditLogAction(Enum):
# fmt: off # fmt: off
guild_update = 1 guild_update = 1
channel_create = 10 channel_create = 10
channel_update = 11 channel_update = 11
channel_delete = 12 channel_delete = 12
overwrite_create = 13 overwrite_create = 13
overwrite_update = 14 overwrite_update = 14
overwrite_delete = 15 overwrite_delete = 15
kick = 20 kick = 20
member_prune = 21 member_prune = 21
ban = 22 ban = 22
unban = 23 unban = 23
member_update = 24 member_update = 24
member_role_update = 25 member_role_update = 25
member_move = 26 member_move = 26
member_disconnect = 27 member_disconnect = 27
bot_add = 28 bot_add = 28
role_create = 30 role_create = 30
role_update = 31 role_update = 31
role_delete = 32 role_delete = 32
invite_create = 40 invite_create = 40
invite_update = 41 invite_update = 41
invite_delete = 42 invite_delete = 42
webhook_create = 50 webhook_create = 50
webhook_update = 51 webhook_update = 51
webhook_delete = 52 webhook_delete = 52
emoji_create = 60 emoji_create = 60
emoji_update = 61 emoji_update = 61
emoji_delete = 62 emoji_delete = 62
message_delete = 72 message_delete = 72
message_bulk_delete = 73 message_bulk_delete = 73
message_pin = 74 message_pin = 74
message_unpin = 75 message_unpin = 75
integration_create = 80 integration_create = 80
integration_update = 81 integration_update = 81
integration_delete = 82 integration_delete = 82
stage_instance_create = 83 stage_instance_create = 83
stage_instance_update = 84 stage_instance_update = 84
stage_instance_delete = 85 stage_instance_delete = 85
sticker_create = 90 sticker_create = 90
sticker_update = 91 sticker_update = 91
sticker_delete = 92 sticker_delete = 92
scheduled_event_create = 100 scheduled_event_create = 100
scheduled_event_update = 101 scheduled_event_update = 101
scheduled_event_delete = 102 scheduled_event_delete = 102
thread_create = 110 thread_create = 110
thread_update = 111 thread_update = 111
thread_delete = 112 thread_delete = 112
app_command_permission_update = 121
# fmt: on # fmt: on
@property @property
def category(self) -> Optional[AuditLogActionCategory]: def category(self) -> Optional[AuditLogActionCategory]:
# fmt: off # fmt: off
lookup: Dict[AuditLogAction, Optional[AuditLogActionCategory]] = { lookup: Dict[AuditLogAction, Optional[AuditLogActionCategory]] = {
AuditLogAction.guild_update: AuditLogActionCategory.update, AuditLogAction.guild_update: AuditLogActionCategory.update,
AuditLogAction.channel_create: AuditLogActionCategory.create, AuditLogAction.channel_create: AuditLogActionCategory.create,
AuditLogAction.channel_update: AuditLogActionCategory.update, AuditLogAction.channel_update: AuditLogActionCategory.update,
AuditLogAction.channel_delete: AuditLogActionCategory.delete, AuditLogAction.channel_delete: AuditLogActionCategory.delete,
AuditLogAction.overwrite_create: AuditLogActionCategory.create, AuditLogAction.overwrite_create: AuditLogActionCategory.create,
AuditLogAction.overwrite_update: AuditLogActionCategory.update, AuditLogAction.overwrite_update: AuditLogActionCategory.update,
AuditLogAction.overwrite_delete: AuditLogActionCategory.delete, AuditLogAction.overwrite_delete: AuditLogActionCategory.delete,
AuditLogAction.kick: None, AuditLogAction.kick: None,
AuditLogAction.member_prune: None, AuditLogAction.member_prune: None,
AuditLogAction.ban: None, AuditLogAction.ban: None,
AuditLogAction.unban: None, AuditLogAction.unban: None,
AuditLogAction.member_update: AuditLogActionCategory.update, AuditLogAction.member_update: AuditLogActionCategory.update,
AuditLogAction.member_role_update: AuditLogActionCategory.update, AuditLogAction.member_role_update: AuditLogActionCategory.update,
AuditLogAction.member_move: None, AuditLogAction.member_move: None,
AuditLogAction.member_disconnect: None, AuditLogAction.member_disconnect: None,
AuditLogAction.bot_add: None, AuditLogAction.bot_add: None,
AuditLogAction.role_create: AuditLogActionCategory.create, AuditLogAction.role_create: AuditLogActionCategory.create,
AuditLogAction.role_update: AuditLogActionCategory.update, AuditLogAction.role_update: AuditLogActionCategory.update,
AuditLogAction.role_delete: AuditLogActionCategory.delete, AuditLogAction.role_delete: AuditLogActionCategory.delete,
AuditLogAction.invite_create: AuditLogActionCategory.create, AuditLogAction.invite_create: AuditLogActionCategory.create,
AuditLogAction.invite_update: AuditLogActionCategory.update, AuditLogAction.invite_update: AuditLogActionCategory.update,
AuditLogAction.invite_delete: AuditLogActionCategory.delete, AuditLogAction.invite_delete: AuditLogActionCategory.delete,
AuditLogAction.webhook_create: AuditLogActionCategory.create, AuditLogAction.webhook_create: AuditLogActionCategory.create,
AuditLogAction.webhook_update: AuditLogActionCategory.update, AuditLogAction.webhook_update: AuditLogActionCategory.update,
AuditLogAction.webhook_delete: AuditLogActionCategory.delete, AuditLogAction.webhook_delete: AuditLogActionCategory.delete,
AuditLogAction.emoji_create: AuditLogActionCategory.create, AuditLogAction.emoji_create: AuditLogActionCategory.create,
AuditLogAction.emoji_update: AuditLogActionCategory.update, AuditLogAction.emoji_update: AuditLogActionCategory.update,
AuditLogAction.emoji_delete: AuditLogActionCategory.delete, AuditLogAction.emoji_delete: AuditLogActionCategory.delete,
AuditLogAction.message_delete: AuditLogActionCategory.delete, AuditLogAction.message_delete: AuditLogActionCategory.delete,
AuditLogAction.message_bulk_delete: AuditLogActionCategory.delete, AuditLogAction.message_bulk_delete: AuditLogActionCategory.delete,
AuditLogAction.message_pin: None, AuditLogAction.message_pin: None,
AuditLogAction.message_unpin: None, AuditLogAction.message_unpin: None,
AuditLogAction.integration_create: AuditLogActionCategory.create, AuditLogAction.integration_create: AuditLogActionCategory.create,
AuditLogAction.integration_update: AuditLogActionCategory.update, AuditLogAction.integration_update: AuditLogActionCategory.update,
AuditLogAction.integration_delete: AuditLogActionCategory.delete, AuditLogAction.integration_delete: AuditLogActionCategory.delete,
AuditLogAction.stage_instance_create: AuditLogActionCategory.create, AuditLogAction.stage_instance_create: AuditLogActionCategory.create,
AuditLogAction.stage_instance_update: AuditLogActionCategory.update, AuditLogAction.stage_instance_update: AuditLogActionCategory.update,
AuditLogAction.stage_instance_delete: AuditLogActionCategory.delete, AuditLogAction.stage_instance_delete: AuditLogActionCategory.delete,
AuditLogAction.sticker_create: AuditLogActionCategory.create, AuditLogAction.sticker_create: AuditLogActionCategory.create,
AuditLogAction.sticker_update: AuditLogActionCategory.update, AuditLogAction.sticker_update: AuditLogActionCategory.update,
AuditLogAction.sticker_delete: AuditLogActionCategory.delete, AuditLogAction.sticker_delete: AuditLogActionCategory.delete,
AuditLogAction.scheduled_event_create: AuditLogActionCategory.create, AuditLogAction.scheduled_event_create: AuditLogActionCategory.create,
AuditLogAction.scheduled_event_update: AuditLogActionCategory.update, AuditLogAction.scheduled_event_update: AuditLogActionCategory.update,
AuditLogAction.scheduled_event_delete: AuditLogActionCategory.delete, AuditLogAction.scheduled_event_delete: AuditLogActionCategory.delete,
AuditLogAction.thread_create: AuditLogActionCategory.create, AuditLogAction.thread_create: AuditLogActionCategory.create,
AuditLogAction.thread_update: AuditLogActionCategory.update, AuditLogAction.thread_delete: AuditLogActionCategory.delete,
AuditLogAction.thread_delete: AuditLogActionCategory.delete, AuditLogAction.thread_update: AuditLogActionCategory.update,
AuditLogAction.app_command_permission_update: AuditLogActionCategory.update,
} }
# fmt: on # fmt: on
return lookup[self] return lookup[self]
@ -435,6 +437,8 @@ class AuditLogAction(Enum):
return 'guild_scheduled_event' return 'guild_scheduled_event'
elif v < 113: elif v < 113:
return 'thread' return 'thread'
elif v < 122:
return 'integration_or_app_command'
class UserFlags(Enum): class UserFlags(Enum):

39
discord/guild.py

@ -78,7 +78,7 @@ from .invite import Invite
from .widget import Widget from .widget import Widget
from .asset import Asset from .asset import Asset
from .flags import SystemChannelFlags from .flags import SystemChannelFlags
from .integrations import Integration, _integration_factory from .integrations import Integration, PartialIntegration, _integration_factory
from .scheduled_event import ScheduledEvent from .scheduled_event import ScheduledEvent
from .stage_instance import StageInstance from .stage_instance import StageInstance
from .threads import Thread, ThreadMember from .threads import Thread, ThreadMember
@ -3346,11 +3346,11 @@ class Guild(Hashable):
if data and entries: if data and entries:
if limit is not None: if limit is not None:
limit -= len(data) limit -= len(entries)
before = Object(id=int(entries[-1]['id'])) before = Object(id=int(entries[-1]['id']))
return data.get('users', []), entries, before, limit return data, entries, after, limit
async def _after_strategy(retrieve, after, limit): async def _after_strategy(retrieve, after, limit):
after_id = after.id if after else None after_id = after.id if after else None
@ -3362,11 +3362,11 @@ class Guild(Hashable):
if data and entries: if data and entries:
if limit is not None: if limit is not None:
limit -= len(data) limit -= len(entries)
after = Object(id=int(entries[0]['id'])) after = Object(id=int(entries[0]['id']))
return data.get('users', []), entries, after, limit return data, entries, after, limit
if user is not MISSING: if user is not MISSING:
user_id = user.id user_id = user.id
@ -3397,31 +3397,46 @@ class Guild(Hashable):
if after and after != OLDEST_OBJECT: if after and after != OLDEST_OBJECT:
predicate = lambda m: int(m['id']) > after.id predicate = lambda m: int(m['id']) > after.id
# avoid circular import
from .app_commands import AppCommand
while True: while True:
retrieve = min(100 if limit is None else limit, 100) retrieve = min(100 if limit is None else limit, 100)
if retrieve < 1: if retrieve < 1:
return return
raw_users, data, state, limit = await strategy(retrieve, state, limit) data, raw_entries, state, limit = await strategy(retrieve, state, limit)
# Terminate loop on next iteration; there's no data left after this # Terminate loop on next iteration; there's no data left after this
if len(data) < 100: if len(raw_entries) < 100:
limit = 0 limit = 0
if reverse: if reverse:
data = reversed(data) raw_entries = reversed(raw_entries)
if predicate: if predicate:
data = filter(predicate, data) raw_entries = filter(predicate, raw_entries)
users = (User(data=raw_user, state=self._state) for raw_user in raw_users) users = (User(data=raw_user, state=self._state) for raw_user in data.get('users', []))
user_map = {user.id: user for user in users} user_map = {user.id: user for user in users}
for raw_entry in data: integrations = (PartialIntegration(data=raw_i, guild=self) for raw_i in data.get('integrations', []))
integration_map = {integration.id: integration for integration in integrations}
app_commands = (AppCommand(data=raw_cmd, state=self._state) for raw_cmd in data.get('application_commands', []))
app_command_map = {app_command.id: app_command for app_command in app_commands}
for raw_entry in raw_entries:
# Weird Discord quirk # Weird Discord quirk
if raw_entry['action_type'] is None: if raw_entry['action_type'] is None:
continue continue
yield AuditLogEntry(data=raw_entry, users=user_map, guild=self) yield AuditLogEntry(
data=raw_entry,
users=user_map,
integrations=integration_map,
app_commands=app_command_map,
guild=self,
)
async def widget(self) -> Widget: async def widget(self) -> Widget:
"""|coro| """|coro|

51
discord/integrations.py

@ -36,6 +36,7 @@ __all__ = (
'Integration', 'Integration',
'StreamIntegration', 'StreamIntegration',
'BotIntegration', 'BotIntegration',
'PartialIntegration',
) )
if TYPE_CHECKING: if TYPE_CHECKING:
@ -49,6 +50,7 @@ if TYPE_CHECKING:
BotIntegration as BotIntegrationPayload, BotIntegration as BotIntegrationPayload,
IntegrationType, IntegrationType,
IntegrationApplication as IntegrationApplicationPayload, IntegrationApplication as IntegrationApplicationPayload,
PartialIntegration as PartialIntegrationPayload,
) )
@ -115,7 +117,7 @@ class Integration:
self._from_data(data) self._from_data(data)
def __repr__(self) -> str: def __repr__(self) -> str:
return f"<{self.__class__.__name__} id={self.id} name={self.name!r}>" return f'<{self.__class__.__name__} id={self.id} name={self.name!r}>'
def _from_data(self, data: IntegrationPayload) -> None: def _from_data(self, data: IntegrationPayload) -> None:
self.id: int = int(data['id']) self.id: int = int(data['id'])
@ -362,6 +364,53 @@ class BotIntegration(Integration):
self.application: IntegrationApplication = IntegrationApplication(data=data['application'], state=self._state) self.application: IntegrationApplication = IntegrationApplication(data=data['application'], state=self._state)
class PartialIntegration:
"""Represents a partial guild integration.
.. versionadded:: 2.0
Attributes
-----------
id: :class:`int`
The integration ID.
name: :class:`str`
The integration name.
guild: :class:`Guild`
The guild of the integration.
type: :class:`str`
The integration type (i.e. Twitch).
account: :class:`IntegrationAccount`
The account linked to this integration.
application_id: Optional[:class:`int`]
The id of the application this integration belongs to.
"""
__slots__ = (
'guild',
'_state',
'id',
'type',
'name',
'account',
'application_id',
)
def __init__(self, *, data: PartialIntegrationPayload, guild: Guild):
self.guild: Guild = guild
self._state: ConnectionState = guild._state
self._from_data(data)
def __repr__(self) -> str:
return f'<{self.__class__.__name__} id={self.id} name={self.name!r}>'
def _from_data(self, data: PartialIntegrationPayload) -> None:
self.id: int = int(data['id'])
self.type: IntegrationType = data['type']
self.name: str = data['name']
self.account: IntegrationAccount = IntegrationAccount(data['account'])
self.application_id: Optional[int] = _get_as_snowflake(data, 'application_id')
def _integration_factory(value: str) -> Tuple[Type[Integration], str]: def _integration_factory(value: str) -> Tuple[Type[Integration], str]:
if value == 'discord': if value == 'discord':
return BotIntegration, value return BotIntegration, value

12
discord/types/audit_log.py

@ -36,6 +36,7 @@ from .snowflake import Snowflake
from .role import Role from .role import Role
from .channel import ChannelType, PrivacyLevel, VideoQualityMode, PermissionOverwrite from .channel import ChannelType, PrivacyLevel, VideoQualityMode, PermissionOverwrite
from .threads import Thread from .threads import Thread
from .command import ApplicationCommand, ApplicationCommandPermissions
AuditLogEvent = Literal[ AuditLogEvent = Literal[
1, 1,
@ -85,6 +86,7 @@ AuditLogEvent = Literal[
110, 110,
111, 111,
112, 112,
121,
] ]
@ -242,6 +244,12 @@ class _AuditLogChange_EntityType(TypedDict):
old_value: EntityType old_value: EntityType
class _AuditLogChange_AppCommandPermissions(TypedDict):
key: str
new_value: ApplicationCommandPermissions
old_value: ApplicationCommandPermissions
AuditLogChange = Union[ AuditLogChange = Union[
_AuditLogChange_Str, _AuditLogChange_Str,
_AuditLogChange_AssetHash, _AuditLogChange_AssetHash,
@ -260,6 +268,7 @@ AuditLogChange = Union[
_AuditLogChange_PrivacyLevel, _AuditLogChange_PrivacyLevel,
_AuditLogChange_Status, _AuditLogChange_Status,
_AuditLogChange_EntityType, _AuditLogChange_EntityType,
_AuditLogChange_AppCommandPermissions,
] ]
@ -272,6 +281,8 @@ class AuditEntryInfo(TypedDict):
id: Snowflake id: Snowflake
type: Literal['0', '1'] type: Literal['0', '1']
role_name: str role_name: str
application_id: Snowflake
guild_id: Snowflake
class AuditLogEntry(TypedDict): class AuditLogEntry(TypedDict):
@ -291,3 +302,4 @@ class AuditLog(TypedDict):
integrations: List[PartialIntegration] integrations: List[PartialIntegration]
threads: List[Thread] threads: List[Thread]
guild_scheduled_events: List[GuildScheduledEvent] guild_scheduled_events: List[GuildScheduledEvent]
application_commands: List[ApplicationCommand]

2
discord/types/command.py

@ -192,7 +192,7 @@ ApplicationCommand = Union[
] ]
ApplicationCommandPermissionType = Literal[1, 2] ApplicationCommandPermissionType = Literal[1, 2, 3]
class ApplicationCommandPermissions(TypedDict): class ApplicationCommandPermissions(TypedDict):

1
discord/types/integration.py

@ -53,6 +53,7 @@ class PartialIntegration(TypedDict):
name: str name: str
type: IntegrationType type: IntegrationType
account: IntegrationAccount account: IntegrationAccount
application_id: Snowflake
IntegrationType = Literal['twitch', 'youtube', 'discord'] IntegrationType = Literal['twitch', 'youtube', 'discord']

43
docs/api.rst

@ -2239,7 +2239,8 @@ of :class:`enum.Enum`.
A guild integration was created. A guild integration was created.
When this is the action, the type of :attr:`~AuditLogEntry.target` is When this is the action, the type of :attr:`~AuditLogEntry.target` is
the :class:`Object` with the integration ID of the integration which was created. a :class:`PartialIntegration` or :class:`Object` with the
integration ID of the integration which was created.
.. versionadded:: 1.3 .. versionadded:: 1.3
@ -2248,7 +2249,8 @@ of :class:`enum.Enum`.
A guild integration was updated. A guild integration was updated.
When this is the action, the type of :attr:`~AuditLogEntry.target` is When this is the action, the type of :attr:`~AuditLogEntry.target` is
the :class:`Object` with the integration ID of the integration which was updated. a :class:`PartialIntegration` or :class:`Object` with the
integration ID of the integration which was updated.
.. versionadded:: 1.3 .. versionadded:: 1.3
@ -2257,7 +2259,8 @@ of :class:`enum.Enum`.
A guild integration was deleted. A guild integration was deleted.
When this is the action, the type of :attr:`~AuditLogEntry.target` is When this is the action, the type of :attr:`~AuditLogEntry.target` is
the :class:`Object` with the integration ID of the integration which was deleted. a :class:`PartialIntegration` or :class:`Object` with the
integration ID of the integration which was deleted.
.. versionadded:: 1.3 .. versionadded:: 1.3
@ -2465,6 +2468,27 @@ of :class:`enum.Enum`.
.. versionadded:: 2.0 .. versionadded:: 2.0
.. attribute:: app_command_permission_update
An application command or integrations application command permissions
were updated.
When this is the action, the type of :attr:`~AuditLogEntry.target` is
a :class:`PartialIntegration` for an integrations general permissions,
:class:`~discord.app_commands.AppCommand` for a specific commands permissions,
or :class:`Object` with the ID of the command or integration which
was updated.
When this is the action, the type of :attr:`~AuditLogEntry.extra` is
set to an :class:`PartialIntegration` or :class:`Object` with the ID of
application that command or integration belongs to.
Possible attributes for :class:`AuditLogDiff`:
- :attr:`~AuditLogDiff.app_command_permissions`
.. versionadded:: 2.0
.. class:: AuditLogActionCategory .. class:: AuditLogActionCategory
Represents the category that the :class:`AuditLogAction` belongs to. Represents the category that the :class:`AuditLogAction` belongs to.
@ -3477,6 +3501,16 @@ AuditLogDiff
:type: :class:`Asset` :type: :class:`Asset`
.. attribute:: app_command_permissions
A list of application command permission tuples that represents a
target and a :class:`bool` for said target.
The first element is the object being targeted, which can either
be a :class:`Member`, :class:`abc.GuildChannel`,
:class:`~discord.app_commands.AllChannels`, or :class:`Role`.
:type: List[Tuple[target, :class:`bool`]]
.. this is currently missing the following keys: reason and application_id .. this is currently missing the following keys: reason and application_id
I'm not sure how to about porting these I'm not sure how to about porting these
@ -3727,6 +3761,9 @@ Integration
.. autoclass:: StreamIntegration() .. autoclass:: StreamIntegration()
:members: :members:
.. autoclass:: PartialIntegration()
:members:
Member Member
~~~~~~ ~~~~~~

8
docs/interactions/api.rst

@ -129,6 +129,14 @@ Argument
.. autoclass:: discord.app_commands.Argument() .. autoclass:: discord.app_commands.Argument()
:members: :members:
AllChannels
~~~~~~~~~~~~
.. attributetable:: discord.app_commands.AllChannels
.. autoclass:: discord.app_commands.AllChannels()
:members:
Data Classes Data Classes
-------------- --------------

Loading…
Cancel
Save