Enhance AutoMod configuration by introducing event-specific settings and thresholds. Refactor Automod schemas to include event configurations, thresholds, and limits for ignored roles and channels. Update database interactions to support new structure and improve handling of AutoMod rules in cogs, ensuring dynamic thresholds for various events. Update dashboard components to accommodate new configurations and improve user experience in managing AutoMod settings.
Some checks failed
CI / Bot (Python) (push) Successful in 12s
CI / Dashboard (Next.js) (push) Failing after 9s

This commit is contained in:
TheOnlyMace
2026-07-21 23:05:05 +02:00
parent d24b810164
commit 36b32de34c
17 changed files with 842 additions and 165 deletions

View File

@@ -11,6 +11,7 @@
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord
from utils.emoji import TICK
@@ -23,7 +24,6 @@ import asyncio
class AntiEmojiSpam(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.emoji_threshold = 5
async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect(db_path("automod.db")) as db:
@@ -118,17 +118,20 @@ class AntiEmojiSpam(commands.Cog):
emoji_count = len(emoji_pattern.findall(message.content))
th = await get_thresholds(guild_id, "anti_emoji_spam")
emoji_threshold = int(th.get("max_emojis", 5))
mute_minutes = float(th.get("mute_minutes", 1))
if emoji_count > self.emoji_threshold:
if emoji_count > emoji_threshold:
punishment = await self.get_punishment(guild_id)
action_taken = None
reason = f"Emoji Spam ({emoji_count} emojis)"
try:
if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=1)
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason=reason)
action_taken = "Muted for 1 minute"
action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick":
await user.kick(reason=reason)
action_taken = "Kicked"

View File

@@ -11,6 +11,7 @@
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord
from utils.emoji import TICK
@@ -105,15 +106,17 @@ class AntiInvite(commands.Cog):
if any(invite.code == invite_code for invite in invite):
return
th = await get_thresholds(guild_id, "anti_invites")
mute_minutes = float(th.get("mute_minutes", 12))
punishment = await self.get_punishment(guild_id)
action_taken = None
reason = "Posted an invite link"
try:
if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=12)
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason="Posted an invite link")
action_taken = "Muted for 12 minutes"
action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick":
await user.kick(reason="Posted an invite link")
action_taken = "Kicked"

View File

@@ -11,6 +11,7 @@
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord
from utils.emoji import TICK
@@ -22,7 +23,6 @@ import asyncio
class AntiMassMention(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.mass_mention_threshold = 5
async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect(db_path("automod.db")) as db:
@@ -97,17 +97,21 @@ class AntiMassMention(commands.Cog):
return
th = await get_thresholds(guild_id, "anti_mass_mention")
mention_threshold = int(th.get("max_mentions", 5))
mute_minutes = float(th.get("mute_minutes", 3))
mention_count = message.content.count("<@")
if mention_count >= self.mass_mention_threshold:
if mention_count >= mention_threshold:
punishment = await self.get_punishment(guild_id)
action_taken = None
reason = f"Mass Mention ({mention_count} mentions)"
try:
if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=3)
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason=reason)
action_taken = "Muted for 3 minutes"
action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick":
await user.kick(reason=reason)
action_taken = "Kicked"

View File

@@ -11,6 +11,7 @@
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord
from utils.emoji import TICK
@@ -22,8 +23,6 @@ from datetime import timedelta
class AntiCaps(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.caps_threshold = 70
self.mute_duration = 2 * 60
async def is_automod_enabled(self, guild_id):
async with aiosqlite.connect(db_path("automod.db")) as db:
@@ -74,9 +73,6 @@ class AntiCaps(commands.Cog):
@commands.Cog.listener()
async def on_message(self, message):
if len(message.content) < 45:
return
if message.author.bot:
return
@@ -85,6 +81,14 @@ class AntiCaps(commands.Cog):
channel = message.channel
guild_id = guild.id
th = await get_thresholds(guild_id, "anti_caps")
min_length = int(th.get("min_length", 45))
caps_threshold = float(th.get("percent", 70))
mute_minutes = float(th.get("mute_minutes", 1))
if len(message.content) < min_length:
return
if not await self.is_automod_enabled(guild_id) or not await self.is_anti_caps_enabled(guild_id):
return
@@ -103,16 +107,16 @@ class AntiCaps(commands.Cog):
caps_count = sum(1 for c in message.content if c.isupper())
caps_percentage = (caps_count / len(message.content)) * 100
if caps_percentage > self.caps_threshold:
if caps_percentage > caps_threshold:
punishment = await self.get_punishment(guild_id)
action_taken = None
reason = "Excessive Caps"
try:
if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=1)
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason="Excessive Caps")
action_taken = "Muted for 1 minutes"
action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick":
await user.kick(reason="Excessive Caps")
action_taken = "Kicked"

View File

@@ -11,6 +11,7 @@
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord
from utils.emoji import TICK
@@ -107,15 +108,17 @@ class AntiLink(commands.Cog):
if self.spotify_pattern.search(message.content):
return
th = await get_thresholds(guild_id, "anti_link")
mute_minutes = float(th.get("mute_minutes", 7))
punishment = await self.get_punishment(guild_id)
action_taken = None
reason = "Posted a link"
try:
if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=7)
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason=reason)
action_taken = "Muted for 7 minutes"
action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick":
await user.kick(reason=reason)
action_taken = "Kicked"

View File

@@ -11,6 +11,7 @@
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝
from utils.db_paths import db_path
from utils.automod_settings import get_thresholds
import discord
from utils.emoji import TICK
@@ -22,8 +23,6 @@ from datetime import timedelta
class AntiSpam(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.spam_threshold = 5
self.mute_duration = 12 * 60
self.recent_messages = {}
async def is_automod_enabled(self, guild_id):
@@ -99,21 +98,26 @@ class AntiSpam(commands.Cog):
return
current_time = message.created_at.timestamp()
th = await get_thresholds(guild_id, "anti_spam")
window = float(th.get("window_seconds", 10))
spam_threshold = int(th.get("max_messages", 5))
mute_minutes = float(th.get("mute_minutes", 12))
user_messages = self.recent_messages.get(user.id, [])
user_messages = [msg for msg in user_messages if current_time - msg < 10]
user_messages = [msg for msg in user_messages if current_time - msg < window]
user_messages.append(current_time)
self.recent_messages[user.id] = user_messages
if len(user_messages) > self.spam_threshold:
if len(user_messages) > spam_threshold:
punishment = await self.get_punishment(guild_id)
action_taken = None
reason = "Spamming"
try:
if punishment == "Mute":
timeout_duration = discord.utils.utcnow() + timedelta(minutes=12)
timeout_duration = discord.utils.utcnow() + timedelta(minutes=mute_minutes)
await user.edit(timed_out_until=timeout_duration, reason="Spamming")
action_taken = "Muted for 12 minutes"
action_taken = f"Muted for {int(mute_minutes)} minutes"
elif punishment == "Kick":
await user.kick(reason="Spamming")
action_taken = "Kicked"

View File

@@ -181,6 +181,15 @@ class Automod(commands.Cog):
PRIMARY KEY (guild_id)
)
""")
await db.execute("""
CREATE TABLE IF NOT EXISTS automod_thresholds (
guild_id INTEGER,
event TEXT,
key TEXT,
value REAL,
PRIMARY KEY (guild_id, event, key)
)
""")
await db.commit()
@commands.hybrid_group(