Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
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 discord/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from .flags import *
from .guild import *
from .http import *
from .incidents import *
from .integrations import *
from .interactions import *
from .invite import *
Expand Down
62 changes: 61 additions & 1 deletion discord/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from __future__ import annotations

import copy
import datetime
import unicodedata
from typing import (
TYPE_CHECKING,
Expand Down Expand Up @@ -68,6 +69,7 @@
from .errors import ClientException, InvalidArgument, InvalidData
from .file import File
from .flags import SystemChannelFlags
from .incidents import IncidentsData
from .integrations import Integration, _integration_factory
from .invite import Invite
from .iterators import (
Expand Down Expand Up @@ -112,7 +114,11 @@
from .template import Template
from .types.guild import Ban as BanPayload
from .types.guild import Guild as GuildPayload
from .types.guild import GuildFeature, MFALevel
from .types.guild import (
GuildFeature,
MFALevel,
)
from .types.guild import ModifyIncidents as ModifyIncidentsPayload
from .types.member import Member as MemberPayload
from .types.threads import Thread as ThreadPayload
from .types.voice import GuildVoiceState
Expand Down Expand Up @@ -290,6 +296,7 @@ class Guild(Hashable):
"approximate_member_count",
"approximate_presence_count",
"_sounds",
"incidents",
)

_PREMIUM_GUILD_LIMITS: ClassVar[dict[int | None, _GuildLimit]] = {
Expand Down Expand Up @@ -569,6 +576,13 @@ def _from_data(self, guild: GuildPayload) -> None:
sound = SoundboardSound(state=state, http=state.http, data=sound)
self._add_sound(sound)

incidents_payload = guild.get("incidents_data")
self.incidents_data: IncidentsData | None = (
IncidentsData(data=incidents_payload)
if incidents_payload is not None
else None
)

def _add_sound(self, sound: SoundboardSound) -> None:
self._sounds[sound.id] = sound
self._state._add_sound(sound)
Expand Down Expand Up @@ -4405,6 +4419,52 @@ async def edit_onboarding(
new = await self._state.http.edit_onboarding(self.id, fields, reason=reason)
return Onboarding(data=new, guild=self)

async def modify_incident_actions(
self,
*,
invites_disabled_until: datetime.datetime | None = MISSING,
dms_disabled_until: datetime.datetime | None = MISSING,
reason: str | None = MISSING,
) -> IncidentsData:
"""|coro|

Modify the guild's incident actions, controlling when invites or DMs
are re-enabled after being temporarily disabled. Requires
:attr:`~Permissions.manage_guild`.

Parameters
----------
invites_disabled_until: Optional[:class:`datetime.datetime`]
The ISO8601 timestamp indicating when invites will be enabled again,
or ``None`` to enable invites immediately.
dms_disabled_until: Optional[:class:`datetime.datetime`]
The ISO8601 timestamp indicating when DMs will be enabled again,
or ``None`` to enable DMs immediately.
reason: Optional[:class:`str`]
The reason for this action, used for the audit log.

Returns
-------
:class:`IncidentsData`
The updated incidents data for the guild.
"""

fields: ModifyIncidentsPayload = {}
if invites_disabled_until is not MISSING:
fields["invites_disabled_until"] = (
invites_disabled_until and invites_disabled_until.isoformat()
)

if dms_disabled_until is not MISSING:
fields["dms_disabled_until"] = (
dms_disabled_until and dms_disabled_until.isoformat()
)

new = await self._state.http.modify_guild_incident_actions(
self.id, fields, reason=reason
)
return IncidentsData(data=new)

async def delete_auto_moderation_rule(
self,
id: int,
Expand Down
15 changes: 14 additions & 1 deletion discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
from .file import VoiceMessage
from .gateway import DiscordClientWebSocketResponse
from .soundboard import PartialSoundboardSound, SoundboardSound
from .utils import MISSING, warn_deprecated
from .utils import MISSING

_log = logging.getLogger(__name__)

Expand Down Expand Up @@ -3135,6 +3135,19 @@ def edit_onboarding(
reason=reason,
)

def modify_guild_incident_actions(
self,
guild_id: Snowflake,
payload: guild.ModifyIncidents,
*,
reason: str | None = None,
) -> Response[guild.IncidentsData]:
return self.request(
Route("PUT", "/guilds/{guild_id}/incident-actions", guild_id=guild_id),
json=payload,
reason=reason,
)

# Polls

def expire_poll(
Expand Down
63 changes: 63 additions & 0 deletions discord/incidents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from __future__ import annotations

import datetime
from typing import TYPE_CHECKING

from .utils import parse_time

if TYPE_CHECKING:
from .types.guild import IncidentsData as IncidentsDataPayload

__all__ = ("IncidentsData",)


class IncidentsData:
"""Represents the incidents data object for a guild.

Attributes
----------
invites_disabled_until: Optional[datetime.datetime]
When invites will be enabled again as a :class:`datetime.datetime`, or ``None``.
dms_disabled_until: Optional[datetime.datetime]
When direct messages will be enabled again as a :class:`datetime.datetime`, or ``None``.
dm_spam_detected_at: Optional[datetime.datetime]
When DM spam was detected, or ``None``.
raid_detected_at: Optional[datetime.datetime]
When a raid was detected, or ``None``.
"""

__slots__ = (
"invites_disabled_until",
"dms_disabled_until",
"dm_spam_detected_at",
"raid_detected_at",
)

def __init__(self, data: IncidentsDataPayload):
self.invites_disabled_until: datetime.datetime | None = parse_time(
data.get("invites_disabled_until")
)

self.dms_disabled_until: datetime.datetime | None = parse_time(
data.get("dms_disabled_until")
)

self.dm_spam_detected_at: datetime.datetime | None = parse_time(
data.get("dm_spam_detected_at")
)

self.raid_detected_at: datetime.datetime | None = parse_time(
data.get("raid_detected_at")
)

def to_dict(self) -> IncidentsDataPayload:
return {
"invites_disabled_until": self.invites_disabled_until
and self.invites_disabled_until.isoformat(),
"dms_disabled_until": self.dms_disabled_until
and self.dms_disabled_until.isoformat(),
"dm_spam_detected_at": self.dm_spam_detected_at
and self.dm_spam_detected_at.isoformat(),
"raid_detected_at": self.raid_detected_at
and self.raid_detected_at.isoformat(),
}
13 changes: 13 additions & 0 deletions discord/types/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ class Guild(_BaseGuildPreview):
premium_tier: PremiumTier
preferred_locale: str
public_updates_channel_id: Snowflake | None
incidents_data: IncidentsData | None


class InviteGuild(Guild, total=False):
Expand Down Expand Up @@ -197,3 +198,15 @@ class GuildMFAModify(TypedDict):
class GuildBulkBan(TypedDict):
banned_users: list[Snowflake]
failed_users: list[Snowflake]


class IncidentsData(TypedDict, total=False):
invites_disabled_until: str | None
dms_disabled_until: str | None
dm_spam_detected_at: str | None
raid_detected_at: str | None


class ModifyIncidents(TypedDict, total=False):
invites_disabled_until: str | None
dms_disabled_until: str | None