import discord from discord.ext import commands from discord import app_commands import datetime import sqlite3 import time class Moderation(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot self.db_connection = sqlite3.connect("xalos_data.db") self.db_cursor = self.db_connection.cursor() self.db_cursor.execute(""" CREATE TABLE IF NOT EXISTS warnings ( warning_id INTEGER PRIMARY KEY AUTOINCREMENT, guild_id INTEGER, user_id INTEGER, moderator_id INTEGER, reason TEXT, timestamp INTEGER ) """) self.db_cursor.execute(""" CREATE TABLE IF NOT EXISTS automod_configs ( guild_id INTEGER PRIMARY KEY, badwords_enabled INTEGER DEFAULT 0 ) """) self.db_cursor.execute(""" CREATE TABLE IF NOT EXISTS forbidden_words ( guild_id INTEGER, word TEXT, PRIMARY KEY (guild_id, word) ) """) self.db_connection.commit() @app_commands.command(name="kick", description="Kickt ein Mitglied vom Server.") @app_commands.describe( member="Das Mitglied, das gekickt werden soll.", reason="Der Grund fuer den Kick." ) @app_commands.checks.has_permissions(kick_members=True) async def kick(self, interaction: discord.Interaction, member: discord.Member, reason: str = "Kein Grund angegeben"): if member == interaction.user: await interaction.response.send_message("Du kannst dich nicht selbst kicken.", ephemeral=True) return if member == self.bot.user or member == interaction.guild.owner: await interaction.response.send_message("Diese Person kann nicht gekickt werden.", ephemeral=True) return try: await member.send(f"Du wurdest vom Server '{interaction.guild.name}' gekickt. Grund: {reason}") except discord.Forbidden: pass await member.kick(reason=reason) embed = discord.Embed( title="Mitglied gekickt", description=f"{member.mention} wurde erfolgreich gekickt.", color=discord.Color.orange() ) embed.add_field(name="Grund", value=reason, inline=False) embed.add_field(name="Moderator", value=interaction.user.mention, inline=False) await interaction.response.send_message(embed=embed) @kick.error async def kick_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError): if isinstance(error, app_commands.MissingPermissions): await interaction.response.send_message("Dir fehlt die Berechtigung (`kick_members`), um diesen Befehl auszufuehren!", ephemeral=True) else: await interaction.response.send_message("Ein unerwarteter Fehler ist aufgetreten.", ephemeral=True) print(error) @app_commands.command(name="ban", description="Verbannt ein Mitglied permanent vom Server.") @app_commands.describe( member="Das Mitglied, das verbannt werden soll.", reason="Der Grund für den Bann." ) @app_commands.checks.has_permissions(ban_members=True) async def ban(self, interaction: discord.Interaction, member: discord.Member, reason: str = "Kein Grund angegeben"): """Verbannt ein Mitglied und sendet eine Bestätigung.""" if member == interaction.user: await interaction.response.send_message("Du kannst dich nicht selbst bannen.", ephemeral=True) return if member == self.bot.user or member == interaction.guild.owner: await interaction.response.send_message("Diese Person kann nicht gebannt werden.", ephemeral=True) return try: await member.send(f"Du wurdest vom Server '{interaction.guild.name}' permanent gebannt. Grund: {reason}") except discord.Forbidden: pass await member.ban(reason=reason) embed = discord.Embed( title="Mitglied gebannt", description=f"{member.mention} wurde erfolgreich gebannt.", color=discord.Color.red() ) embed.add_field(name="Grund", value=reason, inline=False) embed.add_field(name="Moderator", value=interaction.user.mention, inline=False) await interaction.response.send_message(embed=embed) @ban.error async def ban_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError): if isinstance(error, app_commands.MissingPermissions): await interaction.response.send_message("Dir fehlt die Berechtigung (`ban_members`), um diesen Befehl auszuführen!", ephemeral=True) else: await interaction.response.send_message("Ein unerwarteter Fehler ist aufgetreten.", ephemeral=True) print(error) @app_commands.command(name="mute", description="Schaltet ein Mitglied für eine bestimmte Zeit stumm (Timeout).") @app_commands.describe( member="Das Mitglied, das stummgeschaltet werden soll.", minutes="Die Dauer des Mutes in Minuten.", reason="Der Grund für den Mute." ) @app_commands.checks.has_permissions(moderate_members=True) async def mute(self, interaction: discord.Interaction, member: discord.Member, minutes: int, reason: str = "Kein Grund angegeben"): """Versetzt ein Mitglied in einen Timeout.""" duration = datetime.timedelta(minutes=minutes) await member.timeout(duration, reason=reason) embed = discord.Embed( title="Mitglied stummgeschaltet", description=f"{member.mention} wurde für {minutes} Minute(n) stummgeschaltet.", color=discord.Color.blue() ) embed.add_field(name="Grund", value=reason, inline=False) embed.add_field(name="Moderator", value=interaction.user.mention, inline=False) await interaction.response.send_message(embed=embed) @mute.error async def mute_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError): if isinstance(error, app_commands.MissingPermissions): await interaction.response.send_message("Dir fehlt die Berechtigung (`moderate_members`), um diesen Befehl auszuführen!", ephemeral=True) else: await interaction.response.send_message("Ein unerwarteter Fehler ist aufgetreten.", ephemeral=True) print(error) @app_commands.command(name="warn", description="Verwarnt ein Mitglied.") @app_commands.describe( member="Das Mitglied, das verwarnt werden soll.", reason="Der Grund für die Verwarnung." ) @app_commands.checks.has_permissions(moderate_members=True) async def warn(self, interaction: discord.Interaction, member: discord.Member, reason: str): """Verwarnt ein Mitglied und speichert es in der Datenbank.""" guild_id = interaction.guild.id user_id = member.id moderator_id = interaction.user.id timestamp = int(time.time()) self.db_cursor.execute( "INSERT INTO warnings (guild_id, user_id, moderator_id, reason, timestamp) VALUES (?, ?, ?, ?, ?)", (guild_id, user_id, moderator_id, reason, timestamp) ) self.db_connection.commit() warning_id = self.db_cursor.lastrowid embed = discord.Embed( title="⚠️ Mitglied verwarnt", description=f"{member.mention} wurde verwarnt.", color=discord.Color.yellow() ) embed.add_field(name="Moderator", value=interaction.user.mention, inline=True) embed.add_field(name="Grund", value=reason, inline=True) embed.set_footer(text=f"Warnungs-ID: {warning_id}") await interaction.response.send_message(embed=embed) @app_commands.command(name="warnings", description="Zeigt alle Verwarnungen eines Mitglieds an.") @app_commands.describe(member="Das Mitglied, dessen Verwarnungen du sehen möchtest.") @app_commands.checks.has_permissions(moderate_members=True) async def warnings(self, interaction: discord.Interaction, member: discord.Member): """Listet alle Verwarnungen eines Mitglieds auf.""" guild_id = interaction.guild.id user_id = member.id self.db_cursor.execute("SELECT warning_id, moderator_id, reason, timestamp FROM warnings WHERE guild_id = ? AND user_id = ?", (guild_id, user_id)) user_warnings = self.db_cursor.fetchall() if not user_warnings: await interaction.response.send_message(f"{member.display_name} hat keine Verwarnungen.", ephemeral=True) return embed = discord.Embed( title=f"Verwarnungen für {member.display_name}", color=member.color ) for warn_id, mod_id, reason, ts in user_warnings: moderator = interaction.guild.get_member(mod_id) or f"ID: {mod_id}" embed.add_field( name=f"Warnung #{warn_id} - ", value=f"**Grund:** {reason}\n**Moderator:** {moderator}", inline=False ) await interaction.response.send_message(embed=embed) @app_commands.command(name="delwarn", description="Löscht eine spezifische Verwarnung.") @app_commands.describe(warning_id="Die ID der Verwarnung, die gelöscht werden soll.") @app_commands.checks.has_permissions(moderate_members=True) async def delwarn(self, interaction: discord.Interaction, warning_id: int): """Löscht eine Verwarnung anhand ihrer ID.""" self.db_cursor.execute("DELETE FROM warnings WHERE warning_id = ? AND guild_id = ?", (warning_id, interaction.guild.id)) changes = self.db_connection.total_changes self.db_connection.commit() if changes > 0: await interaction.response.send_message(f"✅ Verwarnung mit der ID `{warning_id}` wurde erfolgreich gelöscht.", ephemeral=True) else: await interaction.response.send_message(f"❌ Keine Verwarnung mit der ID `{warning_id}` auf diesem Server gefunden.", ephemeral=True) @app_commands.command(name="lock", description="Sperrt einen Kanal, sodass niemand mehr schreiben kann.") @app_commands.describe(channel="Der Kanal, der gesperrt werden soll (standardmäßig der aktuelle).") @app_commands.checks.has_permissions(manage_channels=True) async def lock(self, interaction: discord.Interaction, channel: discord.TextChannel = None): """Sperrt einen Kanal für die @everyone Rolle.""" target_channel = channel or interaction.channel try: # Bearbeite die Berechtigungen für die @everyone Rolle await target_channel.set_permissions( interaction.guild.default_role, send_messages=False, reason=f"Kanal gesperrt von {interaction.user}" ) except discord.Forbidden: await interaction.response.send_message("Ich habe nicht die nötigen Berechtigungen, um diesen Kanal zu sperren.", ephemeral=True) return embed = discord.Embed( title="🔒 Kanal gesperrt", description=f"Der Kanal {target_channel.mention} wurde von {interaction.user.mention} gesperrt.", color=discord.Color.dark_grey() ) await interaction.response.send_message(embed=embed) @app_commands.command(name="unlock", description="Entsperrt einen Kanal, sodass jeder wieder schreiben kann.") @app_commands.describe(channel="Der Kanal, der entsperrt werden soll (standardmäßig der aktuelle).") @app_commands.checks.has_permissions(manage_channels=True) async def unlock(self, interaction: discord.Interaction, channel: discord.TextChannel = None): """Entsperrt einen Kanal für die @everyone Rolle.""" target_channel = channel or interaction.channel try: # Setzt die Berechtigung für send_messages auf den Standard zurück await target_channel.set_permissions( interaction.guild.default_role, send_messages=None, reason=f"Kanal entsperrt von {interaction.user}" ) except discord.Forbidden: await interaction.response.send_message("Ich habe nicht die nötigen Berechtigungen, um diesen Kanal zu entsperren.", ephemeral=True) return embed = discord.Embed( title="🔓 Kanal entsperrt", description=f"Der Kanal {target_channel.mention} wurde von {interaction.user.mention} entsperrt.", color=discord.Color.light_grey() ) await interaction.response.send_message(embed=embed) @app_commands.command(name="slowmode", description="Setzt den langsamen Modus für einen Kanal.") @app_commands.describe( seconds="Die Verzögerung in Sekunden (0 zum Deaktivieren).", channel="Der Kanal, für den der Slowmode gesetzt werden soll (standardmäßig der aktuelle)." ) @app_commands.checks.has_permissions(manage_channels=True) async def slowmode(self, interaction: discord.Interaction, seconds: int, channel: discord.TextChannel = None): """Setzt den Slowmode für einen Kanal.""" target_channel = channel or interaction.channel await target_channel.edit(slowmode_delay=seconds, reason=f"Slowmode gesetzt von {interaction.user}") embed = discord.Embed( title="⏳ Slowmode aktualisiert", description=f"Der Slowmode für {target_channel.mention} wurde auf **{seconds} Sekunden** gesetzt.", color=discord.Color.blue() ) await interaction.response.send_message(embed=embed) # --- Auto-Moderator --- async def get_log_channel(self, guild_id: int) -> discord.TextChannel | None: """Helper to get the log channel from the server_configs table.""" # This table is managed by the audit_log cog self.db_cursor.execute("SELECT log_channel_id FROM server_configs WHERE guild_id = ?", (guild_id,)) result = self.db_cursor.fetchone() if result and result[0]: return self.bot.get_channel(result[0]) return None @commands.Cog.listener() async def on_message(self, message: discord.Message): if not message.guild or message.author.bot: return # Check if user is an admin/moderator - they should be immune if message.author.guild_permissions.manage_messages: return # --- Bad Word Filter --- self.db_cursor.execute("SELECT badwords_enabled FROM automod_configs WHERE guild_id = ?", (message.guild.id,)) config = self.db_cursor.fetchone() if config and config[0] == 1: self.db_cursor.execute("SELECT word FROM forbidden_words WHERE guild_id = ?", (message.guild.id,)) forbidden_words = [row[0] for row in self.db_cursor.fetchall()] if any(word in message.content.lower() for word in forbidden_words): try: await message.delete() await message.channel.send(f"{message.author.mention}, deine Nachricht wurde gelöscht, da sie ein verbotenes Wort enthielt.", delete_after=10) # Log the action log_channel = await self.get_log_channel(message.guild.id) if log_channel: embed = discord.Embed( title="🛡️ Auto-Mod Aktion", description=f"**Aktion:** Nachricht mit verbotenem Wort gelöscht.", color=discord.Color.red() ) embed.add_field(name="Mitglied", value=message.author.mention, inline=True) embed.add_field(name="Kanal", value=message.channel.mention, inline=True) embed.add_field(name="Inhalt", value=f"||{message.content[:1000]}||", inline=False) await log_channel.send(embed=embed) except discord.Forbidden: # Bot has no permissions to delete messages pass except Exception as e: print(f"Error in automod: {e}") # --- Auto-Mod Commands --- automod_group = app_commands.Group(name="automod", description="Konfiguriert den Auto-Moderator.", default_permissions=discord.Permissions(manage_guild=True)) @automod_group.command(name="togglewords", description="Aktiviert oder deaktiviert den Filter für verbotene Wörter.") @app_commands.describe(enabled="Soll der Filter aktiviert werden?") async def automod_toggle_words(self, interaction: discord.Interaction, enabled: bool): self.db_cursor.execute("INSERT OR REPLACE INTO automod_configs (guild_id, badwords_enabled) VALUES (?, ?)", (interaction.guild.id, int(enabled))) self.db_connection.commit() status = "aktiviert" if enabled else "deaktiviert" await interaction.response.send_message(f"✅ Der Filter für verbotene Wörter wurde **{status}**.", ephemeral=True) badwords_group = app_commands.Group(name="badwords", description="Verwaltet die Liste der verbotenen Wörter.", parent=automod_group) @badwords_group.command(name="add", description="Fügt ein verbotenes Wort hinzu.") @app_commands.describe(word="Das Wort, das hinzugefügt werden soll.") async def badwords_add(self, interaction: discord.Interaction, word: str): word = word.lower() try: self.db_cursor.execute("INSERT INTO forbidden_words (guild_id, word) VALUES (?, ?)", (interaction.guild.id, word)) self.db_connection.commit() await interaction.response.send_message(f"✅ Das Wort `{word}` wurde zur Liste hinzugefügt.", ephemeral=True) except sqlite3.IntegrityError: await interaction.response.send_message(f"⚠️ Das Wort `{word}` ist bereits auf der Liste.", ephemeral=True) @badwords_group.command(name="remove", description="Entfernt ein verbotenes Wort.") @app_commands.describe(word="Das Wort, das entfernt werden soll.") async def badwords_remove(self, interaction: discord.Interaction, word: str): word = word.lower() self.db_cursor.execute("DELETE FROM forbidden_words WHERE guild_id = ? AND word = ?", (interaction.guild.id, word)) if self.db_cursor.rowcount > 0: self.db_connection.commit() await interaction.response.send_message(f"✅ Das Wort `{word}` wurde von der Liste entfernt.", ephemeral=True) else: await interaction.response.send_message(f"❌ Das Wort `{word}` wurde nicht auf der Liste gefunden.", ephemeral=True) @badwords_group.command(name="list", description="Zeigt alle verbotenen Wörter an.") async def badwords_list(self, interaction: discord.Interaction): self.db_cursor.execute("SELECT word FROM forbidden_words WHERE guild_id = ?", (interaction.guild.id,)) words = [row[0] for row in self.db_cursor.fetchall()] if not words: await interaction.response.send_message("Die Liste der verbotenen Wörter ist leer.", ephemeral=True) return embed = discord.Embed( title="🚫 Liste der verbotenen Wörter", description=", ".join(f"`{w}`" for w in words), color=discord.Color.red() ) await interaction.response.send_message(embed=embed, ephemeral=True) async def setup(bot: commands.Bot): cog = Moderation(bot) # Add the command groups to the bot's command tree bot.tree.add_command(cog.automod_group) await bot.add_cog(cog)