Skip to content

Commit f4d9b03

Browse files
LumabotsPaillat-dev
authored andcommitted
feat: Add support for Guild Incident Actions and Incidents Data parsing (Pycord-Development#2955)
* feat: add incident management functionality to guilds * fix: remove deprecated type checking configuration for basedpyright * style(pre-commit): auto fixes from pre-commit.com hooks * fix: rename incidents attribute to incidents_data to follow api * style(pre-commit): auto fixes from pre-commit.com hooks * Update discord/http.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Lumouille <144063653+Lumabots@users.noreply.github.com> * Update discord/guild.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Lumouille <144063653+Lumabots@users.noreply.github.com> * Update discord/incidents.py Co-authored-by: Soheab <33902984+Soheab@users.noreply.github.com> Signed-off-by: Lumouille <144063653+Lumabots@users.noreply.github.com> * refactor(incidents): simplify datetime parsing using parse_time utility * removal of guild * style(pre-commit): auto fixes from pre-commit.com hooks * Update discord/guild.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Lumouille <144063653+Lumabots@users.noreply.github.com> * fix(incidents): require data parameter in IncidentsData constructor * fix(guild): rename incidents attribute to incidents_data for clarity * Update guild.py Co-authored-by: Soheab <33902984+Soheab@users.noreply.github.com> Signed-off-by: Lumouille <144063653+Lumabots@users.noreply.github.com> --------- Signed-off-by: Lumouille <144063653+Lumabots@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Soheab <33902984+Soheab@users.noreply.github.com> (cherry picked from commit 0ccf2f1)
1 parent 128cfd5 commit f4d9b03

5 files changed

Lines changed: 151 additions & 1 deletion

File tree

discord/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from .flags import *
4848
from .guild import *
4949
from .http import *
50+
from .incidents import *
5051
from .integrations import *
5152
from .interactions import *
5253
from .invite import *

discord/guild.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from __future__ import annotations
2727

2828
import copy
29+
import datetime
2930
import unicodedata
3031
from typing import (
3132
TYPE_CHECKING,
@@ -68,6 +69,7 @@
6869
from .errors import ClientException, InvalidArgument, InvalidData
6970
from .file import File
7071
from .flags import SystemChannelFlags
72+
from .incidents import IncidentsData
7173
from .integrations import Integration, _integration_factory
7274
from .invite import Invite
7375
from .iterators import (
@@ -113,7 +115,11 @@
113115
from .template import Template
114116
from .types.guild import Ban as BanPayload
115117
from .types.guild import Guild as GuildPayload
116-
from .types.guild import GuildFeature, MFALevel
118+
from .types.guild import (
119+
GuildFeature,
120+
MFALevel,
121+
)
122+
from .types.guild import ModifyIncidents as ModifyIncidentsPayload
117123
from .types.member import Member as MemberPayload
118124
from .types.threads import Thread as ThreadPayload
119125
from .types.voice import GuildVoiceState
@@ -289,6 +295,7 @@ class Guild(Hashable):
289295
"approximate_member_count",
290296
"approximate_presence_count",
291297
"_sounds",
298+
"incidents_data",
292299
)
293300

294301
_PREMIUM_GUILD_LIMITS: ClassVar[dict[int | None, _GuildLimit]] = {
@@ -526,6 +533,13 @@ def _from_data(self, guild: GuildPayload) -> None:
526533
sound = SoundboardSound(state=state, http=state.http, data=sound)
527534
self._add_sound(sound)
528535

536+
incidents_payload = guild.get("incidents_data")
537+
self.incidents_data: IncidentsData | None = (
538+
IncidentsData(data=incidents_payload)
539+
if incidents_payload is not None
540+
else None
541+
)
542+
529543
def _add_sound(self, sound: SoundboardSound) -> None:
530544
self._sounds[sound.id] = sound
531545
self._state._add_sound(sound)
@@ -4232,6 +4246,52 @@ async def edit_onboarding(
42324246
new = await self._state.http.edit_onboarding(self.id, fields, reason=reason)
42334247
return Onboarding(data=new, guild=self)
42344248

4249+
async def modify_incident_actions(
4250+
self,
4251+
*,
4252+
invites_disabled_until: datetime.datetime | None = MISSING,
4253+
dms_disabled_until: datetime.datetime | None = MISSING,
4254+
reason: str | None = MISSING,
4255+
) -> IncidentsData:
4256+
"""|coro|
4257+
4258+
Modify the guild's incident actions, controlling when invites or DMs
4259+
are re-enabled after being temporarily disabled. Requires
4260+
the :attr:`~Permissions.manage_guild` permission.
4261+
4262+
Parameters
4263+
----------
4264+
invites_disabled_until: Optional[:class:`datetime.datetime`]
4265+
The ISO8601 timestamp indicating when invites will be enabled again,
4266+
or ``None`` to enable invites immediately.
4267+
dms_disabled_until: Optional[:class:`datetime.datetime`]
4268+
The ISO8601 timestamp indicating when DMs will be enabled again,
4269+
or ``None`` to enable DMs immediately.
4270+
reason: Optional[:class:`str`]
4271+
The reason for this action, used for the audit log.
4272+
4273+
Returns
4274+
-------
4275+
:class:`IncidentsData`
4276+
The updated incidents data for the guild.
4277+
"""
4278+
4279+
fields: ModifyIncidentsPayload = {}
4280+
if invites_disabled_until is not MISSING:
4281+
fields["invites_disabled_until"] = (
4282+
invites_disabled_until and invites_disabled_until.isoformat()
4283+
)
4284+
4285+
if dms_disabled_until is not MISSING:
4286+
fields["dms_disabled_until"] = (
4287+
dms_disabled_until and dms_disabled_until.isoformat()
4288+
)
4289+
4290+
new = await self._state.http.modify_guild_incident_actions(
4291+
self.id, fields, reason=reason
4292+
)
4293+
return IncidentsData(data=new)
4294+
42354295
async def delete_auto_moderation_rule(
42364296
self,
42374297
id: int,

discord/http.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2951,6 +2951,19 @@ def edit_onboarding(
29512951
reason=reason,
29522952
)
29532953

2954+
def modify_guild_incident_actions(
2955+
self,
2956+
guild_id: Snowflake,
2957+
payload: guild.ModifyIncidents,
2958+
*,
2959+
reason: str | None = None,
2960+
) -> Response[guild.IncidentsData]:
2961+
return self.request(
2962+
Route("PUT", "/guilds/{guild_id}/incident-actions", guild_id=guild_id),
2963+
json=payload,
2964+
reason=reason,
2965+
)
2966+
29542967
# Polls
29552968

29562969
def expire_poll(self, channel_id: Snowflake, message_id: Snowflake) -> Response[message.Message]:

discord/incidents.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from __future__ import annotations
2+
3+
import datetime
4+
from typing import TYPE_CHECKING
5+
6+
from .utils import parse_time
7+
8+
if TYPE_CHECKING:
9+
from .types.guild import IncidentsData as IncidentsDataPayload
10+
11+
__all__ = ("IncidentsData",)
12+
13+
14+
class IncidentsData:
15+
"""Represents the incidents data object for a guild.
16+
17+
Attributes
18+
----------
19+
invites_disabled_until: Optional[datetime.datetime]
20+
When invites will be enabled again as a :class:`datetime.datetime`, or ``None``.
21+
dms_disabled_until: Optional[datetime.datetime]
22+
When direct messages will be enabled again as a :class:`datetime.datetime`, or ``None``.
23+
dm_spam_detected_at: Optional[datetime.datetime]
24+
When DM spam was detected, or ``None``.
25+
raid_detected_at: Optional[datetime.datetime]
26+
When a raid was detected, or ``None``.
27+
"""
28+
29+
__slots__ = (
30+
"invites_disabled_until",
31+
"dms_disabled_until",
32+
"dm_spam_detected_at",
33+
"raid_detected_at",
34+
)
35+
36+
def __init__(self, data: IncidentsDataPayload):
37+
self.invites_disabled_until: datetime.datetime | None = parse_time(
38+
data.get("invites_disabled_until")
39+
)
40+
41+
self.dms_disabled_until: datetime.datetime | None = parse_time(
42+
data.get("dms_disabled_until")
43+
)
44+
45+
self.dm_spam_detected_at: datetime.datetime | None = parse_time(
46+
data.get("dm_spam_detected_at")
47+
)
48+
49+
self.raid_detected_at: datetime.datetime | None = parse_time(
50+
data.get("raid_detected_at")
51+
)
52+
53+
def to_dict(self) -> IncidentsDataPayload:
54+
return {
55+
"invites_disabled_until": self.invites_disabled_until
56+
and self.invites_disabled_until.isoformat(),
57+
"dms_disabled_until": self.dms_disabled_until
58+
and self.dms_disabled_until.isoformat(),
59+
"dm_spam_detected_at": self.dm_spam_detected_at
60+
and self.dm_spam_detected_at.isoformat(),
61+
"raid_detected_at": self.raid_detected_at
62+
and self.raid_detected_at.isoformat(),
63+
}

discord/types/guild.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ class Guild(_BaseGuildPreview):
291291
premium_tier: PremiumTier
292292
preferred_locale: str
293293
public_updates_channel_id: Snowflake | None
294+
incidents_data: IncidentsData | None
294295

295296

296297
class InviteGuild(Guild, total=False):
@@ -324,3 +325,15 @@ class GuildMFAModify(TypedDict):
324325
class GuildBulkBan(TypedDict):
325326
banned_users: list[Snowflake]
326327
failed_users: list[Snowflake]
328+
329+
330+
class IncidentsData(TypedDict, total=False):
331+
invites_disabled_until: str | None
332+
dms_disabled_until: str | None
333+
dm_spam_detected_at: str | None
334+
raid_detected_at: str | None
335+
336+
337+
class ModifyIncidents(TypedDict, total=False):
338+
invites_disabled_until: str | None
339+
dms_disabled_until: str | None

0 commit comments

Comments
 (0)