From 143539f2994e34e3366b2e0ff3e812dd61d299a2 Mon Sep 17 00:00:00 2001 From: Aamir Farooq Date: Sun, 19 May 2024 18:37:51 +0200 Subject: [PATCH 1/7] Add example config file --- config.example.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 config.example.json diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..60d43dc --- /dev/null +++ b/config.example.json @@ -0,0 +1,33 @@ +{ + "channels": { + "applenews": 123, + "booster_emoji": 123, + "emoji_logs": 123, + "private_logs": 123, + "public_logs": 123, + "bot_commands": 123, + "jailbreak": 123, + "general": 123, + "development": 123, + "genius_bar": 123, + "reports": 123, + "rules": 123, + "common_issues": 123, + "sub_news": 123 + }, + "roles": { + "administrator": 123, + "moderator": 123, + "sub_mod": 123, + "genius": 123, + "developer": 123, + "birthday": 123, + "member_ultra": 123, + "member_one": 123, + "member_edition": 123, + "member_pro": 123, + "member_plus": 123, + "sub_news": 123, + "aaron_role": 123 + } +} \ No newline at end of file From e930e97df5d287255d6b65753bacd81e15a8424e Mon Sep 17 00:00:00 2001 From: Aamir Farooq Date: Sun, 19 May 2024 18:55:38 +0200 Subject: [PATCH 2/7] Add /silent_filter command to mark/unmark commands as silently filtered --- cogs/commands/mod/filter.py | 21 +++++++++++++++++++++ data/model/filterword.py | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cogs/commands/mod/filter.py b/cogs/commands/mod/filter.py index 7e60b7c..8201817 100644 --- a/cogs/commands/mod/filter.py +++ b/cogs/commands/mod/filter.py @@ -1,3 +1,4 @@ +from typing import List import discord from discord import app_commands from data.model import FilterWord @@ -107,6 +108,26 @@ async def _list(self, ctx: GIRContext): menu = Menu(ctx, filters, per_page=12, page_formatter=format_filter_page, whisper=False) await menu.start() + + @mod_and_up() + @app_commands.guilds(cfg.guild_id) + @app_commands.command(description="Silently filter a word (ping mods without removing message)") + @app_commands.describe(word="The word to mark as silently filtered") + @app_commands.autocomplete(word=filterwords_autocomplete) + @transform_context + async def silent_filter(self, ctx: GIRContext, word: str): + word = word.lower() + + words: List[FilterWord] = await guild_service.get_filtered_words() + words = list(filter(lambda w: w.word.lower() == word.lower(), words)) + + if len(words) > 0: + words[0].silent_filter = not words[0].silent_filter + await guild_service.update_filtered_word(words[0]) + + await ctx.send_success("Marked as a silently filtered word!" if words[0].silent_filter else "Removed as a silently filtered word!") + else: + await ctx.send_warning("You must filter that word before it can be marked as silently filtered.", delete_after=5) @mod_and_up() @app_commands.guilds(cfg.guild_id) diff --git a/data/model/filterword.py b/data/model/filterword.py index abb8488..adf540e 100644 --- a/data/model/filterword.py +++ b/data/model/filterword.py @@ -1,8 +1,8 @@ import mongoengine class FilterWord(mongoengine.EmbeddedDocument): - # _id = mongoengine.ObjectIdField(required=True, default=mongoengine.ObjectId., unique=True, primary_key=True) notify = mongoengine.BooleanField(required=True) + silent_filter = mongoengine.BooleanField(default=False) bypass = mongoengine.IntField(required=True) word = mongoengine.StringField(required=True) false_positive = mongoengine.BooleanField(default=False) From 15d655b64fcd72292dee2299a3cbcfc8d4bfd790 Mon Sep 17 00:00:00 2001 From: Aamir Farooq Date: Sun, 19 May 2024 19:19:52 +0200 Subject: [PATCH 3/7] Show silent filtered words in /filter list --- cogs/commands/mod/filter.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cogs/commands/mod/filter.py b/cogs/commands/mod/filter.py index 8201817..1dea3af 100644 --- a/cogs/commands/mod/filter.py +++ b/cogs/commands/mod/filter.py @@ -31,6 +31,12 @@ def format_filter_page(_, entries, current_page, all_pages): embed = discord.Embed( title=f'Filtered words', color=discord.Color.blurple()) for word in entries: + if word.silent_filter: + embed.add_field( + name=word.word, value=f"馃か silent filtered" + ) + continue + notify_flag = "" piracy_flag = "" flags_check = "" From 09cda73aea2e93023ce0cf9564172ebf38620ee8 Mon Sep 17 00:00:00 2001 From: Aamir Farooq Date: Sun, 19 May 2024 19:22:06 +0200 Subject: [PATCH 4/7] Ignore silently words in commands that stop when filter triggered --- cogs/commands/misc/canister.py | 8 +++++--- cogs/commands/misc/memes.py | 6 ++++-- cogs/monitors/misc/songs.py | 3 ++- cogs/monitors/mod/filter.py | 3 +++ utils/framework/filter.py | 7 +++++++ 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cogs/commands/misc/canister.py b/cogs/commands/misc/canister.py index da78962..c0587e2 100644 --- a/cogs/commands/misc/canister.py +++ b/cogs/commands/misc/canister.py @@ -7,6 +7,7 @@ from utils import GIRContext, canister_search_package, cfg, transform_context from utils.fetchers import canister_fetch_repos from utils.framework import gatekeeper, whisper_in_general, find_triggered_filters, find_triggered_raid_phrases +from utils.framework.filter import ignorable_words from utils.views import TweakDropdown, default_repos, repo_autocomplete @@ -22,7 +23,6 @@ async def on_message(self, message): author = message.guild.get_member(message.author.id) if author is None: return - if not gatekeeper.has(message.guild, author, 5) and message.channel.id == cfg.channels.general: return @@ -31,8 +31,10 @@ async def on_message(self, message): if not pattern.match(message.content): return - if await find_triggered_filters(message.content, message.author) or await find_triggered_raid_phrases(message.content, message.author): - return + if filter_words := await find_triggered_filters(message.content, message.author) or await find_triggered_raid_phrases(message.content, message.author): + # if any of the triggered filtered words are not silently filtered, don't show results + if not ignorable_words(filter_words): + return matches = pattern.findall(message.content) if not matches: diff --git a/cogs/commands/misc/memes.py b/cogs/commands/misc/memes.py index f3d00d1..62ab1ab 100644 --- a/cogs/commands/misc/memes.py +++ b/cogs/commands/misc/memes.py @@ -15,6 +15,7 @@ find_triggered_filters, find_triggered_raid_phrases, gatekeeper, memed_and_up, mempro_and_up, mod_and_up, whisper) +from utils.framework.filter import ignorable_words from utils.views import GenericDescriptionModal, Menu, memes_autocomplete @@ -463,8 +464,9 @@ async def aitext(self, ctx: GIRContext, prompt: str): data = await resp.json() text = data.get("choices")[0].get("text") text = discord.utils.escape_markdown(text) - if await find_triggered_filters(text, ctx.author) or await find_triggered_raid_phrases(text, ctx.author): - text = "A filter was triggered by this response. Please try a different prompt." + if filter_words := await find_triggered_filters(text, ctx.author) or await find_triggered_raid_phrases(text, ctx.author): + if not ignorable_words(filter_words): + text = "A filter was triggered by this response. Please try a different prompt." embed = discord.Embed(color=discord.Color.random()) prompt_formatted = discord.utils.escape_markdown(prompt) diff --git a/cogs/monitors/misc/songs.py b/cogs/monitors/misc/songs.py index d6187b1..3f98a90 100644 --- a/cogs/monitors/misc/songs.py +++ b/cogs/monitors/misc/songs.py @@ -10,6 +10,7 @@ from utils import cfg from utils.framework import find_triggered_filters, gatekeeper +from utils.framework.filter import ignorable_words from utils.logging import logger from datetime import timezone @@ -111,7 +112,7 @@ async def generate_view(self, message: discord.Message, link: str): triggered_words = await find_triggered_filters( title, message.author) - if triggered_words: + if triggered_words and not ignorable_words(triggered_words): title = "<:fr:959135064657109012>" view = discord.ui.View() diff --git a/cogs/monitors/mod/filter.py b/cogs/monitors/mod/filter.py index db78da7..b371569 100644 --- a/cogs/monitors/mod/filter.py +++ b/cogs/monitors/mod/filter.py @@ -102,6 +102,9 @@ async def nick_filter(self, member): if not triggered_words: return + if ignorable_words(triggered_words): + return + await member.edit(nick="change name pls") embed = discord.Embed(title="Nickname changed", color=discord.Color.orange()) diff --git a/utils/framework/filter.py b/utils/framework/filter.py index d646fc5..878599e 100644 --- a/utils/framework/filter.py +++ b/utils/framework/filter.py @@ -49,6 +49,13 @@ async def find_triggered_filters(input, member: discord.Member) -> List[FilterWo words_found.append(word) return words_found +def ignorable_words(triggered_filter_words: List[FilterWord]): + """ + We don't want to trigger the filter if the words are silently filtered + return True if all triggered filtered words are silently filtered + """ + return all(filter_word.silent_filter for filter_word in triggered_filter_words) + async def find_triggered_raid_phrases(input, member): symbols = (u"邪斜胁谐写械褢卸蟹懈泄泻谢屑薪芯锌褉褋褌褍褎褏褑褔褕褖褗褘褜褝褞褟袗袘袙袚袛袝衼袞袟袠袡袣袥袦袧袨袩袪小孝校肖啸笑效楔些歇蝎鞋协挟携", From 8e94e0e5b01c1bf8c55ef223398d142e329dafae Mon Sep 17 00:00:00 2001 From: Aamir Farooq Date: Sun, 19 May 2024 19:22:23 +0200 Subject: [PATCH 5/7] For silently filtered words, show a report and don't delete the word --- cogs/monitors/mod/filter.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cogs/monitors/mod/filter.py b/cogs/monitors/mod/filter.py index b371569..772864e 100644 --- a/cogs/monitors/mod/filter.py +++ b/cogs/monitors/mod/filter.py @@ -10,6 +10,7 @@ from discord.ext import commands from utils import cfg, logger, scam_cache from utils.framework import gatekeeper, find_triggered_filters +from utils.framework.filter import ignorable_words from utils.mod import mute from utils.views import manual_report, report @@ -120,8 +121,6 @@ async def bad_word_filter(self, message) -> bool: if not triggered_words: return - dev_role = message.guild.get_role(cfg.roles.developer) - triggered = False for word in triggered_words: if word.piracy: @@ -129,12 +128,19 @@ async def bad_word_filter(self, message) -> bool: if message.channel.id == cfg.roles.developer in message.author.roles: continue - if word.notify: + if word.silent_filter: + # don't delete the word if it's silently filtered, + # just notify the mods + await report(self.bot, message, word.word) + return + elif word.notify: await self.delete(message) await self.ratelimit(message) await self.do_filter_notify(message, word) + if not word.piracy: await report(self.bot, message, word.word) + return triggered = True From 7f96f3bd67666a982aa815cc519f2243ee986332 Mon Sep 17 00:00:00 2001 From: Aamir Farooq Date: Sun, 19 May 2024 20:05:04 +0200 Subject: [PATCH 6/7] Rename `ignorable_words` to `has_only_silent_filtered_words` for clarity --- cogs/commands/misc/canister.py | 4 ++-- cogs/commands/misc/memes.py | 4 ++-- cogs/monitors/misc/songs.py | 4 ++-- cogs/monitors/mod/filter.py | 4 ++-- data/model/filterword.py | 2 +- utils/framework/filter.py | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cogs/commands/misc/canister.py b/cogs/commands/misc/canister.py index c0587e2..e8b7388 100644 --- a/cogs/commands/misc/canister.py +++ b/cogs/commands/misc/canister.py @@ -7,7 +7,7 @@ from utils import GIRContext, canister_search_package, cfg, transform_context from utils.fetchers import canister_fetch_repos from utils.framework import gatekeeper, whisper_in_general, find_triggered_filters, find_triggered_raid_phrases -from utils.framework.filter import ignorable_words +from utils.framework.filter import has_only_silent_filtered_words from utils.views import TweakDropdown, default_repos, repo_autocomplete @@ -33,7 +33,7 @@ async def on_message(self, message): if filter_words := await find_triggered_filters(message.content, message.author) or await find_triggered_raid_phrases(message.content, message.author): # if any of the triggered filtered words are not silently filtered, don't show results - if not ignorable_words(filter_words): + if not has_only_silent_filtered_words(filter_words): return matches = pattern.findall(message.content) diff --git a/cogs/commands/misc/memes.py b/cogs/commands/misc/memes.py index 62ab1ab..7726721 100644 --- a/cogs/commands/misc/memes.py +++ b/cogs/commands/misc/memes.py @@ -15,7 +15,7 @@ find_triggered_filters, find_triggered_raid_phrases, gatekeeper, memed_and_up, mempro_and_up, mod_and_up, whisper) -from utils.framework.filter import ignorable_words +from utils.framework.filter import has_only_silent_filtered_words from utils.views import GenericDescriptionModal, Menu, memes_autocomplete @@ -465,7 +465,7 @@ async def aitext(self, ctx: GIRContext, prompt: str): text = data.get("choices")[0].get("text") text = discord.utils.escape_markdown(text) if filter_words := await find_triggered_filters(text, ctx.author) or await find_triggered_raid_phrases(text, ctx.author): - if not ignorable_words(filter_words): + if not has_only_silent_filtered_words(filter_words): text = "A filter was triggered by this response. Please try a different prompt." embed = discord.Embed(color=discord.Color.random()) diff --git a/cogs/monitors/misc/songs.py b/cogs/monitors/misc/songs.py index 3f98a90..328cd33 100644 --- a/cogs/monitors/misc/songs.py +++ b/cogs/monitors/misc/songs.py @@ -10,7 +10,7 @@ from utils import cfg from utils.framework import find_triggered_filters, gatekeeper -from utils.framework.filter import ignorable_words +from utils.framework.filter import has_only_silent_filtered_words from utils.logging import logger from datetime import timezone @@ -112,7 +112,7 @@ async def generate_view(self, message: discord.Message, link: str): triggered_words = await find_triggered_filters( title, message.author) - if triggered_words and not ignorable_words(triggered_words): + if triggered_words and not has_only_silent_filtered_words(triggered_words): title = "<:fr:959135064657109012>" view = discord.ui.View() diff --git a/cogs/monitors/mod/filter.py b/cogs/monitors/mod/filter.py index 772864e..6dd3d67 100644 --- a/cogs/monitors/mod/filter.py +++ b/cogs/monitors/mod/filter.py @@ -10,7 +10,7 @@ from discord.ext import commands from utils import cfg, logger, scam_cache from utils.framework import gatekeeper, find_triggered_filters -from utils.framework.filter import ignorable_words +from utils.framework.filter import has_only_silent_filtered_words from utils.mod import mute from utils.views import manual_report, report @@ -103,7 +103,7 @@ async def nick_filter(self, member): if not triggered_words: return - if ignorable_words(triggered_words): + if has_only_silent_filtered_words(triggered_words): return await member.edit(nick="change name pls") diff --git a/data/model/filterword.py b/data/model/filterword.py index adf540e..e45af07 100644 --- a/data/model/filterword.py +++ b/data/model/filterword.py @@ -2,7 +2,7 @@ class FilterWord(mongoengine.EmbeddedDocument): notify = mongoengine.BooleanField(required=True) - silent_filter = mongoengine.BooleanField(default=False) + silent_filter = mongoengine.BooleanField(default=False) bypass = mongoengine.IntField(required=True) word = mongoengine.StringField(required=True) false_positive = mongoengine.BooleanField(default=False) diff --git a/utils/framework/filter.py b/utils/framework/filter.py index 878599e..7ed34b9 100644 --- a/utils/framework/filter.py +++ b/utils/framework/filter.py @@ -49,7 +49,7 @@ async def find_triggered_filters(input, member: discord.Member) -> List[FilterWo words_found.append(word) return words_found -def ignorable_words(triggered_filter_words: List[FilterWord]): +def has_only_silent_filtered_words(triggered_filter_words: List[FilterWord]): """ We don't want to trigger the filter if the words are silently filtered return True if all triggered filtered words are silently filtered From a5051ff4853809d843f475774cc90de345476734 Mon Sep 17 00:00:00 2001 From: Aamir Farooq Date: Sun, 19 May 2024 20:06:27 +0200 Subject: [PATCH 7/7] Add missing newline to config example --- config.example.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.example.json b/config.example.json index 60d43dc..38e6bdb 100644 --- a/config.example.json +++ b/config.example.json @@ -30,4 +30,4 @@ "sub_news": 123, "aaron_role": 123 } -} \ No newline at end of file +}