From 79f6df18b3fa590054378aff6cd2cfd6256e8feb Mon Sep 17 00:00:00 2001 From: Soheab_ <33902984+Soheab@users.noreply.github.com> Date: Sat, 27 Jan 2024 02:02:11 +0100 Subject: [PATCH] Add support for guild incidents Co-authored-by: Danny <1695103+Rapptz@users.noreply.github.com> --- discord/guild.py | 85 ++++++++++++++++++++++++++++++++++++++++++ discord/http.py | 3 ++ discord/types/guild.py | 6 +++ 3 files changed, 94 insertions(+) diff --git a/discord/guild.py b/discord/guild.py index cd7c35bc3..830ffbade 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -109,6 +109,7 @@ if TYPE_CHECKING: Guild as GuildPayload, RolePositionUpdate as RolePositionUpdatePayload, UserGuild as UserGuildPayload, + IncidentData, ) from .types.threads import ( Thread as ThreadPayload, @@ -485,6 +486,7 @@ class Guild(Hashable): 'hub_type', '_joined_at', '_cs_joined', + '_incidents_data', ) _PREMIUM_GUILD_LIMITS: ClassVar[Dict[Optional[int], _GuildLimit]] = { @@ -688,6 +690,7 @@ class Guild(Hashable): self.application_id: Optional[int] = utils._get_as_snowflake(guild, 'application_id') self.premium_progress_bar_enabled: bool = guild.get('premium_progress_bar_enabled', False) self._joined_at = guild.get('joined_at') + self._incidents_data: Optional[IncidentData] = guild.get('incidents_data') try: self._large = guild['large'] # type: ignore @@ -2187,6 +2190,8 @@ class Guild(Hashable): widget_enabled: bool = MISSING, widget_channel: Optional[Snowflake] = MISSING, mfa_level: MFALevel = MISSING, + invites_disabled_until: datetime = MISSING, + dms_disabled_until: datetime = MISSING, ) -> Guild: r"""|coro| @@ -2301,6 +2306,18 @@ class Guild(Hashable): reason: Optional[:class:`str`] The reason for editing this guild. Shows up on the audit log. + invites_disabled_until: Optional[:class:`datetime.datetime`] + The time when invites should be enabled again, or ``None`` to disable the action. + This must be a timezone-aware datetime object. Consider using :func:`utils.utcnow`. + + .. versionadded:: 2.4 + + dms_disabled_until: Optional[:class:`datetime.datetime`] + The time when direct messages should be allowed again, or ``None`` to disable the action. + This must be a timezone-aware datetime object. Consider using :func:`utils.utcnow`. + + .. versionadded:: 2.4 + Raises ------- Forbidden @@ -2463,6 +2480,30 @@ class Guild(Hashable): await http.edit_guild_mfa_level(self.id, mfa_level=mfa_level.value) + incident_actions_payload: IncidentData = {} + if invites_disabled_until is not MISSING: + if invites_disabled_until is None: + incident_actions_payload['invites_disabled_until'] = None + else: + if invites_disabled_until.tzinfo is None: + raise TypeError( + 'invites_disabled_until must be an aware datetime. Consider using discord.utils.utcnow() or datetime.datetime.now().astimezone() for local time.' + ) + incident_actions_payload['invites_disabled_until'] = invites_disabled_until.isoformat() + + if dms_disabled_until is not MISSING: + if dms_disabled_until is None: + incident_actions_payload['dms_disabled_until'] = None + else: + if dms_disabled_until.tzinfo is None: + raise TypeError( + 'dms_disabled_until must be an aware datetime. Consider using discord.utils.utcnow() or datetime.datetime.now().astimezone() for local time.' + ) + incident_actions_payload['dms_disabled_until'] = dms_disabled_until.isoformat() + + if incident_actions_payload: + await http.edit_incident_actions(self.id, payload=incident_actions_payload) + data = await http.edit_guild(self.id, reason=reason, **fields) return Guild(data=data, state=self._state) @@ -5423,3 +5464,47 @@ class Guild(Hashable): """ data = await self._state.http.get_directory_broadcast_info(self.id, 1) return data['can_broadcast'] + + @property + def invites_paused_until(self) -> Optional[datetime]: + """Optional[:class:`datetime.datetime`]: If invites are paused, returns when + invites will get enabled in UTC, otherwise returns None. + + .. versionadded:: 2.4 + """ + if not self._incidents_data: + return None + + return utils.parse_time(self._incidents_data.get('invites_disabled_until')) + + @property + def dms_paused_until(self) -> Optional[datetime]: + """Optional[:class:`datetime.datetime`]: If DMs are paused, returns when DMs + will get enabled in UTC, otherwise returns None. + + .. versionadded:: 2.4 + """ + if not self._incidents_data: + return None + + return utils.parse_time(self._incidents_data.get('dms_disabled_until')) + + def invites_paused(self) -> bool: + """:class:`bool`: Whether invites are paused in the guild. + + .. versionadded:: 2.4 + """ + if not self.invites_paused_until: + return False + + return self.invites_paused_until > utils.utcnow() + + def dms_paused(self) -> bool: + """:class:`bool`: Whether DMs are paused in the guild. + + .. versionadded:: 2.4 + """ + if not self.dms_paused_until: + return False + + return self.dms_paused_until > utils.utcnow() diff --git a/discord/http.py b/discord/http.py index 80c5be160..3a598de70 100644 --- a/discord/http.py +++ b/discord/http.py @@ -2299,6 +2299,9 @@ class HTTPClient: Route('PATCH', '/guilds/{guild_id}/welcome-screen', guild_id=guild_id), json=payload, reason=reason ) + def edit_incident_actions(self, guild_id: Snowflake, payload: guild.IncidentData) -> Response[guild.IncidentData]: + return self.request(Route('PUT', '/guilds/{guild_id}/incident-actions', guild_id=guild_id), json=payload) + # Invite management def accept_invite( diff --git a/discord/types/guild.py b/discord/types/guild.py index 3155cc271..02acbea12 100644 --- a/discord/types/guild.py +++ b/discord/types/guild.py @@ -49,6 +49,11 @@ class UnavailableGuild(TypedDict): unavailable: NotRequired[bool] +class IncidentData(TypedDict): + invites_disabled_until: NotRequired[Optional[str]] + dms_disabled_until: NotRequired[Optional[str]] + + DefaultMessageNotificationLevel = Literal[0, 1] ExplicitContentFilterLevel = Literal[0, 1, 2] MFALevel = Literal[0, 1] @@ -127,6 +132,7 @@ class Guild(UnavailableGuild, _GuildMedia): max_video_channel_users: NotRequired[int] # application_command_counts: ApplicationCommandCounts hub_type: Optional[Literal[0, 1, 2]] + incidents_data: Optional[IncidentData] class UserGuild(BaseGuild):