Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(AutoMod): add support for mention_raid_protection_enabled #898

Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/898.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement new :attr:`AutoModTriggerMetadata.mention_raid_protection_enabled` parameter. Implement ``raid_alerts_enabled`` and ``safety_alerts_channel`` parameters in :meth:`Guild.edit`.
31 changes: 25 additions & 6 deletions disnake/automod.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,12 @@ class AutoModTriggerMetadata:
Based on the trigger type, different fields can be used with various limits:

.. csv-table::
:header: "Trigger Type", ``keyword_filter``, ``regex_patterns``, ``presets``, ``allow_list``, ``mention_total_limit``
:header: "Trigger Type", ``keyword_filter``, ``regex_patterns``, ``presets``, ``allow_list``, ``mention_total_limit``, ``mention_raid_protection_enabled``

:attr:`~AutoModTriggerType.keyword`, ✅ (x1000), ✅ (x10), ❌, ✅ (x100), ❌
:attr:`~AutoModTriggerType.spam`, ❌, ❌, ❌, ❌, ❌
:attr:`~AutoModTriggerType.keyword_preset`, ❌, ❌, ✅, ✅ (x1000), ❌
:attr:`~AutoModTriggerType.mention_spam`, ❌, ❌, ❌, ❌, ✅
:attr:`~AutoModTriggerType.keyword`, ✅ (x1000), ✅ (x10), ❌, ✅ (x100), ❌, ❌
:attr:`~AutoModTriggerType.spam`, ❌, ❌, ❌, ❌, ❌, ❌
:attr:`~AutoModTriggerType.keyword_preset`, ❌, ❌, ✅, ✅ (x1000), ❌, ❌
:attr:`~AutoModTriggerType.mention_spam`, ❌, ❌, ❌, ❌, ✅, ✅

.. versionadded:: 2.6

Expand Down Expand Up @@ -256,6 +256,11 @@ class AutoModTriggerMetadata:

mention_total_limit: Optional[:class:`int`]
The maximum number of mentions (members + roles) allowed, between 1 and 50. Used with :attr:`AutoModTriggerType.mention_spam`.

mention_raid_protection_enabled: Optional[:class:`bool`]
Whether to automatically detect mention raids. Used with :attr:`AutoModTriggerType.mention_spam`.

.. versionadded:: 2.8
"""

__slots__ = (
Expand All @@ -264,6 +269,7 @@ class AutoModTriggerMetadata:
"presets",
"allow_list",
"mention_total_limit",
"mention_raid_protection_enabled",
)

@overload
Expand Down Expand Up @@ -296,7 +302,7 @@ def __init__(
...

@overload
def __init__(self, *, mention_total_limit: int) -> None:
def __init__(self, *, mention_total_limit: int, mention_raid_protection_enabled: bool) -> None:
Victorsitou marked this conversation as resolved.
Show resolved Hide resolved
...

def __init__(
Expand All @@ -307,12 +313,14 @@ def __init__(
presets: Optional[AutoModKeywordPresets] = None,
allow_list: Optional[Sequence[str]] = None,
mention_total_limit: Optional[int] = None,
mention_raid_protection_enabled: Optional[bool] = None,
) -> None:
self.keyword_filter: Optional[Sequence[str]] = keyword_filter
self.regex_patterns: Optional[Sequence[str]] = regex_patterns
self.presets: Optional[AutoModKeywordPresets] = presets
self.allow_list: Optional[Sequence[str]] = allow_list
self.mention_total_limit: Optional[int] = mention_total_limit
self.mention_raid_protection_enabled: Optional[bool] = mention_raid_protection_enabled

def with_changes(
self,
Expand All @@ -322,6 +330,7 @@ def with_changes(
presets: Optional[AutoModKeywordPresets] = MISSING,
allow_list: Optional[Sequence[str]] = MISSING,
mention_total_limit: Optional[int] = MISSING,
mention_raid_protection_enabled: Optional[bool] = MISSING,
) -> Self:
"""
Returns a new instance with the given changes applied.
Expand All @@ -340,6 +349,11 @@ def with_changes(
mention_total_limit=(
self.mention_total_limit if mention_total_limit is MISSING else mention_total_limit
),
mention_raid_protection_enabled=(
self.mention_raid_protection_enabled
if mention_raid_protection_enabled is MISSING
else mention_raid_protection_enabled
),
)

@classmethod
Expand All @@ -355,6 +369,7 @@ def _from_dict(cls, data: AutoModTriggerMetadataPayload) -> Self:
presets=presets,
allow_list=data.get("allow_list"),
mention_total_limit=data.get("mention_total_limit"),
mention_raid_protection_enabled=data.get("mention_raid_protection_enabled"),
)

def to_dict(self) -> AutoModTriggerMetadataPayload:
Expand All @@ -369,6 +384,8 @@ def to_dict(self) -> AutoModTriggerMetadataPayload:
data["allow_list"] = list(self.allow_list)
if self.mention_total_limit is not None:
data["mention_total_limit"] = self.mention_total_limit
if self.mention_raid_protection_enabled is not None:
data["mention_raid_protection_enabled"] = self.mention_raid_protection_enabled
return data

def __repr__(self) -> str:
Expand All @@ -383,6 +400,8 @@ def __repr__(self) -> str:
s += f" allow_list={self.allow_list!r}"
if self.mention_total_limit is not None:
s += f" mention_total_limit={self.mention_total_limit!r}"
if self.mention_raid_protection_enabled is not None:
s += f" mention_raid_protection_enabled={self.mention_raid_protection_enabled!r}"
return f"{s}>"


Expand Down
62 changes: 61 additions & 1 deletion disnake/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ class Guild(Hashable):
- ``PARTNERED``: Guild is a partnered server.
- ``PREVIEW_ENABLED``: Guild can be viewed before being accepted via Membership Screening.
- ``PRIVATE_THREADS``: Guild has access to create private threads (no longer has any effect).
- ``RAID_ALERTS_ENABLED``: Guild has enabled alerts for join raids in the configured safety alerts channel.
- ``ROLE_ICONS``: Guild has access to role icons.
- ``SEVEN_DAY_THREAD_ARCHIVE``: Guild has access to the seven day archive time for threads (no longer has any effect).
- ``TEXT_IN_VOICE_ENABLED``: Guild has text in voice channels enabled (no longer has any effect).
Expand Down Expand Up @@ -329,6 +330,7 @@ class Guild(Hashable):
"_scheduled_events",
"_threads",
"_region",
"_safety_alerts_channel_id",
)

_PREMIUM_GUILD_LIMITS: ClassVar[Dict[Optional[int], _GuildLimit]] = {
Expand Down Expand Up @@ -546,6 +548,9 @@ def _from_data(self, guild: GuildPayload) -> None:
self.widget_enabled: Optional[bool] = guild.get("widget_enabled")
self.widget_channel_id: Optional[int] = utils._get_as_snowflake(guild, "widget_channel_id")
self.vanity_url_code: Optional[str] = guild.get("vanity_url_code")
self._safety_alerts_channel_id: Optional[int] = utils._get_as_snowflake(
guild, "safety_alerts_channel_id"
)

stage_instances = guild.get("stage_instances")
if stage_instances is not None:
Expand Down Expand Up @@ -832,6 +837,19 @@ def public_updates_channel(self) -> Optional[TextChannel]:
channel_id = self._public_updates_channel_id
return channel_id and self._channels.get(channel_id) # type: ignore

@property
def safety_alerts_channel(self) -> Optional[TextChannel]:
"""Optional[:class:`TextChannel`]: Return's the guild's channel where admins and
moderators of the guild receive safety alerts from Discord. The guild must be a
Community guild.

If no channel is set, then this returns ``None``.

.. versionadded:: 2.8
"""
channel_id = self._safety_alerts_channel_id
return channel_id and self._channels.get(channel_id) # type: ignore

@property
def emoji_limit(self) -> int:
""":class:`int`: The maximum number of emoji slots this guild has."""
Expand Down Expand Up @@ -1784,6 +1802,7 @@ async def edit(
discovery_splash: Optional[AssetBytes] = MISSING,
community: bool = MISSING,
invites_disabled: bool = MISSING,
raid_alerts_enabled: bool = MISSING,
afk_channel: Optional[VoiceChannel] = MISSING,
owner: Snowflake = MISSING,
afk_timeout: int = MISSING,
Expand All @@ -1796,6 +1815,7 @@ async def edit(
preferred_locale: Locale = MISSING,
rules_channel: Optional[TextChannel] = MISSING,
public_updates_channel: Optional[TextChannel] = MISSING,
safety_alerts_channel: Optional[TextChannel] = MISSING,
premium_progress_bar_enabled: bool = MISSING,
) -> Guild:
"""
Expand Down Expand Up @@ -1877,6 +1897,16 @@ async def edit(

.. versionadded:: 2.6

raid_alerts_enabled: :class:`bool`
Whether the guild has enabled join raid alerts.

This is only available to guilds that contain ``COMMUNITY``
in :attr:`Guild.features`.

This cannot be changed at the same time as the ``community`` feature due a Discord API limitation.

.. versionadded:: 2.8

afk_channel: Optional[:class:`VoiceChannel`]
The new channel that is the AFK channel. Could be ``None`` for no AFK channel.
afk_timeout: :class:`int`
Expand Down Expand Up @@ -1911,6 +1941,13 @@ async def edit(
The new channel that is used for public updates from Discord. This is only available to
guilds that contain ``COMMUNITY`` in :attr:`Guild.features`. Could be ``None`` for no
public updates channel.
safety_alerts_channel: Optional[:class:`TextChannel`]
The new channel that is used for safety alerts. This is only available to
guilds that contain ``COMMUNITY`` in :attr:`Guild.features`. Could be ``None`` for no
safety alerts channel.

.. versionadded:: 2.8

premium_progress_bar_enabled: :class:`bool`
Whether the server boost progress bar is enabled.
reason: Optional[:class:`str`]
Expand Down Expand Up @@ -2000,6 +2037,12 @@ async def edit(
else:
fields["public_updates_channel_id"] = public_updates_channel.id

if safety_alerts_channel is not MISSING:
if safety_alerts_channel is None:
fields["safety_alerts_channel_id"] = safety_alerts_channel
else:
fields["safety_alerts_channel_id"] = safety_alerts_channel.id

if owner is not MISSING:
if self.owner_id != self._state.self_id:
raise ValueError("To transfer ownership you must be the owner of the guild.")
Expand All @@ -2024,7 +2067,11 @@ async def edit(

fields["system_channel_flags"] = system_channel_flags.value

if community is not MISSING or invites_disabled is not MISSING:
if (
community is not MISSING
or invites_disabled is not MISSING
or raid_alerts_enabled is not MISSING
):
# If we don't have complete feature information for the guild,
# it is possible to disable or enable other features that we didn't intend to touch.
# To enable or disable a feature, we will need to provide all of the existing features in advance.
Expand Down Expand Up @@ -2059,6 +2106,19 @@ async def edit(
else:
features.discard("INVITES_DISABLED")

if raid_alerts_enabled is not MISSING:
if community is not MISSING:
raise ValueError(
"cannot modify both the COMMUNITY feature and RAID_ALERTS_ENABLED feature at the "
"same time due to a discord limitation."
)
if not isinstance(raid_alerts_enabled, bool):
raise TypeError("raid_alerts_enabled must be a bool")
if raid_alerts_enabled:
features.add("RAID_ALERTS_ENABLED")
else:
features.discard("RAID_ALERTS_ENABLED")

fields["features"] = list(features)

if premium_progress_bar_enabled is not MISSING:
Expand Down
1 change: 1 addition & 0 deletions disnake/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1338,6 +1338,7 @@ def edit_guild(
"public_updates_channel_id",
"preferred_locale",
"premium_progress_bar_enabled",
"safety_alerts_channel_id",
)

payload = {k: v for k, v in fields.items() if k in valid_keys}
Expand Down
1 change: 1 addition & 0 deletions disnake/types/automod.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class AutoModTriggerMetadata(TypedDict, total=False):
presets: List[AutoModPresetType]
allow_list: List[str]
mention_total_limit: int
mention_raid_protection_enabled: bool


class AutoModRule(TypedDict):
Expand Down
2 changes: 2 additions & 0 deletions disnake/types/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class UnavailableGuild(TypedDict):
"PREVIEW_ENABLED",
"PRIVATE_THREADS", # deprecated
"RELAY_ENABLED",
"RAID_ALERTS_ENABLED",
"ROLE_ICONS",
"ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE", # not yet documented/finalised
"ROLE_SUBSCRIPTIONS_ENABLED", # not yet documented/finalised
Expand Down Expand Up @@ -126,6 +127,7 @@ class Guild(_BaseGuildPreview):
nsfw_level: NSFWLevel
stickers: NotRequired[List[GuildSticker]]
premium_progress_bar_enabled: bool
safety_alerts_channel_id: Optional[Snowflake]

# specific to GUILD_CREATE event
joined_at: NotRequired[Optional[str]]
Expand Down