From 018dfbb6f9f63cde971ce02d168fa82248b2137e Mon Sep 17 00:00:00 2001 From: lunazeta <70282650+lunazeta@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:19:18 +0000 Subject: [PATCH 1/5] Added bot_moderation cog --- apollo.py | 1 + cogs/bot_moderation.py | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 cogs/bot_moderation.py diff --git a/apollo.py b/apollo.py index 93b5af95..c0ee7a66 100644 --- a/apollo.py +++ b/apollo.py @@ -51,6 +51,7 @@ "cogs.commands.xkcd", "cogs.commands.market", "cogs.commands.auction", + "cogs.bot_moderation", "cogs.channel_checker", "cogs.database", "cogs.irc", diff --git a/cogs/bot_moderation.py b/cogs/bot_moderation.py new file mode 100644 index 00000000..cd5dd554 --- /dev/null +++ b/cogs/bot_moderation.py @@ -0,0 +1,50 @@ +import asyncio +import difflib + +from datetime import datetime, timedelta + +import discord +from discord import Embed, Color +from discord.ext.commands import Bot, Cog + +from config import CONFIG + +async def not_in_blacklisted_channel(ctx: Context): + return ( + await is_compsoc_exec_in_guild(ctx) + or db_session.query(IgnoredChannel) + .filter(IgnoredChannel.channel == ctx.channel.id) + .first() + is None + ) + +class Database(Cog): + def __init__(self, bot: Bot): + self.bot = bot + # Set up a global check that we're not in a blacklisted channel + self.bot.add_check(not_in_blacklisted_channel) + + @Cog.listener() + async def on_message(self, message: discord.Message): + joined_recently = message.author.joined_at > datetime.now() - timedelta(days=7) + contains_everyone = '@everyone' in message.content + is_giving_away = 'giving away' in message.content.lower() + + if not joined_recently or not (contains_everyone or is_giving_away): + break + + channel = self.bot.get_channel(CONFIG.UWCS_MESSAGE_LOG_CHANNEL_ID) + + embed_colour = Color.from_rgb(61, 83, 255) + embed_title = f'@{message.author.global_name}, ID: {message.author.id}' + embed_description = f'User suspected to be a bot, joined_recently: {joined_recently}, contains_everyone: {contains_everyone}, is_giving_away: {is_giving_away}' + embed = discord.Embed( + title=embed_title, color=embed_colour, embed_description=embed_description + ) + + await message.delete() + await channel.send(f'<@&{CONFIG.UWCS_EXEC_ROLE_IDS[1]}>', embed=embed) + await message.author.timeout(timedelta(days=1)) + +async def setup(bot: Bot): + await bot.add_cog(Database(bot)) \ No newline at end of file From ad5948633884c9a1b8086a391f169b1a6c196909 Mon Sep 17 00:00:00 2001 From: lunazeta <70282650+lunazeta@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:19:38 +0000 Subject: [PATCH 2/5] Updated config to reflect changes --- config.example.yaml | 2 ++ config/config.py | 1 + 2 files changed, 3 insertions(+) diff --git a/config.example.yaml b/config.example.yaml index 9b2e9060..3a87df47 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -20,6 +20,8 @@ config: UWCS_roles_channel_id: 123 # Channel for the channel movement checker UWCS_exec_spam_channel_id: 1234 + # Channel for message logs + UWCS_message_log_channel_id: 1234 # IRC bridge bot ID UWCS_discord_bridge_bot_id: 1337 # API Key for chatgpt integration diff --git a/config/config.py b/config/config.py index 64cc34ab..275cb0fa 100644 --- a/config/config.py +++ b/config/config.py @@ -20,6 +20,7 @@ def __init__(self, filepath: str): self.UWCS_WELCOME_CHANNEL_ID: int = parsed.get("UWCS_welcome_channel_id") self.UWCS_ROLES_CHANNEL_ID: int = parsed.get("UWCS_roles_channel_id") self.UWCS_EXEC_SPAM_CHANNEL_ID: int = parsed.get("UWCS_exec_spam_channel_id") + self.UWCS_MESSAGE_LOG_CHANNEL_ID: int = parsed.get("UWCS_message_log_channel_id") self.UWCS_DISCORD_BRIDGE_BOT_ID: int = parsed.get("UWCS_discord_bridge_bot_id") self.OPENAI_API_KEY: str = parsed.get("openai_api_key") self.AI_INCLUDE_NAMES: bool = parsed.get("ai_include_names") From ebe3270ab038f66f5019c40356e84b815815e43b Mon Sep 17 00:00:00 2001 From: lunazeta Date: Thu, 19 Mar 2026 13:03:17 +0000 Subject: [PATCH 3/5] Me being stupid --- cogs/bot_moderation.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/cogs/bot_moderation.py b/cogs/bot_moderation.py index cd5dd554..c190c2f6 100644 --- a/cogs/bot_moderation.py +++ b/cogs/bot_moderation.py @@ -1,6 +1,3 @@ -import asyncio -import difflib - from datetime import datetime, timedelta import discord @@ -9,15 +6,6 @@ from config import CONFIG -async def not_in_blacklisted_channel(ctx: Context): - return ( - await is_compsoc_exec_in_guild(ctx) - or db_session.query(IgnoredChannel) - .filter(IgnoredChannel.channel == ctx.channel.id) - .first() - is None - ) - class Database(Cog): def __init__(self, bot: Bot): self.bot = bot @@ -31,14 +19,14 @@ async def on_message(self, message: discord.Message): is_giving_away = 'giving away' in message.content.lower() if not joined_recently or not (contains_everyone or is_giving_away): - break + return channel = self.bot.get_channel(CONFIG.UWCS_MESSAGE_LOG_CHANNEL_ID) embed_colour = Color.from_rgb(61, 83, 255) embed_title = f'@{message.author.global_name}, ID: {message.author.id}' embed_description = f'User suspected to be a bot, joined_recently: {joined_recently}, contains_everyone: {contains_everyone}, is_giving_away: {is_giving_away}' - embed = discord.Embed( + embed = Embed( title=embed_title, color=embed_colour, embed_description=embed_description ) From da6c062874f2bba47d4ec6aeb958cfe0cd0703fc Mon Sep 17 00:00:00 2001 From: lunazeta Date: Thu, 19 Mar 2026 13:06:05 +0000 Subject: [PATCH 4/5] Still being stupid apparently --- cogs/bot_moderation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cogs/bot_moderation.py b/cogs/bot_moderation.py index c190c2f6..3789c5e1 100644 --- a/cogs/bot_moderation.py +++ b/cogs/bot_moderation.py @@ -1,16 +1,15 @@ from datetime import datetime, timedelta import discord -from discord import Embed, Color +from discord import Color, Embed from discord.ext.commands import Bot, Cog from config import CONFIG + class Database(Cog): def __init__(self, bot: Bot): self.bot = bot - # Set up a global check that we're not in a blacklisted channel - self.bot.add_check(not_in_blacklisted_channel) @Cog.listener() async def on_message(self, message: discord.Message): From 2316798f5327cb6f2cc8ea3922374301bfcc111e Mon Sep 17 00:00:00 2001 From: lunazeta Date: Thu, 19 Mar 2026 13:09:02 +0000 Subject: [PATCH 5/5] Updated config based on #296 --- cogs/bot_moderation.py | 2 +- config.example.yaml | 2 +- config/config.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cogs/bot_moderation.py b/cogs/bot_moderation.py index 3789c5e1..6cc3351e 100644 --- a/cogs/bot_moderation.py +++ b/cogs/bot_moderation.py @@ -20,7 +20,7 @@ async def on_message(self, message: discord.Message): if not joined_recently or not (contains_everyone or is_giving_away): return - channel = self.bot.get_channel(CONFIG.UWCS_MESSAGE_LOG_CHANNEL_ID) + channel = self.bot.get_channel(CONFIG.UWCS_BOT_LOG_CHANNEL_ID) embed_colour = Color.from_rgb(61, 83, 255) embed_title = f'@{message.author.global_name}, ID: {message.author.id}' diff --git a/config.example.yaml b/config.example.yaml index 3a87df47..b210a57b 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -21,7 +21,7 @@ config: # Channel for the channel movement checker UWCS_exec_spam_channel_id: 1234 # Channel for message logs - UWCS_message_log_channel_id: 1234 + UWCS_bot_log_channel_id: 1234 # IRC bridge bot ID UWCS_discord_bridge_bot_id: 1337 # API Key for chatgpt integration diff --git a/config/config.py b/config/config.py index 275cb0fa..430beec8 100644 --- a/config/config.py +++ b/config/config.py @@ -20,7 +20,7 @@ def __init__(self, filepath: str): self.UWCS_WELCOME_CHANNEL_ID: int = parsed.get("UWCS_welcome_channel_id") self.UWCS_ROLES_CHANNEL_ID: int = parsed.get("UWCS_roles_channel_id") self.UWCS_EXEC_SPAM_CHANNEL_ID: int = parsed.get("UWCS_exec_spam_channel_id") - self.UWCS_MESSAGE_LOG_CHANNEL_ID: int = parsed.get("UWCS_message_log_channel_id") + self.UWCS_BOT_LOG_CHANNEL_ID: int = parsed.get("UWCS_message_log_channel_id") self.UWCS_DISCORD_BRIDGE_BOT_ID: int = parsed.get("UWCS_discord_bridge_bot_id") self.OPENAI_API_KEY: str = parsed.get("openai_api_key") self.AI_INCLUDE_NAMES: bool = parsed.get("ai_include_names")