Repository: Cog-Creators/Red-DiscordBot

Issue:
Include the ability to log filter hits
# Feature request

<!-- This template is for feature requests. Please fill out the following: -->


#### Select the type of feature you are requesting:

<!-- To check a box, replace the space between the [] with a x -->

- [ ] Cog
- [x] Command
- [ ] API functionality

#### Describe your requested feature

We have a `filterban` casetype, so **within a similar vein** I was wondering if we could get a `filterhit` command - it would allow us to **mark a channel to act as a log** for when someone uses a blacklisted phrase - loosely related, also record it as a modlog case?


Discussion:
100% for this. I built a 3rd party cog for personal use to do this because I liked seeing who's repeatedly getting filtered out or a way to make sure the filter is working properly and not catching false positives.

Would love to see this done for core filter.
+1
While it is easy to make a cog listening for the filter's message delete event, I don't see a reason why it shouldn't just be a part of Filter.
+1
i would 100% love this.

Resolving patch:
diff --git a/redbot/cogs/filter/__init__.py b/redbot/cogs/filter/__init__.py
--- a/redbot/cogs/filter/__init__.py
+++ b/redbot/cogs/filter/__init__.py
@@ -2,5 +2,7 @@
 from redbot.core.bot import Red
 
 
-def setup(bot: Red):
-    bot.add_cog(Filter(bot))
+async def setup(bot: Red) -> None:
+    cog = Filter(bot)
+    await cog.initialize()
+    bot.add_cog(cog)
diff --git a/redbot/cogs/filter/filter.py b/redbot/cogs/filter/filter.py
--- a/redbot/cogs/filter/filter.py
+++ b/redbot/cogs/filter/filter.py
@@ -37,7 +37,6 @@ def __init__(self, bot: Red):
         self.config.register_guild(**default_guild_settings)
         self.config.register_member(**default_member_settings)
         self.config.register_channel(**default_channel_settings)
-        self.register_task = self.bot.loop.create_task(self.register_filterban())
         self.pattern_cache = {}
 
     async def red_delete_data_for_user(
@@ -55,17 +54,27 @@ async def red_delete_data_for_user(
             if user_id in guild_data:
                 await self.config.member_from_ids(guild_id, user_id).clear()
 
-    def cog_unload(self):
-        self.register_task.cancel()
+    async def initialize(self) -> None:
+        await self.register_casetypes()
 
     @staticmethod
-    async def register_filterban():
-        try:
-            await modlog.register_casetype(
-                "filterban", False, ":filing_cabinet: :hammer:", "Filter ban"
-            )
-        except RuntimeError:
-            pass
+    async def register_casetypes() -> None:
+        await modlog.register_casetypes(
+            [
+                {
+                    "name": "filterban",
+                    "default_setting": False,
+                    "image": "\N{FILE CABINET}\N{VARIATION SELECTOR-16} \N{HAMMER}",
+                    "case_str": "Filter ban",
+                },
+                {
+                    "name": "filterhit",
+                    "default_setting": False,
+                    "image": "\N{FILE CABINET}\N{VARIATION SELECTOR-16}",
+                    "case_str": "Filter hit",
+                },
+            ]
+        )
 
     @commands.group()
     @commands.guild_only()
@@ -391,6 +400,20 @@ async def check_filter(self, message: discord.Message):
         hits = await self.filter_hits(message.content, message.channel)
 
         if hits:
+            await modlog.create_case(
+                bot=self.bot,
+                guild=guild,
+                created_at=message.created_at.replace(tzinfo=timezone.utc),
+                action_type="filterhit",
+                user=author,
+                moderator=guild.me,
+                reason=(
+                    _("Filtered words used: {words}").format(words=humanize_list(list(hits)))
+                    if len(hits) > 1
+                    else _("Filtered word used: {word}").format(word=list(hits)[0])
+                ),
+                channel=message.channel,
+            )
             try:
                 await message.delete()
             except discord.HTTPException:
@@ -471,7 +494,6 @@ async def maybe_filter_name(self, member: discord.Member):
         await set_contextual_locales_from_guild(self.bot, guild)
 
         if await self.filter_hits(member.display_name, member.guild):
-
             name_to_use = guild_data["filter_default_name"]
             reason = _("Filtered nickname") if member.nick else _("Filtered name")
             try:


Test patch: