From cf77026b5f103386ce29d7a550a0e085f2126115 Mon Sep 17 00:00:00 2001 From: fretuks Date: Mon, 15 Dec 2025 20:00:51 +0100 Subject: [PATCH] Fix the fucking bot --- helper_moderation.py | 32 +++++++++++++++++++---- tars_bot.py | 62 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/helper_moderation.py b/helper_moderation.py index faab0d4..d129316 100644 --- a/helper_moderation.py +++ b/helper_moderation.py @@ -23,6 +23,9 @@ def is_user_immune(member: discord.Member) -> bool: async def handle_moderation(message): + current_warnings = await get_warnings(str(message.author.id)) + if current_warnings >= WARN_THRESHOLD: + return if message.author.bot: return if is_user_immune(message.author): @@ -42,7 +45,25 @@ async def handle_moderation(message): await message.delete() except Exception as e: logger.warning(f"Failed to delete banned word message: {e}") - + if count >= WARN_THRESHOLD: + try: + await message.author.timeout( + discord.utils.utcnow() + timedelta(minutes=10), + reason="T.A.R.S. automated enforcement (banned word)" + ) + await send_mod_log( + g, + f"{message.author} was timed out for 10 minutes (banned word threshold).", + ping_staff=True + ) + await set_warnings(uid, 0) + except Exception as e: + await send_mod_log( + g, + f"Failed to timeout {message.author}: {e}", + ping_staff=False + ) + return await message.channel.send( tars_text(f"{message.author.mention}, watch your language. [Warning {count}/3]") ) @@ -53,7 +74,7 @@ async def handle_moderation(message): await send_mod_log( g, f"Banned word '{word}' used by {message.author} in {message.channel.mention}. Warnings {count}.", - ping_staff=(count >= WARN_THRESHOLD) + ping_staff=False ) return if len(text.splitlines()) > 10 or len(text) > 500: @@ -175,7 +196,6 @@ async def handle_moderation(message): ping_staff=(count >= WARN_THRESHOLD) ) return - current_warnings = await get_warnings(uid) if current_warnings >= WARN_THRESHOLD: try: await message.author.timeout( @@ -199,7 +219,7 @@ async def handle_moderation(message): async def increment_warning(user_id: str) -> int: count = await get_warnings(user_id) - count += 1 + count = min(count + 1, WARN_THRESHOLD) await set_warnings(user_id, count) return count @@ -256,7 +276,9 @@ async def helper_warn(message, reaction, uid): except Exception as e: logger.exception(f"Could not delete message: {e}") count = await get_warnings(uid) - count += 1 + if count >= WARN_THRESHOLD: + return WARN_THRESHOLD + count = min(count + 1, WARN_THRESHOLD) await set_warnings(uid, count) return count diff --git a/tars_bot.py b/tars_bot.py index 300d5eb..6fff2b4 100644 --- a/tars_bot.py +++ b/tars_bot.py @@ -790,32 +790,37 @@ async def on_message(message: discord.Message): @tree.command(name="tars", description="Activate T.A.R.S. and show available commands") async def slash_tars(interaction: discord.Interaction): - version = BOT_VERSION # pull current version + version = BOT_VERSION intro = tars_text( - f"T.A.R.S. online. Systems nominal.\n**Current Version:** `{version}`\n" - "You can address me directly or use the following commands.", + f"T.A.R.S. online. Systems nominal.\n" + f"**Current Version:** `{version}`\n\n" + "Address me directly or use the commands below.", "info" ) mod_embed = tars_embed( - "Moderation Systems Online", + "Moderation Systems", "/tarsreport — report a user\n" "/clean — delete the last N messages\n" "/lock — lock the current channel\n" "/unlock — unlock the current channel\n" - "/addbannedword — add banned word to auto-delete list\n" - "/listbannedwords — view banned words list\n" + "/slowmode — set slowmode for a channel\n" + "/addbannedword — add a banned word\n" + "/removebannedword — remove a banned word\n" + "/listbannedwords — view banned words\n" ) util_embed = tars_embed( - "Utility Subroutines", + "Utility & Diagnostics", "/userinfo — get user info\n" + "/roleinfo — role details\n" "/serverinfo — server info\n" + "/status — system health & diagnostics\n" + "/config_view — view live configuration (owner)\n" + "/ai_stats — AI usage metrics (moderator)\n" "/remindme — set a reminder\n" "/reactionrole — create reaction roles\n" - "/slowmode — set slowmode for a channel\n" - "/getquote — retrieve a saved quote\n" "/setmotd — configure the message of the day\n" ) @@ -824,7 +829,8 @@ async def slash_tars(interaction: discord.Interaction): "/8ball — Magic 8-ball\n" "/dice — roll dice\n" "/quote — save message quotes\n" - "/ping — check T.A.R.S. responsiveness" + "/getquote — retrieve saved quotes\n" + "/ping — check responsiveness\n" ) await interaction.response.send_message( @@ -1150,6 +1156,40 @@ async def slash_list_banned(interaction: discord.Interaction): ephemeral=True) +@tree.command( + name="removebannedword", + description="Remove a word from the auto-delete list (admin only)" +) +@app_commands.describe(word="Word to unban") +async def slash_remove_banned(interaction: discord.Interaction, word: str): + if not interaction.user.guild_permissions.manage_messages: + await interaction.response.send_message( + tars_text("You lack permission to modify banned words.", "error"), + ephemeral=True + ) + return + + word = word.lower().strip() + banned = await get_config("banned_words", []) + if word not in banned: + await interaction.response.send_message( + tars_text(f"'{word}' is not currently in the banned words list.", "warning"), + ephemeral=True + ) + return + banned.remove(word) + await set_config("banned_words", banned) + await interaction.response.send_message( + tars_text(f"Removed '{word}' from banned words.", "success"), + ephemeral=True + ) + await helper_moderation.send_mod_log( + interaction.guild, + f"Admin {interaction.user.mention} removed banned word: **{word}**", + ping_staff=False + ) + + @tree.command(name="ping", description="Check T.A.R.S. responsiveness") async def slash_ping(interaction: discord.Interaction): latency = round(bot.latency * 1000) @@ -1401,7 +1441,7 @@ async def slash_config_view(interaction: discord.Interaction): @tree.command(name="ai_stats", description="View AI usage metrics (moderator)") async def slash_ai_stats(interaction: discord.Interaction): - if not interaction.user.guild_permissions.manage_guild: + if not interaction.user.guild_permissions.manage_messages: await interaction.response.send_message(tars_text("Insufficient clearance."), ephemeral=True) return top_users = sorted(