aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/filtering.py85
-rw-r--r--bot/constants.py1
-rw-r--r--config-default.yml3
3 files changed, 80 insertions, 9 deletions
diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py
index 4ebc831e1..76ea68660 100644
--- a/bot/cogs/filtering.py
+++ b/bot/cogs/filtering.py
@@ -2,11 +2,12 @@ import asyncio
import logging
import re
from datetime import datetime, timedelta
-from typing import List, Optional, Union
+from typing import List, Mapping, Optional, Union
+import dateutil
import discord.errors
from dateutil.relativedelta import relativedelta
-from discord import Colour, Member, Message, TextChannel
+from discord import Colour, HTTPException, Member, Message, NotFound, TextChannel
from discord.ext.commands import Cog
from discord.utils import escape_markdown
@@ -17,6 +18,8 @@ from bot.constants import (
Filter, Icons, URLs
)
from bot.utils.redis_cache import RedisCache
+from bot.utils.scheduling import Scheduler
+from bot.utils.time import wait_until
log = logging.getLogger(__name__)
@@ -54,7 +57,10 @@ def expand_spoilers(text: str) -> str:
)
-class Filtering(Cog):
+OFFENSIVE_MSG_DELETE_TIME = timedelta(days=Filter.offensive_msg_delete_days)
+
+
+class Filtering(Cog, Scheduler):
"""Filtering out invites, blacklisting domains, and warning us of certain regular expressions."""
# Redis cache mapping a user ID to the last timestamp a bad nickname alert was sent
@@ -62,6 +68,8 @@ class Filtering(Cog):
def __init__(self, bot: Bot):
self.bot = bot
+ super().__init__()
+
self.name_lock = asyncio.Lock()
staff_mistake_str = "If you believe this was a mistake, please let staff know!"
@@ -75,7 +83,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,
@@ -86,7 +95,8 @@ class Filtering(Cog):
"notification_msg": (
f"Per Rule 6, 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,
@@ -96,22 +106,27 @@ 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_regex": {
"enabled": Filter.watch_regex,
"function": self._has_watch_regex_match,
"type": "watchlist",
"content_only": True,
+ "schedule_deletion": True
},
"watch_rich_embeds": {
"enabled": Filter.watch_rich_embeds,
"function": self._has_rich_embed,
"type": "watchlist",
"content_only": False,
- },
+ "schedule_deletion": False
+ }
}
+ self.bot.loop.create_task(self.reschedule_offensive_msg_deletion())
+
@property
def mod_log(self) -> ModLog:
"""Get currently loaded ModLog cog instance."""
@@ -242,6 +257,20 @@ class Filtering(Cog):
if _filter["user_notification"]:
await self.notify_member(msg.author, _filter["notification_msg"], msg.channel)
+ # 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"] and not is_private:
+ delete_date = (msg.created_at + OFFENSIVE_MSG_DELETE_TIME).isoformat()
+ data = {
+ 'id': msg.id,
+ 'channel_id': msg.channel.id,
+ 'delete_date': delete_date
+ }
+
+ await self.bot.api_client.post('bot/offensive-messages', json=data)
+ self.schedule_task(msg.id, data)
+ log.trace(f"Offensive message {msg.id} will be deleted on {delete_date}")
+
if is_private:
channel_str = "via DM"
else:
@@ -359,7 +388,7 @@ class Filtering(Cog):
Attempts to catch some of common ways to try to cheat the system.
"""
- # Remove backslashes to prevent escape character aroundfuckery like
+ # Remove backslashes to prevent escape character around fuckery like
# discord\.gg/gdudes-pony-farm
text = text.replace("\\", "")
@@ -428,6 +457,46 @@ class Filtering(Cog):
except discord.errors.Forbidden:
await channel.send(f"{filtered_member.mention} {reason}")
+ async def _scheduled_task(self, msg: dict) -> None:
+ """Delete an offensive message once its deletion date is reached."""
+ delete_at = dateutil.parser.isoparse(msg['delete_date']).replace(tzinfo=None)
+
+ await wait_until(delete_at)
+ await self.delete_offensive_msg(msg)
+
+ 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-messages',)
+
+ now = datetime.utcnow()
+
+ for msg in response:
+ delete_at = dateutil.parser.isoparse(msg['delete_date']).replace(tzinfo=None)
+
+ if delete_at < now:
+ await self.delete_offensive_msg(msg)
+ else:
+ self.schedule_task(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)."
+ )
+ 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 setup(bot: Bot) -> None:
"""Load the Filtering cog."""
diff --git a/bot/constants.py b/bot/constants.py
index 470221369..a1b392c82 100644
--- a/bot/constants.py
+++ b/bot/constants.py
@@ -226,6 +226,7 @@ class Filter(metaclass=YAMLGetter):
notify_user_domains: bool
ping_everyone: bool
+ offensive_msg_delete_days: 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 f111c64f5..64c4e715b 100644
--- a/config-default.yml
+++ b/config-default.yml
@@ -269,7 +269,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_days: 7 # How many days before deleting an offensive message?
guild_invite_whitelist:
- 280033776820813825 # Functional Programming