diff options
| -rw-r--r-- | bot/cogs/filtering.py | 83 | ||||
| -rw-r--r-- | bot/constants.py | 1 | ||||
| -rw-r--r-- | config-default.yml | 3 |
3 files changed, 80 insertions, 7 deletions
diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py index be9b95bc7..5bd72a584 100644 --- a/bot/cogs/filtering.py +++ b/bot/cogs/filtering.py @@ -1,10 +1,12 @@ +import asyncio +import datetime import logging import re -from typing import Optional, Union +from typing import Mapping, Optional, Union import discord.errors from dateutil.relativedelta import relativedelta -from discord import Colour, DMChannel, Member, Message, TextChannel +from discord import Colour, DMChannel, Member, Message, NotFound, TextChannel from discord.ext.commands import Bot, Cog from bot.cogs.moderation import ModLog @@ -12,6 +14,8 @@ from bot.constants import ( Channels, Colours, Filter, Icons, URLs ) +from bot.utils.scheduling import Scheduler +from bot.utils.time import wait_until log = logging.getLogger(__name__) @@ -36,12 +40,15 @@ TOKEN_WATCHLIST_PATTERNS = [ re.compile(fr'{expression}', flags=re.IGNORECASE) for expression in Filter.token_watchlist ] +OFFENSIVE_MSG_DELETE_TIME = datetime.timedelta(days=Filter.offensive_msg_delete_time) -class Filtering(Cog): + +class Filtering(Cog, Scheduler): """Filtering out invites, blacklisting domains, and warning us of certain regular expressions.""" def __init__(self, bot: Bot): self.bot = bot + super().__init__() _staff_mistake_str = "If you believe this was a mistake, please let staff know!" self.filters = { @@ -54,7 +61,8 @@ class Filtering(Cog): "notification_msg": ( "Your post has been removed for abusing Unicode character rendering (aka Zalgo text). " f"{_staff_mistake_str}" - ) + ), + "schedule_deletion": False }, "filter_invites": { "enabled": Filter.filter_invites, @@ -65,7 +73,8 @@ class Filtering(Cog): "notification_msg": ( f"Per Rule 10, your invite link has been removed. {_staff_mistake_str}\n\n" r"Our server rules can be found here: <https://pythondiscord.com/pages/rules>" - ) + ), + "schedule_deletion": False }, "filter_domains": { "enabled": Filter.filter_domains, @@ -75,28 +84,35 @@ class Filtering(Cog): "user_notification": Filter.notify_user_domains, "notification_msg": ( f"Your URL has been removed because it matched a blacklisted domain. {_staff_mistake_str}" - ) + ), + "schedule_deletion": False }, "watch_rich_embeds": { "enabled": Filter.watch_rich_embeds, "function": self._has_rich_embed, "type": "watchlist", "content_only": False, + "schedule_deletion": False }, "watch_words": { "enabled": Filter.watch_words, "function": self._has_watchlist_words, "type": "watchlist", "content_only": True, + "schedule_deletion": True }, "watch_tokens": { "enabled": Filter.watch_tokens, "function": self._has_watchlist_tokens, "type": "watchlist", "content_only": True, + "schedule_deletion": True }, } + self.deletion_task = None + self.bot.loop.create_task(self.reschedule_offensive_msg_deletion()) + @property def mod_log(self) -> ModLog: """Get currently loaded ModLog cog instance.""" @@ -171,6 +187,21 @@ class Filtering(Cog): except discord.errors.NotFound: return + # If the message is classed as offensive, we store it in the site db and + # it will be deleted it after one week. + if _filter["schedule_deletion"]: + delete_date = msg.created_at.date() + OFFENSIVE_MSG_DELETE_TIME + await self.bot.api_client.post( + 'bot/offensive-message', + json={ + 'id': msg.id, + 'channel_id': msg.channel.id, + 'delete_date': delete_date.isoformat() + } + ) + log.trace(f"Offensive message will be deleted on " + f"{delete_date.isoformat()}") + # Notify the user if the filter specifies if _filter["user_notification"]: await self.notify_member(msg.author, _filter["notification_msg"], msg.channel) @@ -368,6 +399,46 @@ class Filtering(Cog): except discord.errors.Forbidden: await channel.send(f"{filtered_member.mention} {reason}") + async def _scheduled_task(self, msg: dict) -> None: + """A coroutine which delete the offensive message once the delete date is reached.""" + delete_at = datetime.datetime.fromisoformat(msg['delete_date'][:-1]) + + await wait_until(delete_at) + await self.delete_offensive_msg(msg) + + self.cancel_task(msg['id']) + + async def reschedule_offensive_msg_deletion(self) -> None: + """Get all the pending message deletion from the API and reschedule them.""" + await self.bot.wait_until_ready() + response = await self.bot.api_client.get( + 'bot/offensive-message', + ) + + now = datetime.datetime.utcnow() + loop = asyncio.get_event_loop() + + for msg in response: + delete_at = datetime.datetime.fromisoformat(msg['delete_date'][:-1]) + + if delete_at < now: + await self.delete_offensive_msg(msg) + else: + self.schedule_task(loop, msg['id'], msg) + + async def delete_offensive_msg(self, msg: Mapping[str, str]) -> 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 NotFound: + log.info(f"Tried to delete message {msg['id']}, but the message can't be found " + f"(it has been probably already deleted).") + await self.bot.api_client.delete(f'bot/offensive-message/{msg["id"]}') + log.info(f"Deleted the offensive message with id {msg['id']}.") + def setup(bot: Bot) -> None: """Filtering cog load.""" diff --git a/bot/constants.py b/bot/constants.py index 838fe7a79..fd95712e7 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -211,6 +211,7 @@ class Filter(metaclass=YAMLGetter): notify_user_domains: bool ping_everyone: bool + offensive_msg_delete_time: int guild_invite_whitelist: List[int] domain_blacklist: List[str] word_watchlist: List[str] diff --git a/config-default.yml b/config-default.yml index 4638a89ee..98638a3e1 100644 --- a/config-default.yml +++ b/config-default.yml @@ -167,7 +167,8 @@ filter: notify_user_domains: false # Filter configuration - ping_everyone: true # Ping @everyone when we send a mod-alert? + ping_everyone: true # Ping @everyone when we send a mod-alert? + offensive_msg_delete_time: 7 # How many days before deleting an offensive message? guild_invite_whitelist: - 280033776820813825 # Functional Programming |