mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-05-12 16:59:50 +00:00
Implement AutoMod
This commit is contained in:
parent
7ad00750c6
commit
5426d19dc7
@ -67,6 +67,7 @@ from .scheduled_event import *
|
||||
from .interactions import *
|
||||
from .components import *
|
||||
from .threads import *
|
||||
from .automod import *
|
||||
|
||||
|
||||
class VersionInfo(NamedTuple):
|
||||
|
@ -276,6 +276,7 @@ class AuditLogChanges:
|
||||
'preferred_locale': (None, _enum_transformer(enums.Locale)),
|
||||
'image_hash': ('cover_image', _transform_cover_image),
|
||||
'app_command_permission_update': ('app_command_permissions', _transform_app_command_permissions),
|
||||
'trigger_type': (None, _enum_transformer(enums.AutoModRuleTriggerType)),
|
||||
}
|
||||
# fmt: on
|
||||
|
||||
@ -394,6 +395,12 @@ class _AuditLogProxyMessageBulkDelete(_AuditLogProxy):
|
||||
count: int
|
||||
|
||||
|
||||
class _AuditLogProxyAutoModAction(_AuditLogProxy):
|
||||
automod_rule_name: str
|
||||
automod_rule_trigger_type: str
|
||||
channel: Union[abc.GuildChannel, Thread]
|
||||
|
||||
|
||||
class AuditLogEntry(Hashable):
|
||||
r"""Represents an Audit Log entry.
|
||||
|
||||
@ -469,6 +476,7 @@ class AuditLogEntry(Hashable):
|
||||
_AuditLogProxyPinAction,
|
||||
_AuditLogProxyStageInstanceAction,
|
||||
_AuditLogProxyMessageBulkDelete,
|
||||
_AuditLogProxyAutoModAction,
|
||||
Member, User, None, PartialIntegration,
|
||||
Role, Object
|
||||
] = None
|
||||
@ -500,6 +508,16 @@ class AuditLogEntry(Hashable):
|
||||
channel=self.guild.get_channel_or_thread(channel_id) or Object(id=channel_id),
|
||||
message_id=int(extra['message_id']),
|
||||
)
|
||||
elif self.action is enums.AuditLogAction.automod_block_message:
|
||||
channel_id = int(extra['channel_id'])
|
||||
self.extra = _AuditLogProxyAutoModAction(
|
||||
automod_rule_name=extra['auto_moderation_rule_name'],
|
||||
automod_rule_trigger_type=enums.try_enum(
|
||||
enums.AutoModRuleTriggerType, extra['auto_moderation_rule_trigger_type']
|
||||
),
|
||||
channel=self.guild.get_channel_or_thread(channel_id) or Object(id=channel_id),
|
||||
)
|
||||
|
||||
elif self.action.name.startswith('overwrite_'):
|
||||
# the overwrite_ actions have a dict with some information
|
||||
instance_id = int(extra['id'])
|
||||
@ -660,3 +678,6 @@ class AuditLogEntry(Hashable):
|
||||
|
||||
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)
|
||||
|
||||
def _convert_target_auto_moderation(self, target_id: int) -> Union[Member, Object]:
|
||||
return self.guild.get_member(target_id) or Object(target_id)
|
||||
|
487
discord/automod.py
Normal file
487
discord/automod.py
Normal file
@ -0,0 +1,487 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-present Rapptz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import datetime
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Dict, Optional, List, Sequence, Set, Union, Sequence
|
||||
|
||||
|
||||
from .enums import AutoModRuleTriggerType, AutoModRuleActionType, AutoModRuleEventType, try_enum
|
||||
from .flags import AutoModPresets
|
||||
from . import utils
|
||||
from .utils import MISSING, cached_slot_property
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Self
|
||||
from .abc import Snowflake, GuildChannel
|
||||
from .threads import Thread
|
||||
from .guild import Guild
|
||||
from .member import Member
|
||||
from .state import ConnectionState
|
||||
from .types.automod import (
|
||||
AutoModerationRule as AutoModerationRulePayload,
|
||||
AutoModerationTriggerMetadata as AutoModerationTriggerMetadataPayload,
|
||||
AutoModerationAction as AutoModerationActionPayload,
|
||||
AutoModerationActionExecution as AutoModerationActionExecutionPayload,
|
||||
)
|
||||
from .role import Role
|
||||
|
||||
__all__ = (
|
||||
'AutoModRuleAction',
|
||||
'AutoModTrigger',
|
||||
'AutoModRule',
|
||||
'AutoModAction',
|
||||
)
|
||||
|
||||
|
||||
class AutoModRuleAction:
|
||||
"""Represents an auto moderation's rule action.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
type: :class:`AutoModRuleActionType`
|
||||
The type of action to take.
|
||||
channel_id: Optional[:class:`int`]
|
||||
The ID of the channel to send the alert message to, if any.
|
||||
duration: Optional[:class:`datetime.timedelta`]
|
||||
The duration of the timeout to apply, if any.
|
||||
Has a maximum of 28 days.
|
||||
"""
|
||||
|
||||
__slots__ = ('type', 'channel_id', 'duration')
|
||||
|
||||
def __init__(self, *, channel_id: Optional[int] = None, duration: Optional[datetime.timedelta] = None) -> None:
|
||||
self.channel_id: Optional[int] = channel_id
|
||||
self.duration: Optional[datetime.timedelta] = duration
|
||||
if channel_id and duration:
|
||||
raise ValueError('Please provide only one of ``channel`` or ``duration``')
|
||||
|
||||
if channel_id:
|
||||
self.type = AutoModRuleActionType.send_alert_message
|
||||
elif duration:
|
||||
self.type = AutoModRuleActionType.timeout
|
||||
else:
|
||||
self.type = AutoModRuleActionType.block_message
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<AutoModRuleAction type={self.type.value} channel={self.channel_id} duration={self.duration}>'
|
||||
|
||||
@classmethod
|
||||
def from_data(cls, data: AutoModerationActionPayload) -> Self:
|
||||
type_ = try_enum(AutoModRuleActionType, data['type'])
|
||||
if data['type'] == AutoModRuleActionType.timeout.value:
|
||||
duration_seconds = data['metadata']['duration_seconds']
|
||||
return cls(duration=datetime.timedelta(seconds=duration_seconds))
|
||||
elif data['type'] == AutoModRuleActionType.send_alert_message.value:
|
||||
channel_id = int(data['metadata']['channel_id'])
|
||||
return cls(channel_id=channel_id)
|
||||
return cls()
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
ret = {'type': self.type.value, 'metadata': {}}
|
||||
if self.type is AutoModRuleActionType.timeout:
|
||||
ret['metadata'] = {'duration_seconds': int(self.duration.total_seconds())} # type: ignore # duration cannot be None here
|
||||
elif self.type is AutoModRuleActionType.send_alert_message:
|
||||
ret['metadata'] = {'channel_id': str(self.channel_id)}
|
||||
return ret
|
||||
|
||||
|
||||
class AutoModTrigger:
|
||||
"""Represents a trigger for an auto moderation rule.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
type: :class:`AutoModRuleTriggerType`
|
||||
The type of trigger.
|
||||
keyword_filter: Optional[List[:class:`str`]]
|
||||
The list of strings that will trigger the keyword filter.
|
||||
presets: Optional[:class:`AutoModPresets`]
|
||||
The presets used with the preset keyword filter.
|
||||
"""
|
||||
|
||||
__slots__ = ('type', 'keyword_filter', 'presets')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
keyword_filter: Optional[List[str]] = None,
|
||||
presets: Optional[AutoModPresets] = None,
|
||||
) -> None:
|
||||
self.keyword_filter: Optional[List[str]] = keyword_filter
|
||||
self.presets: Optional[AutoModPresets] = presets
|
||||
if keyword_filter and presets:
|
||||
raise ValueError('Please pass only one of keyword_filter or presets.')
|
||||
|
||||
if self.keyword_filter is not None:
|
||||
self.type = AutoModRuleTriggerType.keyword
|
||||
else:
|
||||
self.type = AutoModRuleTriggerType.keyword_preset
|
||||
|
||||
@classmethod
|
||||
def from_data(cls, type: int, data: Optional[AutoModerationTriggerMetadataPayload]) -> Self:
|
||||
type_ = try_enum(AutoModRuleTriggerType, type)
|
||||
if type_ is AutoModRuleTriggerType.keyword:
|
||||
return cls(keyword_filter=data['keyword_filter']) # type: ignore # unable to typeguard due to outer payload
|
||||
else:
|
||||
return cls(presets=AutoModPresets._from_value(data['presets'])) # type: ignore # unable to typeguard due to outer payload
|
||||
|
||||
def to_metadata_dict(self) -> Dict[str, Any]:
|
||||
if self.keyword_filter is not None:
|
||||
return {'keyword_filter': self.keyword_filter}
|
||||
elif self.presets is not None:
|
||||
return {'presets': self.presets.to_array()}
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
class AutoModRule:
|
||||
"""Represents an auto moderation rule.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
id: :class:`int`
|
||||
The ID of the rule.
|
||||
guild: :class:`Guild`
|
||||
The guild the rule is for.
|
||||
name: :class:`str`
|
||||
The name of the rule.
|
||||
creator_id: :class:`int`
|
||||
The ID of the user that created the rule.
|
||||
trigger: :class:`AutoModTrigger`
|
||||
The rule's trigger.
|
||||
enabled: :class:`bool`
|
||||
Whether the rule is enabled.
|
||||
exempt_role_ids: Set[:class:`int`]
|
||||
The IDs of the roles that are exempt from the rule.
|
||||
exempt_channel_ids: Set[:class:`int`]
|
||||
The IDs of the channels that are exempt from the rule.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
'_state',
|
||||
'_cs_exempt_roles',
|
||||
'_cs_exempt_channels',
|
||||
'_cs_actions',
|
||||
'id',
|
||||
'guild',
|
||||
'name',
|
||||
'creator_id',
|
||||
'event_type',
|
||||
'trigger',
|
||||
'enabled',
|
||||
'exempt_role_ids',
|
||||
'exempt_channel_ids',
|
||||
'_actions',
|
||||
)
|
||||
|
||||
def __init__(self, *, data: AutoModerationRulePayload, guild: Guild, state: ConnectionState) -> None:
|
||||
self._state: ConnectionState = state
|
||||
self.guild: Guild = guild
|
||||
self.id: int = int(data['id'])
|
||||
self.name: str = data['name']
|
||||
self.creator_id = int(data['creator_id'])
|
||||
self.event_type: AutoModRuleEventType = try_enum(AutoModRuleEventType, data['event_type'])
|
||||
self.trigger: AutoModTrigger = AutoModTrigger.from_data(data['trigger_type'], data=data.get('trigger_metadata'))
|
||||
self.enabled: bool = data['enabled']
|
||||
self.exempt_role_ids: Set[int] = {int(role_id) for role_id in data['exempt_roles']}
|
||||
self.exempt_channel_ids: Set[int] = {int(channel_id) for channel_id in data['exempt_channels']}
|
||||
self._actions: List[AutoModerationActionPayload] = data['actions']
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<AutoModRule id={self.id} name={self.name!r} guild={self.guild!r}>'
|
||||
|
||||
def to_dict(self) -> AutoModerationRulePayload:
|
||||
ret: AutoModerationRulePayload = {
|
||||
'id': str(self.id),
|
||||
'guild_id': str(self.guild.id),
|
||||
'name': self.name,
|
||||
'creator_id': str(self.creator_id),
|
||||
'event_type': self.event_type.value,
|
||||
'trigger_type': self.trigger.type.value,
|
||||
'trigger_metadata': self.trigger.to_metadata_dict(),
|
||||
'actions': [action.to_dict() for action in self.actions],
|
||||
'enabled': self.enabled,
|
||||
'exempt_roles': [str(role_id) for role_id in self.exempt_role_ids],
|
||||
'exempt_channels': [str(channel_id) for channel_id in self.exempt_channel_ids],
|
||||
} # type: ignore # trigger types break the flow here.
|
||||
|
||||
return ret
|
||||
|
||||
@property
|
||||
def creator(self) -> Optional[Member]:
|
||||
"""Optional[:class:`Member`]: The member that created this rule."""
|
||||
return self.guild.get_member(self.creator_id)
|
||||
|
||||
@cached_slot_property('_cs_exempt_roles')
|
||||
def exempt_roles(self) -> List[Role]:
|
||||
"""List[:class:`Role`]: The roles that are exempt from this rule."""
|
||||
result = []
|
||||
get_role = self.guild.get_role
|
||||
for role_id in self.exempt_role_ids:
|
||||
role = get_role(role_id)
|
||||
if role is not None:
|
||||
result.append(role)
|
||||
|
||||
return utils._unique(result)
|
||||
|
||||
@cached_slot_property('_cs_exempt_channels')
|
||||
def exempt_channels(self) -> List[Union[GuildChannel, Thread]]:
|
||||
"""List[Union[:class:`abc.GuildChannel`, :class:`Thread`]]: The channels that are exempt from this rule."""
|
||||
it = filter(None, map(self.guild._resolve_channel, self.exempt_channel_ids))
|
||||
return utils._unique(it)
|
||||
|
||||
@cached_slot_property('_cs_actions')
|
||||
def actions(self) -> List[AutoModRuleAction]:
|
||||
"""List[:class:`AutoModRuleAction`]: The actions that are taken when this rule is triggered."""
|
||||
return [AutoModRuleAction.from_data(action) for action in self._actions]
|
||||
|
||||
def is_exempt(self, obj: Snowflake, /) -> bool:
|
||||
"""Check if an object is exempt from the automod rule.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
obj: :class:`abc.Snowflake`
|
||||
The role, channel, or thread to check.
|
||||
|
||||
Returns
|
||||
--------
|
||||
:class:`bool`
|
||||
Whether the object is exempt from the automod rule.
|
||||
"""
|
||||
return obj.id in self.exempt_channel_ids or obj.id in self.exempt_role_ids
|
||||
|
||||
async def edit(
|
||||
self,
|
||||
*,
|
||||
name: str = MISSING,
|
||||
event_type: AutoModRuleEventType = MISSING,
|
||||
actions: List[AutoModRuleAction] = MISSING,
|
||||
trigger: AutoModTrigger = MISSING,
|
||||
enabled: bool = MISSING,
|
||||
exempt_roles: Sequence[Snowflake] = MISSING,
|
||||
exempt_channels: Sequence[Snowflake] = MISSING,
|
||||
reason: str = MISSING,
|
||||
) -> Self:
|
||||
"""|coro|
|
||||
|
||||
Edits this auto moderation rule.
|
||||
|
||||
You must have :attr:`Permissions.manage_guild` to edit rules.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
name: :class:`str`
|
||||
The new name to change to.
|
||||
event_type: :class:`AutoModRuleEventType`
|
||||
The new event type to change to.
|
||||
actions: List[:class:`AutoModRuleAction`]
|
||||
The new rule actions to update.
|
||||
trigger: :class:`AutoModTrigger`
|
||||
The new trigger to update.
|
||||
You can only change the trigger metadata, not the type.
|
||||
enabled: :class:`bool`
|
||||
Whether the rule should be enabled or not.
|
||||
exempt_roles: Sequence[:class:`abc.Snowflake`]
|
||||
The new roles to exempt from the rule.
|
||||
exempt_channels: Sequence[:class:`abc.Snowflake`]
|
||||
The new channels to exempt from the rule.
|
||||
reason: :class:`str`
|
||||
The reason for updating this rule. Shows up on the audit log.
|
||||
|
||||
Raises
|
||||
-------
|
||||
Forbidden
|
||||
You do not have permission to edit this rule.
|
||||
HTTPException
|
||||
Editing the rule failed.
|
||||
|
||||
Returns
|
||||
--------
|
||||
:class:`AutoModRule`
|
||||
The updated auto moderation rule.
|
||||
"""
|
||||
payload = {}
|
||||
if actions is not MISSING:
|
||||
payload['actions'] = [action.to_dict() for action in actions]
|
||||
|
||||
if name is not MISSING:
|
||||
payload['name'] = name
|
||||
|
||||
if event_type is not MISSING:
|
||||
payload['event_type'] = event_type
|
||||
|
||||
if trigger is not MISSING:
|
||||
payload['trigger_metadata'] = trigger.to_metadata_dict()
|
||||
|
||||
if enabled is not MISSING:
|
||||
payload['enabled'] = enabled
|
||||
|
||||
if exempt_roles is not MISSING:
|
||||
payload['exempt_roles'] = exempt_roles
|
||||
|
||||
if exempt_channels is not MISSING:
|
||||
payload['exempt_channels'] = exempt_channels
|
||||
|
||||
data = await self._state.http.edit_auto_moderation_rule(
|
||||
self.guild.id,
|
||||
self.id,
|
||||
reason=reason,
|
||||
**payload,
|
||||
)
|
||||
|
||||
return AutoModRule(data=data, guild=self.guild, state=self._state)
|
||||
|
||||
async def delete(self, *, reason: str = MISSING) -> None:
|
||||
"""|coro|
|
||||
|
||||
Deletes the auto moderation rule.
|
||||
|
||||
You must have :attr:`Permissions.manage_guild` to delete rules.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
reason: :class:`str`
|
||||
The reason for deleting this rule. Shows up on the audit log.
|
||||
|
||||
Raises
|
||||
-------
|
||||
Forbidden
|
||||
You do not have permissions to delete the rule.
|
||||
HTTPException
|
||||
Deleting the rule failed.
|
||||
"""
|
||||
await self._state.http.delete_auto_moderation_rule(self.guild.id, self.id, reason=reason)
|
||||
|
||||
|
||||
class AutoModAction:
|
||||
"""Represents an action that was taken as the result of a moderation rule.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
action: :class:`AutoModRuleAction`
|
||||
The action that was taken.
|
||||
message_id: Optional[:class:`int`]
|
||||
The message ID that triggered the action.
|
||||
rule_id: :class:`int`
|
||||
The ID of the rule that was triggered.
|
||||
rule_trigger_type: :class:`AutoModRuleTriggerType`
|
||||
The trigger type of the rule that was triggered.
|
||||
guild_id: :class:`int`
|
||||
The ID of the guild where the rule was triggered.
|
||||
user_id: :class:`int`
|
||||
The ID of the user that triggered the rule.
|
||||
channel_id: :class:`int`
|
||||
The ID of the channel where the rule was triggered.
|
||||
alert_system_message_id: Optional[:class:`int`]
|
||||
The ID of the system message that was sent to the predefined alert channel.
|
||||
content: :class:`str`
|
||||
The content of the message that triggered the rule.
|
||||
Requires the :attr:`Intents.message_content` or it will always return an empty string.
|
||||
matched_keyword: Optional[:class:`str`]
|
||||
The matched keyword from the triggering message.
|
||||
matched_content: Optional[:class:`str`]
|
||||
The matched content from the triggering message.
|
||||
Requires the :attr:`Intents.message_content` or it will always return an empty string.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
'_state',
|
||||
'action',
|
||||
'rule_id',
|
||||
'rule_trigger_type',
|
||||
'guild_id',
|
||||
'user_id',
|
||||
'channel_id',
|
||||
'message_id',
|
||||
'alert_system_message_id',
|
||||
'content',
|
||||
'matched_keyword',
|
||||
'matched_content',
|
||||
)
|
||||
|
||||
def __init__(self, *, data: AutoModerationActionExecutionPayload, state: ConnectionState) -> None:
|
||||
self._state: ConnectionState = state
|
||||
self.message_id: Optional[int] = utils._get_as_snowflake(data, 'message_id')
|
||||
self.action: AutoModRuleAction = AutoModRuleAction.from_data(data['action'])
|
||||
self.rule_id: int = int(data['rule_id'])
|
||||
self.rule_trigger_type: AutoModRuleTriggerType = try_enum(AutoModRuleTriggerType, data['rule_trigger_type'])
|
||||
self.guild_id: int = int(data['guild_id'])
|
||||
self.channel_id: Optional[int] = utils._get_as_snowflake(data, 'channel_id')
|
||||
self.user_id: int = int(data['user_id'])
|
||||
self.alert_system_message_id: Optional[int] = utils._get_as_snowflake(data, 'alert_system_message_id')
|
||||
self.content: str = data['content']
|
||||
self.matched_keyword: Optional[str] = data['matched_keyword']
|
||||
self.matched_content: Optional[str] = data['matched_content']
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<AutoModRuleExecution rule_id={self.rule_id} action={self.action!r}>'
|
||||
|
||||
@property
|
||||
def guild(self) -> Guild:
|
||||
""":class:`Guild`: The guild this action was taken in."""
|
||||
return self._state._get_or_create_unavailable_guild(self.guild_id)
|
||||
|
||||
@property
|
||||
def channel(self) -> Optional[Union[GuildChannel, Thread]]:
|
||||
"""Optional[Union[:class:`abc.GuildChannel`, :class:`Thread`]]: The channel this action was taken in."""
|
||||
if self.channel_id:
|
||||
return self.guild.get_channel(self.channel_id)
|
||||
return None
|
||||
|
||||
@property
|
||||
def member(self) -> Optional[Member]:
|
||||
"""Optional[:class:`Member`]: The member this action was taken against /who triggered this rule."""
|
||||
return self.guild.get_member(self.user_id)
|
||||
|
||||
async def fetch_rule(self) -> AutoModRule:
|
||||
"""|coro|
|
||||
|
||||
Fetch the rule whose action was taken.
|
||||
|
||||
You must have the :attr:`Permissions.manage_guild` permission to use this.
|
||||
|
||||
Raises
|
||||
-------
|
||||
Forbidden
|
||||
You do not have permissions to view the rule.
|
||||
HTTPException
|
||||
Fetching the rule failed.
|
||||
|
||||
Returns
|
||||
--------
|
||||
:class:`AutoModRule`
|
||||
The rule that was executed.
|
||||
"""
|
||||
|
||||
data = await self._state.http.get_auto_moderation_rule(self.guild.id, self.rule_id)
|
||||
return AutoModRule(data=data, guild=self.guild, state=self._state)
|
@ -63,6 +63,9 @@ __all__ = (
|
||||
'AppCommandType',
|
||||
'AppCommandOptionType',
|
||||
'AppCommandPermissionType',
|
||||
'AutoModRuleTriggerType',
|
||||
'AutoModRuleEventType',
|
||||
'AutoModRuleActionType',
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -227,6 +230,7 @@ class MessageType(Enum):
|
||||
thread_starter_message = 21
|
||||
guild_invite_reminder = 22
|
||||
context_menu_command = 23
|
||||
auto_moderation_action = 24
|
||||
|
||||
|
||||
class SpeakingState(Enum):
|
||||
@ -347,6 +351,10 @@ class AuditLogAction(Enum):
|
||||
thread_update = 111
|
||||
thread_delete = 112
|
||||
app_command_permission_update = 121
|
||||
automod_rule_create = 140
|
||||
automod_rule_update = 141
|
||||
automod_rule_delete = 142
|
||||
automod_block_message = 143
|
||||
# fmt: on
|
||||
|
||||
@property
|
||||
@ -401,6 +409,10 @@ class AuditLogAction(Enum):
|
||||
AuditLogAction.thread_delete: AuditLogActionCategory.delete,
|
||||
AuditLogAction.thread_update: AuditLogActionCategory.update,
|
||||
AuditLogAction.app_command_permission_update: AuditLogActionCategory.update,
|
||||
AuditLogAction.automod_rule_create: AuditLogActionCategory.create,
|
||||
AuditLogAction.automod_rule_update: AuditLogActionCategory.update,
|
||||
AuditLogAction.automod_rule_delete: AuditLogActionCategory.delete,
|
||||
AuditLogAction.automod_block_message: None,
|
||||
}
|
||||
# fmt: on
|
||||
return lookup[self]
|
||||
@ -440,6 +452,8 @@ class AuditLogAction(Enum):
|
||||
return 'thread'
|
||||
elif v < 122:
|
||||
return 'integration_or_app_command'
|
||||
elif v < 144:
|
||||
return 'auto_moderation'
|
||||
|
||||
|
||||
class UserFlags(Enum):
|
||||
@ -689,6 +703,23 @@ class AppCommandPermissionType(Enum):
|
||||
channel = 3
|
||||
|
||||
|
||||
class AutoModRuleTriggerType(Enum):
|
||||
keyword = 1
|
||||
harmful_link = 2
|
||||
spam = 3
|
||||
keyword_preset = 4
|
||||
|
||||
|
||||
class AutoModRuleEventType(Enum):
|
||||
message_send = 1
|
||||
|
||||
|
||||
class AutoModRuleActionType(Enum):
|
||||
block_message = 1
|
||||
send_alert_message = 2
|
||||
timeout = 3
|
||||
|
||||
|
||||
def create_unknown_value(cls: Type[E], val: Any) -> E:
|
||||
value_cls = cls._enum_value_cls_ # type: ignore # This is narrowed below
|
||||
name = f'unknown_{val}'
|
||||
|
133
discord/flags.py
133
discord/flags.py
@ -24,6 +24,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import reduce
|
||||
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Iterator, List, Optional, Tuple, Type, TypeVar, overload
|
||||
|
||||
from .enums import UserFlags
|
||||
@ -40,6 +41,7 @@ __all__ = (
|
||||
'MemberCacheFlags',
|
||||
'ApplicationFlags',
|
||||
'ChannelFlags',
|
||||
'AutoModPresets',
|
||||
)
|
||||
|
||||
BF = TypeVar('BF', bound='BaseFlags')
|
||||
@ -655,8 +657,7 @@ class Intents(BaseFlags):
|
||||
@classmethod
|
||||
def all(cls: Type[Intents]) -> Intents:
|
||||
"""A factory method that creates a :class:`Intents` with everything enabled."""
|
||||
bits = max(cls.VALID_FLAGS.values()).bit_length()
|
||||
value = (1 << bits) - 1
|
||||
value = reduce(lambda a, b: a | b, cls.VALID_FLAGS.values())
|
||||
self = cls.__new__(cls)
|
||||
self.value = value
|
||||
return self
|
||||
@ -1104,6 +1105,31 @@ class Intents(BaseFlags):
|
||||
"""
|
||||
return 1 << 16
|
||||
|
||||
@flag_value
|
||||
def auto_moderation_configuration(self):
|
||||
""":class:`bool`: Whether auto moderation configuration related events are enabled.
|
||||
|
||||
This corresponds to the following events:
|
||||
|
||||
- :func:`on_automod_rule_create`
|
||||
- :func:`on_automod_rule_update`
|
||||
- :func:`on_automod_rule_delete`
|
||||
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
return 1 << 20
|
||||
|
||||
@flag_value
|
||||
def auto_moderation_execution(self):
|
||||
""":class:`bool`: Whether auto moderation execution related events are enabled.
|
||||
|
||||
This corresponds to the following events:
|
||||
- :func:`on_automod_action`
|
||||
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
return 1 << 21
|
||||
|
||||
|
||||
@fill_with_flags()
|
||||
class MemberCacheFlags(BaseFlags):
|
||||
@ -1436,3 +1462,106 @@ class ChannelFlags(BaseFlags):
|
||||
def pinned(self):
|
||||
""":class:`bool`: Returns ``True`` if the thread is pinned to the forum channel."""
|
||||
return 1 << 1
|
||||
|
||||
|
||||
class ArrayFlags(BaseFlags):
|
||||
@classmethod
|
||||
def _from_value(cls: Type[Self], value: List[int]) -> Self:
|
||||
self = cls.__new__(cls)
|
||||
self.value = reduce(lambda a, b: a | (1 << b - 1), value)
|
||||
return self
|
||||
|
||||
def to_array(self) -> List[int]:
|
||||
return [i + 1 for i in range(self.value.bit_length()) if self.value & (1 << i)]
|
||||
|
||||
|
||||
@fill_with_flags()
|
||||
class AutoModPresets(ArrayFlags):
|
||||
r"""Wraps up the Discord :class:`AutoModRule` presets.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
|
||||
.. container:: operations
|
||||
|
||||
.. describe:: x == y
|
||||
|
||||
Checks if two AutoMod preset flags are equal.
|
||||
|
||||
.. describe:: x != y
|
||||
|
||||
Checks if two AutoMod preset flags are not equal.
|
||||
|
||||
.. describe:: x | y, x |= y
|
||||
|
||||
Returns a AutoModPresets instance with all enabled flags from
|
||||
both x and y.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. describe:: x & y, x &= y
|
||||
|
||||
Returns a AutoModPresets instance with only flags enabled on
|
||||
both x and y.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. describe:: x ^ y, x ^= y
|
||||
|
||||
Returns a AutoModPresets instance with only flags enabled on
|
||||
only one of x or y, not on both.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. describe:: ~x
|
||||
|
||||
Returns a AutoModPresets instance with all flags inverted from x.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. describe:: hash(x)
|
||||
|
||||
Return the flag's hash.
|
||||
.. describe:: iter(x)
|
||||
|
||||
Returns an iterator of ``(name, value)`` pairs. This allows it
|
||||
to be, for example, constructed as a dict or a list of pairs.
|
||||
Note that aliases are not shown.
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
value: :class:`int`
|
||||
The raw value. You should query flags via the properties
|
||||
rather than using this raw value.
|
||||
"""
|
||||
|
||||
@flag_value
|
||||
def profanity(self):
|
||||
""":class:`bool`: Whether to use the preset profanity filter."""
|
||||
return 1 << 0
|
||||
|
||||
@flag_value
|
||||
def sexual_content(self):
|
||||
""":class:`bool`: Whether to use the preset sexual content filter."""
|
||||
return 1 << 1
|
||||
|
||||
@flag_value
|
||||
def slurs(self):
|
||||
""":class:`bool`: Whether to use the preset slurs filter."""
|
||||
return 1 << 2
|
||||
|
||||
@classmethod
|
||||
def all(cls: Type[Self]) -> Self:
|
||||
"""A factory method that creates a :class:`AutoModPresets` with everything enabled."""
|
||||
bits = max(cls.VALID_FLAGS.values()).bit_length()
|
||||
value = (1 << bits) - 1
|
||||
self = cls.__new__(cls)
|
||||
self.value = value
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def none(cls: Type[Self]) -> Self:
|
||||
"""A factory method that creates a :class:`AutoModPresets` with everything disabled."""
|
||||
self = cls.__new__(cls)
|
||||
self.value = self.DEFAULT_VALUE
|
||||
return self
|
||||
|
123
discord/guild.py
123
discord/guild.py
@ -71,6 +71,7 @@ from .enums import (
|
||||
NSFWLevel,
|
||||
MFALevel,
|
||||
Locale,
|
||||
AutoModRuleEventType,
|
||||
)
|
||||
from .mixins import Hashable
|
||||
from .user import User
|
||||
@ -87,6 +88,7 @@ from .file import File
|
||||
from .audit_logs import AuditLogEntry
|
||||
from .object import OLDEST_OBJECT, Object
|
||||
from .welcome_screen import WelcomeScreen, WelcomeChannel
|
||||
from .automod import AutoModRule, AutoModTrigger, AutoModRuleAction
|
||||
|
||||
|
||||
__all__ = (
|
||||
@ -3833,3 +3835,124 @@ class Guild(Hashable):
|
||||
ws = self._state._get_websocket(self.id)
|
||||
channel_id = channel.id if channel else None
|
||||
await ws.voice_state(self.id, channel_id, self_mute, self_deaf)
|
||||
|
||||
async def fetch_automod_rule(self, automod_rule_id: int, /) -> AutoModRule:
|
||||
"""|coro|
|
||||
|
||||
Fetches an active automod rule from the guild.
|
||||
|
||||
You must have the :attr:`Permissions.manage_guild` to use this.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
automod_rule_id: :class:`int`
|
||||
The ID of the automod rule to fetch.
|
||||
|
||||
Raises
|
||||
-------
|
||||
Forbidden
|
||||
You do not have permission to view the automod rule.
|
||||
|
||||
Returns
|
||||
--------
|
||||
:class:`AutoModRule`
|
||||
The automod rule that was fetched.
|
||||
"""
|
||||
|
||||
data = await self._state.http.get_auto_moderation_rule(self.id, automod_rule_id)
|
||||
|
||||
return AutoModRule(data=data, guild=self, state=self._state)
|
||||
|
||||
async def fetch_automod_rules(self) -> List[AutoModRule]:
|
||||
"""|coro|
|
||||
|
||||
Fetches all automod rules from the guild.
|
||||
|
||||
You must have the :attr:`Permissions.manage_guild` to use this.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Raises
|
||||
-------
|
||||
Forbidden
|
||||
You do not have permission to view the automod rule.
|
||||
NotFound
|
||||
There are no automod rules within this guild.
|
||||
|
||||
Returns
|
||||
--------
|
||||
List[:class:`AutoModRule`]
|
||||
The automod rules that were fetched.
|
||||
"""
|
||||
data = await self._state.http.get_auto_moderation_rules(self.id)
|
||||
|
||||
return [AutoModRule(data=d, guild=self, state=self._state) for d in data]
|
||||
|
||||
async def create_automod_rule(
|
||||
self,
|
||||
*,
|
||||
name: str,
|
||||
event_type: AutoModRuleEventType,
|
||||
trigger: AutoModTrigger,
|
||||
actions: List[AutoModRuleAction],
|
||||
enabled: bool = MISSING,
|
||||
exempt_roles: Sequence[Snowflake] = MISSING,
|
||||
exempt_channels: Sequence[Snowflake] = MISSING,
|
||||
reason: str = MISSING,
|
||||
) -> AutoModRule:
|
||||
"""|coro|
|
||||
|
||||
Create an automod rule.
|
||||
|
||||
You must have the :attr:`Permissions.manage_guild` permission to use this.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
name: :class:`str`
|
||||
The name of the automod rule.
|
||||
event_type: :class:`AutoModRuleEventType`
|
||||
The type of event that the automod rule will trigger on.
|
||||
trigger: :class:`AutoModTrigger`
|
||||
The trigger that will trigger the automod rule.
|
||||
actions: List[:class:`AutoModRuleAction`]
|
||||
The actions that will be taken when the automod rule is triggered.
|
||||
enabled: :class:`bool`
|
||||
Whether the automod rule is enabled.
|
||||
Discord will default to ``False``.
|
||||
exempt_roles: Sequence[:class:`abc.Snowflake`]
|
||||
A list of roles that will be exempt from the automod rule.
|
||||
exempt_channels: Sequence[:class:`abc.Snowflake`]
|
||||
A list of channels that will be exempt from the automod rule.
|
||||
reason: :class:`str`
|
||||
The reason for creating this automod rule. Shows up on the audit log.
|
||||
|
||||
Raises
|
||||
-------
|
||||
Forbidden
|
||||
You do not have permissions to create an automod rule.
|
||||
HTTPException
|
||||
Creating the automod rule failed.
|
||||
|
||||
Returns
|
||||
--------
|
||||
:class:`AutoModRule`
|
||||
The automod rule that was created.
|
||||
"""
|
||||
data = await self._state.http.create_auto_moderation_rule(
|
||||
self.id,
|
||||
name=name,
|
||||
event_type=event_type.value,
|
||||
trigger_type=trigger.type.value,
|
||||
trigger_metadata=trigger.to_metadata_dict() or None,
|
||||
actions=[a.to_dict() for a in actions],
|
||||
enabled=enabled,
|
||||
exempt_roles=[str(r.id) for r in exempt_roles] if exempt_roles else None,
|
||||
exempt_channel=[str(c.id) for c in exempt_channels] if exempt_channels else None,
|
||||
reason=reason,
|
||||
)
|
||||
|
||||
return AutoModRule(data=data, guild=self, state=self._state)
|
||||
|
@ -71,6 +71,7 @@ if TYPE_CHECKING:
|
||||
from .types import (
|
||||
appinfo,
|
||||
audit_log,
|
||||
automod,
|
||||
channel,
|
||||
command,
|
||||
emoji,
|
||||
@ -2039,6 +2040,63 @@ class HTTPClient:
|
||||
)
|
||||
return self.request(r, json=payload)
|
||||
|
||||
def get_auto_moderation_rules(self, guild_id: Snowflake) -> Response[List[automod.AutoModerationRule]]:
|
||||
return self.request(Route('GET', '/guilds/{guild_id}/auto-moderation/rules', guild_id=guild_id))
|
||||
|
||||
def get_auto_moderation_rule(self, guild_id: Snowflake, rule_id: Snowflake) -> Response[automod.AutoModerationRule]:
|
||||
return self.request(
|
||||
Route('GET', '/guilds/{guild_id}/auto-moderation/rules/{rule_id}', guild_id=guild_id, rule_id=rule_id)
|
||||
)
|
||||
|
||||
def create_auto_moderation_rule(
|
||||
self, guild_id: Snowflake, *, reason: Optional[str], **payload: Any
|
||||
) -> Response[automod.AutoModerationRule]:
|
||||
valid_keys = (
|
||||
'name',
|
||||
'event_type',
|
||||
'trigger_type',
|
||||
'trigger_metadata',
|
||||
'actions',
|
||||
'enabled',
|
||||
'exempt_roles',
|
||||
'exempt_channels',
|
||||
)
|
||||
|
||||
payload = {k: v for k, v in payload.items() if k in valid_keys and v is not None}
|
||||
|
||||
return self.request(
|
||||
Route('POST', '/guilds/{guild_id}/auto-moderation/rules', guild_id=guild_id), json=payload, reason=reason
|
||||
)
|
||||
|
||||
def edit_auto_moderation_rule(
|
||||
self, guild_id: Snowflake, rule_id: Snowflake, *, reason: Optional[str], **payload: Any
|
||||
) -> Response[automod.AutoModerationRule]:
|
||||
valid_keys = (
|
||||
'name',
|
||||
'event_type',
|
||||
'trigger_metadata',
|
||||
'actions',
|
||||
'enabled',
|
||||
'exempt_roles',
|
||||
'exempt_channels',
|
||||
)
|
||||
|
||||
payload = {k: v for k, v in payload.items() if k in valid_keys and v is not None}
|
||||
|
||||
return self.request(
|
||||
Route('PATCH', '/guilds/{guild_id}/auto-moderation/rules/{rule_id}', guild_id=guild_id, rule_id=rule_id),
|
||||
json=payload,
|
||||
reason=reason,
|
||||
)
|
||||
|
||||
def delete_auto_moderation_rule(
|
||||
self, guild_id: Snowflake, rule_id: Snowflake, *, reason: Optional[str]
|
||||
) -> Response[None]:
|
||||
return self.request(
|
||||
Route('DELETE', '/guilds/{guild_id}/auto-moderation/rules/{rule_id}', guild_id=guild_id, rule_id=rule_id),
|
||||
reason=reason,
|
||||
)
|
||||
|
||||
# Misc
|
||||
|
||||
def application_info(self) -> Response[appinfo.AppInfo]:
|
||||
|
@ -73,6 +73,7 @@ from .scheduled_event import ScheduledEvent
|
||||
from .stage_instance import StageInstance
|
||||
from .threads import Thread, ThreadMember
|
||||
from .sticker import GuildSticker
|
||||
from .automod import AutoModRule, AutoModAction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .abc import PrivateChannel
|
||||
@ -84,6 +85,7 @@ if TYPE_CHECKING:
|
||||
from .gateway import DiscordWebSocket
|
||||
from .app_commands import CommandTree
|
||||
|
||||
from .types.automod import AutoModerationRule, AutoModerationActionExecution
|
||||
from .types.snowflake import Snowflake
|
||||
from .types.activity import Activity as ActivityPayload
|
||||
from .types.channel import DMChannel as DMChannelPayload
|
||||
@ -1079,6 +1081,46 @@ class ConnectionState:
|
||||
guild.stickers = tuple(map(lambda d: self.store_sticker(guild, d), data['stickers']))
|
||||
self.dispatch('guild_stickers_update', guild, before_stickers, guild.stickers)
|
||||
|
||||
def parse_auto_moderation_rule_create(self, data: AutoModerationRule) -> None:
|
||||
guild = self._get_guild(int(data['guild_id']))
|
||||
if guild is None:
|
||||
_log.debug('AUTO_MODERATION_RULE_CREATE referencing an unknown guild ID: %s. Discarding.', data['guild_id'])
|
||||
return
|
||||
|
||||
rule = AutoModRule(data=data, guild=guild, state=self)
|
||||
|
||||
self.dispatch('automod_rule_create', rule)
|
||||
|
||||
def parse_auto_moderation_rule_update(self, data: AutoModerationRule) -> None:
|
||||
guild = self._get_guild(int(data['guild_id']))
|
||||
if guild is None:
|
||||
_log.debug('AUTO_MODERATION_RULE_UPDATE referencing an unknown guild ID: %s. Discarding.', data['guild_id'])
|
||||
return
|
||||
|
||||
rule = AutoModRule(data=data, guild=guild, state=self)
|
||||
|
||||
self.dispatch('automod_rule_update', rule)
|
||||
|
||||
def parse_auto_moderation_rule_delete(self, data: AutoModerationRule) -> None:
|
||||
guild = self._get_guild(int(data['guild_id']))
|
||||
if guild is None:
|
||||
_log.debug('AUTO_MODERATION_RULE_DELETE referencing an unknown guild ID: %s. Discarding.', data['guild_id'])
|
||||
return
|
||||
|
||||
rule = AutoModRule(data=data, guild=guild, state=self)
|
||||
|
||||
self.dispatch('automod_rule_delete', rule)
|
||||
|
||||
def parse_auto_moderation_action_execution(self, data: AutoModerationActionExecution) -> None:
|
||||
guild = self._get_guild(int(data['guild_id']))
|
||||
if guild is None:
|
||||
_log.debug('AUTO_MODERATION_ACTION_EXECUTION referencing an unknown guild ID: %s. Discarding.', data['guild_id'])
|
||||
return
|
||||
|
||||
execution = AutoModAction(data=data, state=self)
|
||||
|
||||
self.dispatch('automod_action', execution)
|
||||
|
||||
def _get_create_guild(self, data: gw.GuildCreateEvent) -> Guild:
|
||||
if data.get('unavailable') is False:
|
||||
# GUILD_CREATE with unavailable in the response
|
||||
|
@ -283,6 +283,8 @@ class AuditEntryInfo(TypedDict):
|
||||
role_name: str
|
||||
application_id: Snowflake
|
||||
guild_id: Snowflake
|
||||
auto_moderation_rule_name: str
|
||||
auto_moderation_rule_trigger_type: str
|
||||
|
||||
|
||||
class AuditLogEntry(TypedDict):
|
||||
|
119
discord/types/automod.py
Normal file
119
discord/types/automod.py
Normal file
@ -0,0 +1,119 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-present Rapptz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
from typing import Literal, TypedDict, List, Union, Optional
|
||||
from typing_extensions import NotRequired
|
||||
|
||||
from .snowflake import Snowflake
|
||||
|
||||
AutoModerationRuleTriggerType = Literal[1, 2, 3, 4]
|
||||
AutoModerationActionTriggerType = Literal[1, 2, 3]
|
||||
AutoModerationRuleEventType = Literal[1]
|
||||
AutoModerationTriggerPresets = Literal[1, 2, 3]
|
||||
|
||||
|
||||
class Empty(TypedDict):
|
||||
...
|
||||
|
||||
|
||||
class _AutoModerationActionMetadataAlert(TypedDict):
|
||||
channel_id: Snowflake
|
||||
|
||||
|
||||
class _AutoModerationActionMetadataTimeout(TypedDict):
|
||||
duration_seconds: int
|
||||
|
||||
|
||||
class _AutoModerationActionBlockMessage(TypedDict):
|
||||
type: Literal[1]
|
||||
metadata: NotRequired[Empty]
|
||||
|
||||
|
||||
class _AutoModerationActionAlert(TypedDict):
|
||||
type: Literal[2]
|
||||
metadata: _AutoModerationActionMetadataAlert
|
||||
|
||||
|
||||
class _AutoModerationActionTimeout(TypedDict):
|
||||
type: Literal[3]
|
||||
metadata: _AutoModerationActionMetadataTimeout
|
||||
|
||||
|
||||
AutoModerationAction = Union[_AutoModerationActionBlockMessage, _AutoModerationActionAlert, _AutoModerationActionTimeout]
|
||||
|
||||
|
||||
class _AutoModerationTriggerMetadataKeyword(TypedDict):
|
||||
keyword_filter: List[str]
|
||||
|
||||
|
||||
class _AutoModerationTriggerMetadataKeywordPreset(TypedDict):
|
||||
presets: List[AutoModerationTriggerPresets]
|
||||
|
||||
|
||||
AutoModerationTriggerMetadata = Union[
|
||||
_AutoModerationTriggerMetadataKeyword, _AutoModerationTriggerMetadataKeywordPreset, Empty
|
||||
]
|
||||
|
||||
|
||||
class _BaseAutoModerationRule(TypedDict):
|
||||
id: Snowflake
|
||||
guild_id: Snowflake
|
||||
name: str
|
||||
creator_id: Snowflake
|
||||
event_type: AutoModerationRuleEventType
|
||||
actions: List[AutoModerationAction]
|
||||
enabled: bool
|
||||
exempt_roles: List[Snowflake]
|
||||
exempt_channels: List[Snowflake]
|
||||
|
||||
|
||||
class _AutoModerationRuleKeyword(_BaseAutoModerationRule):
|
||||
trigger_type: Literal[1]
|
||||
trigger_metadata: _AutoModerationTriggerMetadataKeyword
|
||||
|
||||
|
||||
class _AutoModerationRuleKeywordPreset(_BaseAutoModerationRule):
|
||||
trigger_type: Literal[4]
|
||||
trigger_metadata: _AutoModerationTriggerMetadataKeywordPreset
|
||||
|
||||
|
||||
class _AutoModerationRuleOther(_BaseAutoModerationRule):
|
||||
trigger_type: Literal[2, 3]
|
||||
|
||||
|
||||
AutoModerationRule = Union[_AutoModerationRuleKeyword, _AutoModerationRuleKeywordPreset, _AutoModerationRuleOther]
|
||||
|
||||
|
||||
class AutoModerationActionExecution(TypedDict):
|
||||
guild_id: Snowflake
|
||||
action: AutoModerationAction
|
||||
rule_id: Snowflake
|
||||
rule_trigger_type: AutoModerationRuleTriggerType
|
||||
user_id: Snowflake
|
||||
channel_id: NotRequired[Snowflake]
|
||||
message_id: NotRequired[Snowflake]
|
||||
alert_system_message_id: NotRequired[Snowflake]
|
||||
content: str
|
||||
matched_keyword: Optional[str]
|
||||
matched_content: Optional[str]
|
@ -25,6 +25,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
from typing import List, Literal, Optional, TypedDict
|
||||
from typing_extensions import NotRequired, Required
|
||||
|
||||
from .automod import AutoModerationAction, AutoModerationRuleTriggerType
|
||||
from .activity import PartialPresenceUpdate
|
||||
from .voice import GuildVoiceState
|
||||
from .integration import BaseIntegration, IntegrationApplication
|
||||
@ -321,3 +322,17 @@ class TypingStartEvent(TypedDict):
|
||||
timestamp: int
|
||||
guild_id: NotRequired[Snowflake]
|
||||
member: NotRequired[MemberWithUser]
|
||||
|
||||
|
||||
class AutoModerationActionExecution(TypedDict):
|
||||
guild_id: Snowflake
|
||||
action: AutoModerationAction
|
||||
rule_id: Snowflake
|
||||
rule_trigger_type: AutoModerationRuleTriggerType
|
||||
user_id: Snowflake
|
||||
channel_id: NotRequired[Snowflake]
|
||||
message_id: NotRequired[Snowflake]
|
||||
alert_system_message_id: NotRequired[Snowflake]
|
||||
content: str
|
||||
matched_keyword: Optional[str]
|
||||
matched_content: Optional[str]
|
||||
|
249
docs/api.rst
249
docs/api.rst
@ -203,6 +203,53 @@ to handle it, which defaults to logging the traceback and ignoring the exception
|
||||
errors. In order to turn a function into a coroutine they must be ``async def``
|
||||
functions.
|
||||
|
||||
AutoMod
|
||||
~~~~~~~
|
||||
|
||||
.. function:: on_automod_rule_create(rule)
|
||||
|
||||
Called when a :class:`AutoModRule` is created.
|
||||
|
||||
This requires :attr:`Intents.auto_moderation_configuration` to be enabled.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
:param rule: The rule that was created.
|
||||
:type rule: :class:`AutoModRule`
|
||||
|
||||
.. function:: on_automod_rule_update(rule)
|
||||
|
||||
Called when a :class:`AutoModRule` is updated.
|
||||
|
||||
This requires :attr:`Intents.auto_moderation_configuration` to be enabled.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
:param rule: The rule that was updated.
|
||||
:type rule: :class:`AutoModRule`
|
||||
|
||||
.. function:: on_automod_rule_delete(rule)
|
||||
|
||||
Called when a :class:`AutoModRule` is deleted.
|
||||
|
||||
This requires :attr:`Intents.auto_moderation_configuration` to be enabled.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
:param rule: The rule that was deleted.
|
||||
:type rule: :class:`AutoModRule`
|
||||
|
||||
.. function:: on_automod_action(execution)
|
||||
|
||||
Called when a :class:`AutoModAction` is created/performed.
|
||||
|
||||
This requires :attr:`Intents.auto_moderation_execution` to be enabled.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
:param execution: The rule execution that was performed.
|
||||
:type execution: :class:`AutoModAction`
|
||||
|
||||
Channels
|
||||
~~~~~~~~~
|
||||
|
||||
@ -2525,6 +2572,84 @@ of :class:`enum.Enum`.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. attribute:: automod_rule_create
|
||||
|
||||
An automod rule was created.
|
||||
|
||||
When this is the action, the type of :attr:`~AuditLogEntry.target` is
|
||||
a :class:`Object` with the ID of the automod rule that was created.
|
||||
|
||||
Possible attributes for :class:`AuditLogDiff`:
|
||||
|
||||
- :attr:`~AuditLogDiff.name`
|
||||
- :attr:`~AuditLogDiff.enabled`
|
||||
- :attr:`~AuditLogDiff.event_type`
|
||||
- :attr:`~AuditLogDiff.trigger_type`
|
||||
- :attr:`~AuditLogDiff.trigger_metadata`
|
||||
- :attr:`~AuditLogDiff.actions`
|
||||
- :attr:`~AuditLogDiff.exempt_roles`
|
||||
- :attr:`~AuditLogDiff.exempt_channels`
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. attribute:: automod_role_update
|
||||
|
||||
An automod rule was updated.
|
||||
|
||||
When this is the action, the type of :attr:`~AuditLogEntry.target` is
|
||||
a :class:`Object` with the ID of the automod rule that was updated.
|
||||
|
||||
Possible attributes for :class:`AuditLogDiff`:
|
||||
|
||||
- :attr:`~AuditLogDiff.name`
|
||||
- :attr:`~AuditLogDiff.enabled`
|
||||
- :attr:`~AuditLogDiff.event_type`
|
||||
- :attr:`~AuditLogDiff.trigger_type`
|
||||
- :attr:`~AuditLogDiff.trigger_metadata`
|
||||
- :attr:`~AuditLogDiff.actions`
|
||||
- :attr:`~AuditLogDiff.exempt_roles`
|
||||
- :attr:`~AuditLogDiff.exempt_channels`
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. attribute:: automod_rule_delete
|
||||
|
||||
An automod rule was deleted.
|
||||
|
||||
When this is the action, the type of :attr:`~AuditLogEntry.target` is
|
||||
a :class:`Object` with the ID of the automod rule that was deleted.
|
||||
|
||||
Possible attributes for :class:`AuditLogDiff`:
|
||||
|
||||
- :attr:`~AuditLogDiff.name`
|
||||
- :attr:`~AuditLogDiff.enabled`
|
||||
- :attr:`~AuditLogDiff.event_type`
|
||||
- :attr:`~AuditLogDiff.trigger_type`
|
||||
- :attr:`~AuditLogDiff.trigger_metadata`
|
||||
- :attr:`~AuditLogDiff.actions`
|
||||
- :attr:`~AuditLogDiff.exempt_roles`
|
||||
- :attr:`~AuditLogDiff.exempt_channels`
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. attribute:: automod_block_message
|
||||
|
||||
An automod rule blocked a message from being sent.
|
||||
|
||||
When this is the action, the type of :attr:`~AuditLogEntry.target` is
|
||||
a :class:`Member` with the ID of the person who triggered the automod rule.
|
||||
|
||||
When this is the action, the type of :attr:`~AuditLogEntry.extra` is
|
||||
set to an unspecified proxy object with 3 attributes:
|
||||
|
||||
- ``automod_rule_name``: The name of the automod rule that was triggered.
|
||||
- ``automod_rule_trigger``: A :class:`AutoModRuleTriggerType` representation of the rule type that was triggered.
|
||||
- ``channel``: The channel in which the automod rule was triggered.
|
||||
|
||||
When this is the action, :attr:`AuditLogEntry.changes` is empty.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. class:: AuditLogActionCategory
|
||||
|
||||
Represents the category that the :class:`AuditLogAction` belongs to.
|
||||
@ -2950,6 +3075,56 @@ of :class:`enum.Enum`.
|
||||
|
||||
An alias for :attr:`completed`.
|
||||
|
||||
.. class:: AutoModRuleTriggerType
|
||||
|
||||
Represents the trigger type of an auto mod rule.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. attribute:: keyword
|
||||
|
||||
The rule will trigger when a keyword is mentioned.
|
||||
|
||||
.. attribute:: harmful_link
|
||||
|
||||
The rule will trigger when a harmful link is posted.
|
||||
|
||||
.. attribute:: spam
|
||||
|
||||
The rule will trigger when a spam message is posted.
|
||||
|
||||
.. attribute:: keyword_preset
|
||||
|
||||
The rule will trigger when something triggers based on the set keyword preset types.
|
||||
|
||||
.. class:: AutoModRuleEventType
|
||||
|
||||
Represents the event type of an auto mod rule.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. attribute:: message_send
|
||||
|
||||
The rule will trigger when a message is sent.
|
||||
|
||||
.. class:: AutoModRuleActionType
|
||||
|
||||
Represents the action type of an auto mod rule.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. attribute:: block_message
|
||||
|
||||
The rule will block a message from being sent.
|
||||
|
||||
.. attribute:: send_alert_message
|
||||
|
||||
The rule will send an alert message to a predefined channel.
|
||||
|
||||
.. attribute:: timeout
|
||||
|
||||
The rule will timeout a user.
|
||||
|
||||
.. _discord-api-audit-logs:
|
||||
|
||||
Audit Log Data
|
||||
@ -3543,6 +3718,48 @@ AuditLogDiff
|
||||
|
||||
:type: :class:`~discord.app_commands.AppCommandPermissions`
|
||||
|
||||
.. attribute:: enabled
|
||||
|
||||
Whether the automod rule is active or not.
|
||||
|
||||
:type: :class:`bool`
|
||||
|
||||
.. attribute:: event_type
|
||||
|
||||
The event type for triggering the automod rule.
|
||||
|
||||
:type: :class:`str`
|
||||
|
||||
.. attribute:: trigger_type
|
||||
|
||||
The trigger type for the automod rule.
|
||||
|
||||
:type: :class:`AutoModRuleTriggerType`
|
||||
|
||||
.. attribute:: trigger_metadata
|
||||
|
||||
The trigger metadata for the automod rule.
|
||||
|
||||
:type: Dict[:class:`str`, Any]
|
||||
|
||||
.. attribute:: actions
|
||||
|
||||
The actions to take when an automod rule is triggered.
|
||||
|
||||
:type: List[Dict[:class:`str`, Any]]
|
||||
|
||||
.. attribute:: exempt_roles
|
||||
|
||||
The list of roles that are exempt from the automod rule.
|
||||
|
||||
:type: List[:class:`str`]
|
||||
|
||||
.. attribute:: exempt_channels
|
||||
|
||||
The list of channels that are exempt from the automod rule.
|
||||
|
||||
:type: List[:class:`str`]
|
||||
|
||||
.. this is currently missing the following keys: reason and application_id
|
||||
I'm not sure how to about porting these
|
||||
|
||||
@ -3699,6 +3916,15 @@ User
|
||||
.. automethod:: typing
|
||||
:async-with:
|
||||
|
||||
AutoMod
|
||||
~~~~~~~
|
||||
|
||||
.. autoclass:: AutoModRule()
|
||||
:members:
|
||||
|
||||
.. autoclass:: AutoModAction()
|
||||
:members:
|
||||
|
||||
Attachment
|
||||
~~~~~~~~~~~
|
||||
|
||||
@ -4295,6 +4521,29 @@ ChannelFlags
|
||||
.. autoclass:: ChannelFlags
|
||||
:members:
|
||||
|
||||
AutoModPresets
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. attributetable:: AutoModPresets
|
||||
|
||||
.. autoclass:: AutoModPresets
|
||||
:members:
|
||||
|
||||
AutoModRuleAction
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. attributetable:: AutoModRuleAction
|
||||
|
||||
.. autoclass:: AutoModRuleAction
|
||||
:members:
|
||||
|
||||
AutoModTrigger
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. attributetable:: AutoModTrigger
|
||||
|
||||
.. autoclass:: AutoModTrigger
|
||||
:members:
|
||||
|
||||
File
|
||||
~~~~~
|
||||
|
Loading…
x
Reference in New Issue
Block a user