This commit is contained in:
Robin
2025-10-06 14:20:28 +02:00
commit f0c8fe734a
16 changed files with 1360 additions and 0 deletions

401
cogs/moderation.py Normal file
View File

@@ -0,0 +1,401 @@
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} - <t:{ts}:d>",
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)