diff options
| -rw-r--r-- | bot/cogs/filtering.py | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py index c57ab0688..eb587d781 100644 --- a/bot/cogs/filtering.py +++ b/bot/cogs/filtering.py @@ -2,10 +2,9 @@ import asyncio import logging import re from datetime import datetime, timedelta -from typing import Optional, Union +from typing import List, Optional, Union import discord.errors -from dateutil import parser from dateutil.relativedelta import relativedelta from discord import Colour, Member, Message, TextChannel from discord.ext.commands import Cog @@ -44,6 +43,8 @@ TOKEN_WATCHLIST_PATTERNS = [ ] WATCHLIST_PATTERNS = WORD_WATCHLIST_PATTERNS + TOKEN_WATCHLIST_PATTERNS +DAYS_BETWEEN_ALERTS = 3 + def expand_spoilers(text: str) -> str: """Return a string containing all interpretations of a spoilered message.""" @@ -120,7 +121,7 @@ class Filtering(Cog): async def on_message(self, msg: Message) -> None: """Invoke message filter for new messages.""" await self._filter_message(msg) - await self.bad_words_in_name(msg) + await self.check_is_bad_words_in_name(msg.author) @Cog.listener() async def on_message_edit(self, before: Message, after: Message) -> None: @@ -135,27 +136,40 @@ class Filtering(Cog): delta = relativedelta(after.edited_at, before.edited_at).microseconds await self._filter_message(after, delta) - async def bad_words_in_name(self, msg: Message) -> None: + @staticmethod + def get_name_matches(name: str) -> List[re.Match]: + """Check bad words from passed string (name). Return list of matches.""" + matches = [] + for pattern in WATCHLIST_PATTERNS: + match = pattern.search(name) + if match: + matches.append(match) + return matches + + async def check_send_alert(self, member: Member) -> bool: + """When there is less than 3 days after last alert, return `False`, otherwise `True`.""" + last_alert = await self.name_alerts.get(member.id) + if last_alert: + last_alert = datetime.fromtimestamp(last_alert) + if datetime.now() - timedelta(days=DAYS_BETWEEN_ALERTS) < last_alert: + return False + + return True + + async def check_is_bad_words_in_name(self, member: Member) -> None: """Check bad words from user display name. When there is more than 3 days after last alert, send new alert.""" # Use lock to avoid race conditions async with self.name_lock: # Check does nickname have match in filters. - matches = [] - for pattern in WATCHLIST_PATTERNS: - match = pattern.search(msg.author.display_name) - if match: - matches.append(match) + matches = self.get_name_matches(member.display_name) if matches: - last_alert = await self.name_alerts.get(msg.author.id) - if last_alert: - last_alert = parser.isoparse(last_alert) - if datetime.now() - timedelta(days=3) < last_alert: - return + if not self.check_send_alert(member): + return log_string = ( - f"**User:** {msg.author.mention} (`{msg.author.id}`)\n" - f"**Display Name:** {msg.author.display_name}\n" + f"**User:** {member.mention} (`{member.id}`)\n" + f"**Display Name:** {member.display_name}\n" f"**Bad Matches:** {', '.join(match.group() for match in matches)}" ) await self.mod_log.send_log_message( @@ -167,7 +181,7 @@ class Filtering(Cog): ) # Update time when alert sent - await self.name_alerts.set(msg.author.id, datetime.now().isoformat()) + await self.name_alerts.set(member.id, datetime.now().timestamp()) async def _filter_message(self, msg: Message, delta: Optional[int] = None) -> None: """Filter the input message to see if it violates any of our rules, and then respond accordingly.""" |