8484from .widget import Widget , WidgetSettings
8585
8686__all__ = (
87+ "IncidentsData" ,
8788 "Guild" ,
8889 "GuildBuilder" ,
8990)
110111 CreateGuildPlaceholderRole ,
111112 Guild as GuildPayload ,
112113 GuildFeature ,
114+ IncidentsData as IncidentsDataPayload ,
113115 MFALevel ,
114116 )
115117 from .types .integration import Integration as IntegrationPayload , IntegrationType
@@ -135,6 +137,94 @@ class _GuildLimit(NamedTuple):
135137 sounds : int
136138
137139
140+ class IncidentsData :
141+ """Represents data about various security incidents/actions in a guild.
142+
143+ .. collapse:: operations
144+
145+ .. describe:: x == y
146+
147+ Checks if two ``IncidentsData`` instances are equal.
148+
149+ .. describe:: x != y
150+
151+ Checks if two ``IncidentsData`` instances are not equal.
152+
153+ .. versionadded:: 2.11
154+
155+ Attributes
156+ ----------
157+ dm_spam_detected_at: Optional[:class:`datetime.datetime`]
158+ The time (in UTC) at which DM spam was last detected.
159+ raid_detected_at: Optional[:class:`datetime.datetime`]
160+ The time (in UTC) at which a raid was last detected.
161+ """
162+
163+ __slots__ = (
164+ "_invites_disabled_until" ,
165+ "_dms_disabled_until" ,
166+ "dm_spam_detected_at" ,
167+ "raid_detected_at" ,
168+ )
169+
170+ def __init__ (self , data : IncidentsDataPayload ) -> None :
171+ self ._invites_disabled_until : Optional [datetime .datetime ] = utils .parse_time (
172+ data .get ("invites_disabled_until" )
173+ )
174+ self ._dms_disabled_until : Optional [datetime .datetime ] = utils .parse_time (
175+ data .get ("dms_disabled_until" )
176+ )
177+ self .dm_spam_detected_at : Optional [datetime .datetime ] = utils .parse_time (
178+ data .get ("dm_spam_detected_at" )
179+ )
180+ self .raid_detected_at : Optional [datetime .datetime ] = utils .parse_time (
181+ data .get ("raid_detected_at" )
182+ )
183+
184+ @property
185+ def invites_disabled_until (self ) -> Optional [datetime .datetime ]:
186+ """Optional[:class:`datetime.datetime`]: Returns the time (in UTC) until
187+ which users cannot join the server via invites, if any.
188+ """
189+ if (
190+ self ._invites_disabled_until is not None
191+ and self ._invites_disabled_until < utils .utcnow ()
192+ ):
193+ self ._invites_disabled_until = None
194+
195+ return self ._invites_disabled_until
196+
197+ @property
198+ def dms_disabled_until (self ) -> Optional [datetime .datetime ]:
199+ """Optional[:class:`datetime.datetime`]: Returns the time (in UTC) until
200+ which members cannot send DMs to each other, if any.
201+
202+ This does not apply to moderators, bots, or members who are
203+ already friends with each other.
204+ """
205+ if self ._dms_disabled_until is not None and self ._dms_disabled_until < utils .utcnow ():
206+ self ._dms_disabled_until = None
207+
208+ return self ._dms_disabled_until
209+
210+ def __eq__ (self , other : Any ) -> bool :
211+ return (
212+ isinstance (other , IncidentsData )
213+ and self .invites_disabled_until == other .invites_disabled_until
214+ and self .dms_disabled_until == other .dms_disabled_until
215+ and self .dm_spam_detected_at == other .dm_spam_detected_at
216+ and self .raid_detected_at == other .raid_detected_at
217+ )
218+
219+ def __repr__ (self ) -> str :
220+ return (
221+ f"<IncidentsData invites_disabled_until={ self .invites_disabled_until !r} "
222+ f" dms_disabled_until={ self .dms_disabled_until !r} "
223+ f" dm_spam_detected_at={ self .dm_spam_detected_at !r} "
224+ f" raid_detected_at={ self .raid_detected_at !r} >"
225+ )
226+
227+
138228class Guild (Hashable ):
139229 """Represents a Discord guild.
140230
@@ -322,6 +412,11 @@ class Guild(Hashable):
322412 To get a full :class:`Invite` object, see :attr:`Guild.vanity_invite`.
323413
324414 .. versionadded:: 2.5
415+
416+ incidents_data: Optional[:class:`IncidentsData`]
417+ Data about various security incidents/actions in this guild, like disabled invites/DMs.
418+
419+ .. versionadded:: 2.11
325420 """
326421
327422 __slots__ = (
@@ -354,6 +449,7 @@ class Guild(Hashable):
354449 "widget_enabled" ,
355450 "widget_channel_id" ,
356451 "vanity_url_code" ,
452+ "incidents_data" ,
357453 "_members" ,
358454 "_channels" ,
359455 "_icon" ,
@@ -600,6 +696,11 @@ def _from_data(self, guild: GuildPayload) -> None:
600696 self ._safety_alerts_channel_id : Optional [int ] = utils ._get_as_snowflake (
601697 guild , "safety_alerts_channel_id"
602698 )
699+ self .incidents_data : Optional [IncidentsData ] = (
700+ IncidentsData (incidents_data )
701+ if (incidents_data := guild .get ("incidents_data" ))
702+ else None
703+ )
603704
604705 stage_instances = guild .get ("stage_instances" )
605706 if stage_instances is not None :
@@ -2040,6 +2141,8 @@ async def edit(
20402141 discovery_splash : Optional [AssetBytes ] = MISSING ,
20412142 community : bool = MISSING ,
20422143 invites_disabled : bool = MISSING ,
2144+ invites_disabled_until : Optional [Union [datetime .datetime , datetime .timedelta ]] = MISSING ,
2145+ dms_disabled_until : Optional [Union [datetime .datetime , datetime .timedelta ]] = MISSING ,
20432146 raid_alerts_disabled : bool = MISSING ,
20442147 afk_channel : Optional [VoiceChannel ] = MISSING ,
20452148 owner : Snowflake = MISSING ,
@@ -2125,7 +2228,8 @@ async def edit(
21252228 Whether the guild should be a Community guild. If set to ``True``\\ , both ``rules_channel``
21262229 and ``public_updates_channel`` parameters are required.
21272230 invites_disabled: :class:`bool`
2128- Whether the guild has paused invites, preventing new users from joining.
2231+ Whether the guild has paused invites (indefinitely), preventing new users from joining.
2232+ See also the ``invites_disabled_until`` parameter.
21292233
21302234 This is only available to guilds that contain ``COMMUNITY``
21312235 in :attr:`Guild.features`.
@@ -2134,6 +2238,28 @@ async def edit(
21342238
21352239 .. versionadded:: 2.6
21362240
2241+ invites_disabled_until: Optional[Union[:class:`datetime.datetime`, :class:`datetime.timedelta`]]
2242+ The time until/for which invites are paused, up to 24 hours in the future.
2243+ See also the ``invites_disabled`` parameter.
2244+ Can be set to ``None`` to re-enable invites.
2245+
2246+ This is only available to guilds that contain ``COMMUNITY``
2247+ in :attr:`Guild.features`.
2248+
2249+ .. versionadded:: 2.11
2250+
2251+ dms_disabled_until: Union[:class:`datetime.datetime`, :class:`datetime.timedelta`]
2252+ The time until/for which DMs between guild members are disabled, up to 24 hours in the future.
2253+ Can be set to ``None`` to re-enable DMs.
2254+
2255+ This does not apply to moderators, bots, or members who are
2256+ already friends with each other.
2257+
2258+ This is only available to guilds that contain ``COMMUNITY``
2259+ in :attr:`Guild.features`.
2260+
2261+ .. versionadded:: 2.11
2262+
21372263 raid_alerts_disabled: :class:`bool`
21382264 Whether the guild has disabled join raid alerts.
21392265
@@ -2220,6 +2346,30 @@ async def edit(
22202346 if vanity_code is not MISSING :
22212347 await http .change_vanity_code (self .id , vanity_code , reason = reason )
22222348
2349+ if invites_disabled_until is not MISSING or dms_disabled_until is not MISSING :
2350+ payload : IncidentsDataPayload = {}
2351+
2352+ # we need to include the old values, otherwise Discord will consider them set to `null`
2353+ # (which would e.g. re-enable DMs when disabling invites)
2354+ if self .incidents_data :
2355+ if invites_disabled_until is MISSING :
2356+ invites_disabled_until = self .incidents_data .invites_disabled_until
2357+ if dms_disabled_until is MISSING :
2358+ dms_disabled_until = self .incidents_data .dms_disabled_until
2359+
2360+ if invites_disabled_until is not MISSING :
2361+ if isinstance (invites_disabled_until , datetime .timedelta ):
2362+ invites_disabled_until = utils .utcnow () + invites_disabled_until
2363+ payload ["invites_disabled_until" ] = utils .isoformat_utc (invites_disabled_until )
2364+
2365+ if dms_disabled_until is not MISSING :
2366+ if isinstance (dms_disabled_until , datetime .timedelta ):
2367+ dms_disabled_until = utils .utcnow () + dms_disabled_until
2368+ payload ["dms_disabled_until" ] = utils .isoformat_utc (dms_disabled_until )
2369+
2370+ if payload :
2371+ await http .edit_guild_incident_actions (self .id , payload )
2372+
22232373 fields : Dict [str , Any ] = {}
22242374 if name is not MISSING :
22252375 fields ["name" ] = name
0 commit comments