[Filter] Filter based on words for non-phrases (#2262)

Filters based strictly on words (ignoring punctuation) if filter entry isn't a phrase.
This commit is contained in:
Caleb Johnson 2019-02-12 22:14:12 -05:00 committed by Toby Harradine
parent 820be2a0ae
commit ac8b1fc108

View File

@ -1,11 +1,13 @@
import discord import discord
from typing import Union import re
from typing import Union, Set
from redbot.core import checks, Config, modlog, commands from redbot.core import checks, Config, modlog, commands
from redbot.core.bot import Red from redbot.core.bot import Red
from redbot.core.i18n import Translator, cog_i18n from redbot.core.i18n import Translator, cog_i18n
from redbot.core.utils.chat_formatting import pagify from redbot.core.utils.chat_formatting import pagify
RE_WORD_SPLIT = re.compile(r"[^\w]")
_ = Translator("Filter", __file__) _ = Translator("Filter", __file__)
@ -317,17 +319,38 @@ class Filter(commands.Cog):
return removed return removed
async def filter_hits(
self, text: str, server_or_channel: Union[discord.Guild, discord.TextChannel]
) -> Set[str]:
if isinstance(server_or_channel, discord.Guild):
word_list = set(await self.settings.guild(server_or_channel).filter())
elif isinstance(server_or_channel, discord.TextChannel):
word_list = set(
await self.settings.guild(server_or_channel.guild).filter()
+ await self.settings.channel(server_or_channel).filter()
)
else:
raise TypeError("%r should be Guild or TextChannel" % server_or_channel)
content = text.lower()
msg_words = set(RE_WORD_SPLIT.split(content))
filtered_phrases = {x for x in word_list if len(RE_WORD_SPLIT.split(x)) > 1}
filtered_words = word_list - filtered_phrases
hits = {p for p in filtered_phrases if p in content}
hits |= filtered_words & msg_words
return hits
async def check_filter(self, message: discord.Message): async def check_filter(self, message: discord.Message):
server = message.guild server = message.guild
author = message.author author = message.author
word_list = set(
await self.settings.guild(server).filter()
+ await self.settings.channel(message.channel).filter()
)
filter_count = await self.settings.guild(server).filterban_count() filter_count = await self.settings.guild(server).filterban_count()
filter_time = await self.settings.guild(server).filterban_time() filter_time = await self.settings.guild(server).filterban_time()
user_count = await self.settings.member(author).filter_count() user_count = await self.settings.member(author).filter_count()
next_reset_time = await self.settings.member(author).next_reset_time() next_reset_time = await self.settings.member(author).next_reset_time()
if filter_count > 0 and filter_time > 0: if filter_count > 0 and filter_time > 0:
if message.created_at.timestamp() >= next_reset_time: if message.created_at.timestamp() >= next_reset_time:
next_reset_time = message.created_at.timestamp() + filter_time next_reset_time = message.created_at.timestamp() + filter_time
@ -336,36 +359,36 @@ class Filter(commands.Cog):
user_count = 0 user_count = 0
await self.settings.member(author).filter_count.set(user_count) await self.settings.member(author).filter_count.set(user_count)
if word_list: hits = await self.filter_hits(message.content, message.channel)
for w in word_list:
if w in message.content.lower(): if hits:
try: try:
await message.delete() await message.delete()
except discord.HTTPException: except discord.HTTPException:
pass pass
else: else:
if filter_count > 0 and filter_time > 0: if filter_count > 0 and filter_time > 0:
user_count += 1 user_count += 1
await self.settings.member(author).filter_count.set(user_count) await self.settings.member(author).filter_count.set(user_count)
if ( if (
user_count >= filter_count user_count >= filter_count
and message.created_at.timestamp() < next_reset_time and message.created_at.timestamp() < next_reset_time
): ):
reason = _("Autoban (too many filtered messages.)") reason = _("Autoban (too many filtered messages.)")
try: try:
await server.ban(author, reason=reason) await server.ban(author, reason=reason)
except discord.HTTPException: except discord.HTTPException:
pass pass
else: else:
await modlog.create_case( await modlog.create_case(
self.bot, self.bot,
server, server,
message.created_at, message.created_at,
"filterban", "filterban",
author, author,
server.me, server.me,
reason, reason,
) )
async def on_message(self, message: discord.Message): async def on_message(self, message: discord.Message):
if isinstance(message.channel, discord.abc.PrivateChannel): if isinstance(message.channel, discord.abc.PrivateChannel):