aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Joe Banks <[email protected]>2025-06-23 04:49:09 +0100
committerGravatar Joe Banks <[email protected]>2025-06-23 06:52:11 +0100
commit71cf8cee28fff7685459836199a4349ef9cc28dc (patch)
treeec40b9e68fcdd084ec79b0572d08828de09a5d61
parentUpdate information cog test suite to patch get_channel for rules command tests (diff)
Delete automated infraction messages after a period of time
-rw-r--r--bot/exts/moderation/infraction/_scheduler.py72
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.)"