diff options
-rw-r--r-- | bot/exts/moderation/infraction/_scheduler.py | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/bot/exts/moderation/infraction/_scheduler.py b/bot/exts/moderation/infraction/_scheduler.py index 9abf3305b..7610ec04c 100644 --- a/bot/exts/moderation/infraction/_scheduler.py +++ b/bot/exts/moderation/infraction/_scheduler.py @@ -2,14 +2,17 @@ import textwrap import typing as t from abc import abstractmethod from collections.abc import Awaitable, Callable +from datetime import UTC, datetime, timedelta from gettext import ngettext import arrow import dateutil.parser import discord +from async_rediscache import RedisCache from discord.ext.commands import Context from pydis_core.site_api import ResponseCodeError from pydis_core.utils import scheduling +from pydis_core.utils.channel import get_or_fetch_channel from bot import constants from bot.bot import Bot @@ -24,18 +27,26 @@ from bot.utils.modlog import send_log_message log = get_logger(__name__) +AUTOMATED_TIDY_UP_HOURS = 8 + class InfractionScheduler: """Handles the application, pardoning, and expiration of infractions.""" + messages_to_tidy: RedisCache = RedisCache() + def __init__(self, bot: Bot, supported_infractions: t.Container[str]): self.bot = bot self.scheduler = scheduling.Scheduler(self.__class__.__name__) + self.tidy_up_scheduler = scheduling.Scheduler( + f"{self.__class__.__name__}TidyUp" + ) self.supported_infractions = supported_infractions async def cog_unload(self) -> None: """Cancel scheduled tasks.""" self.scheduler.cancel_all() + self.tidy_up_scheduler.cancel_all() @property def mod_log(self) -> ModLog: @@ -76,7 +87,46 @@ class InfractionScheduler: self.scheduler.schedule_at(next_reschedule_point, -1, self.cog_load()) - log.trace("Done rescheduling") + log.trace("Done rescheduling expirations, scheduling tidy up tasks.") + + for key, expire_at in await self.messages_to_tidy.items(): + channel_id, message_id = map(int, key.split(":")) + expire_at = dateutil.parser.isoparse(expire_at) + + log.trace( + "Scheduling tidy up for message %s in channel %s at %s", + message_id, channel_id, expire_at + ) + + self.tidy_up_scheduler.schedule_at( + expire_at, + message_id, + self._delete_infraction_message(channel_id, message_id) + ) + + async def _delete_infraction_message( + self, + channel_id: int, + message_id: int + ) -> None: + """ + Delete a message in the given channel. + + This is used to delete infraction messages after a certain period of time. + """ + channel = await get_or_fetch_channel(self.bot, channel_id) + if channel is None: + log.warning(f"Channel {channel_id} not found for infraction message deletion.") + return + + try: + message = await channel.fetch_message(message_id) + await message.delete() + log.trace(f"Deleted infraction message {message_id} in channel {channel_id}.") + except discord.NotFound: + log.warning(f"Message {message_id} not found in channel {channel_id}.") + + await self.messages_to_tidy.delete(f"{channel_id}:{message_id}") async def reapply_infraction( self, @@ -269,7 +319,25 @@ class InfractionScheduler: # Send a confirmation message to the invoking context. log.trace(f"Sending infraction #{id_} confirmation message.") mentions = discord.AllowedMentions(users=[user], roles=False) - await ctx.send(f"{dm_result}{confirm_msg}{infr_message}.", allowed_mentions=mentions) + sent_msg = await ctx.send(f"{dm_result}{confirm_msg}{infr_message}.", allowed_mentions=mentions) + + if infraction["actor"] == self.bot.user.id: + expire_message_time = datetime.now(UTC) + timedelta(hours=AUTOMATED_TIDY_UP_HOURS) + + log.trace(f"Scheduling message tidy for infraction #{id_} in {AUTOMATED_TIDY_UP_HOURS} hours.") + + # Schedule the message to be deleted after a certain period of time. + self.tidy_up_scheduler.schedule_at( + expire_message_time, + sent_msg.id, + self._delete_infraction_message(ctx.channel.id, sent_msg.id) + ) + + # Persist to Redis to handle for bot restarts. + await self.messages_to_tidy.set( + f"{ctx.channel.id}:{sent_msg.id}", + expire_message_time.isoformat(), + ) if jump_url is None: jump_url = "(Infraction issued in a ModMail channel.)" |