aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar mbaruh <[email protected]>2022-11-25 23:43:03 +0200
committerGravatar mbaruh <[email protected]>2022-11-25 23:43:03 +0200
commit7591c5e58d97d264505302c984acca32da143fc7 (patch)
tree8bb5f4fc7672bd49d334a95e97afe6047a3de8e9
parentAdd nickname filter (diff)
Add offending message deletion scheduling
This is mostly a copy-paste from the old system. If there are any actions taken against the message, but deleting is not one of them - schedule the message for deletion after 7 days.
-rw-r--r--bot/exts/filtering/filtering.py77
1 files changed, 72 insertions, 5 deletions
diff --git a/bot/exts/filtering/filtering.py b/bot/exts/filtering/filtering.py
index 9c9b1eff4..65089a6d5 100644
--- a/bot/exts/filtering/filtering.py
+++ b/bot/exts/filtering/filtering.py
@@ -4,7 +4,7 @@ import operator
import re
import unicodedata
from collections import defaultdict
-from collections.abc import Iterable
+from collections.abc import Iterable, Mapping
from functools import partial, reduce
from io import BytesIO
from operator import attrgetter
@@ -14,6 +14,7 @@ import arrow
import discord
from async_rediscache import RedisCache
from botcore.site_api import ResponseCodeError
+from botcore.utils import scheduling
from discord import Colour, Embed, HTTPException, Message, MessageType
from discord.ext import commands, tasks
from discord.ext.commands import BadArgument, Cog, Context, command, has_any_role
@@ -48,6 +49,7 @@ log = get_logger(__name__)
CACHE_SIZE = 100
HOURS_BETWEEN_NICKNAME_ALERTS = 1
+OFFENSIVE_MSG_DELETE_TIME = datetime.timedelta(days=7)
WEEKLY_REPORT_ISO_DAY = 3 # 1=Monday, 7=Sunday
@@ -66,6 +68,7 @@ class Filtering(Cog):
self.bot = bot
self.filter_lists: dict[str, FilterList] = {}
self._subscriptions: defaultdict[Event, list[FilterList]] = defaultdict(list)
+ self.delete_scheduler = scheduling.Scheduler(self.__class__.__name__)
self.webhook = None
self.loaded_settings = {}
@@ -95,6 +98,7 @@ class Filtering(Cog):
log.error(f"Failed to fetch filters webhook with ID `{Webhooks.filters}`.")
self.collect_loaded_types(example_list)
+ await self.schedule_offending_messages_deletion()
self.weekly_auto_infraction_report_task.start()
def subscribe(self, filter_list: FilterList, *events: Event) -> None:
@@ -175,6 +179,18 @@ class Filtering(Cog):
for field_name in extra_fields_type.__fields__
}
+ async def schedule_offending_messages_deletion(self) -> None:
+ """Load the messages that need to be scheduled for deletion from the database."""
+ response = await self.bot.api_client.get('bot/offensive-messages')
+
+ now = arrow.utcnow()
+ for msg in response:
+ delete_at = arrow.get(msg['delete_date'])
+ if delete_at < now:
+ await self._delete_offensive_msg(msg)
+ else:
+ self._schedule_msg_delete(msg)
+
async def cog_check(self, ctx: Context) -> bool:
"""Only allow moderators to invoke the commands in this cog."""
return await has_any_role(*MODERATION_ROLES).predicate(ctx)
@@ -197,9 +213,11 @@ class Filtering(Cog):
if ctx.send_alert:
await self._send_alert(ctx, list_messages)
- ctx = FilterContext.from_message(Event.NICKNAME, msg)
- ctx.content = msg.author.display_name
- await self._check_bad_name(ctx)
+ nick_ctx = FilterContext.from_message(Event.NICKNAME, msg)
+ nick_ctx.content = msg.author.display_name
+ await self._check_bad_name(nick_ctx)
+
+ await self._maybe_schedule_msg_delete(ctx, result_actions)
@Cog.listener()
async def on_message_edit(self, before: discord.Message, after: discord.Message) -> None:
@@ -221,6 +239,7 @@ class Filtering(Cog):
await result_actions.action(ctx)
if ctx.send_alert:
await self._send_alert(ctx, list_messages)
+ await self._maybe_schedule_msg_delete(ctx, result_actions)
@Cog.listener()
async def on_voice_state_update(self, member: discord.Member, *_) -> None:
@@ -1187,6 +1206,53 @@ class Filtering(Cog):
ctx = await bot.instance.get_context(message)
await LinePaginator.paginate(lines, ctx, embed, max_lines=15, empty=False, reply=True)
+ async def _delete_offensive_msg(self, msg: Mapping[str, int]) -> None:
+ """Delete an offensive message, and then delete it from the DB."""
+ try:
+ channel = self.bot.get_channel(msg['channel_id'])
+ if channel:
+ msg_obj = await channel.fetch_message(msg['id'])
+ await msg_obj.delete()
+ except discord.NotFound:
+ log.info(
+ f"Tried to delete message {msg['id']}, but the message can't be found "
+ f"(it has been probably already deleted)."
+ )
+ except HTTPException as e:
+ log.warning(f"Failed to delete message {msg['id']}: status {e.status}")
+
+ await self.bot.api_client.delete(f'bot/offensive-messages/{msg["id"]}')
+ log.info(f"Deleted the offensive message with id {msg['id']}.")
+
+ def _schedule_msg_delete(self, msg: dict) -> None:
+ """Delete an offensive message once its deletion date is reached."""
+ delete_at = arrow.get(msg['delete_date']).datetime
+ self.delete_scheduler.schedule_at(delete_at, msg['id'], self._delete_offensive_msg(msg))
+
+ async def _maybe_schedule_msg_delete(self, ctx: FilterContext, actions: ActionSettings | None) -> None:
+ """Post the message to the database and schedule it for deletion if it's not set to be deleted already."""
+ msg = ctx.message
+ if not msg or not actions or actions.get_setting("remove_context", True):
+ return
+
+ delete_date = (msg.created_at + OFFENSIVE_MSG_DELETE_TIME).isoformat()
+ data = {
+ 'id': msg.id,
+ 'channel_id': msg.channel.id,
+ 'delete_date': delete_date
+ }
+
+ try:
+ await self.bot.api_client.post('bot/offensive-messages', json=data)
+ except ResponseCodeError as e:
+ if e.status == 400 and "already exists" in e.response_json.get("id", [""])[0]:
+ log.debug(f"Offensive message {msg.id} already exists.")
+ else:
+ log.error(f"Offensive message {msg.id} failed to post: {e}")
+ else:
+ self._schedule_msg_delete(data)
+ log.trace(f"Offensive message {msg.id} will be deleted on {delete_date}")
+
# endregion
# region: tasks
@@ -1242,8 +1308,9 @@ class Filtering(Cog):
# endregion
async def cog_unload(self) -> None:
- """Cancel the weekly auto-infraction filter report on cog unload."""
+ """Cancel the weekly auto-infraction filter report and deletion scheduling on cog unload."""
self.weekly_auto_infraction_report_task.cancel()
+ self.delete_scheduler.cancel_all()
async def setup(bot: Bot) -> None: