modified: bot.py

This commit is contained in:
SimolZimol
2025-08-19 20:05:13 +02:00
parent 4d8db0773f
commit 6109a8beb8

320
bot.py
View File

@@ -2587,6 +2587,122 @@ def check_moderation_permission(user_permission):
"""Checks if the user has moderation rights (Permission 5 or higher)""" """Checks if the user has moderation rights (Permission 5 or higher)"""
return user_permission >= 5 return user_permission >= 5
async def log_moderation_action(guild, action_type, moderator, target_user, reason, duration=None, additional_info=None):
"""Logs moderation actions to the configured log channel"""
try:
guild_settings = get_guild_settings(guild.id)
# Check if logging is enabled and channel is configured
if not guild_settings["mod_log_enabled"] or not guild_settings["log_channel_id"]:
return
log_channel = guild.get_channel(guild_settings["log_channel_id"])
if not log_channel:
logger.warning(f"Log channel {guild_settings['log_channel_id']} not found in guild {guild.id}")
return
# Create log embed
color_map = {
"warn": 0xff9500,
"mute": 0xff0000,
"unmute": 0x00ff00,
"kick": 0xff6600,
"ban": 0x8b0000,
"unban": 0x00ff00
}
embed = discord.Embed(
title=f"🛡️ Moderation Action: {action_type.title()}",
color=color_map.get(action_type.lower(), 0x3498db),
timestamp=datetime.now()
)
embed.add_field(name="👤 Target User", value=f"{target_user.mention}\n`{target_user.id}`", inline=True)
embed.add_field(name="👮 Moderator", value=f"{moderator.mention}\n`{moderator.id}`", inline=True)
embed.add_field(name="📝 Reason", value=reason, inline=True)
if duration:
embed.add_field(name="⏱️ Duration", value=duration, inline=True)
if additional_info:
for key, value in additional_info.items():
embed.add_field(name=key, value=value, inline=True)
embed.set_thumbnail(url=target_user.display_avatar.url)
embed.set_footer(text=f"Action ID: {guild.id}-{target_user.id}-{int(datetime.now().timestamp())}")
await log_channel.send(embed=embed)
logger.info(f"Logged {action_type} action for user {target_user.id} in guild {guild.id}")
except Exception as e:
logger.error(f"Error logging moderation action: {e}")
async def save_warning_to_database(user_id, guild_id, moderator_id, reason, timestamp=None):
"""Saves individual warning records to the database"""
connection = None
cursor = None
try:
connection = connect_to_database()
cursor = connection.cursor()
if timestamp is None:
timestamp = datetime.now()
insert_query = """
INSERT INTO user_warnings (user_id, guild_id, moderator_id, reason, created_at)
VALUES (%s, %s, %s, %s, %s)
"""
cursor.execute(insert_query, (user_id, guild_id, moderator_id, reason, timestamp))
connection.commit()
logger.info(f"Saved warning record for user {user_id} in guild {guild_id}")
return cursor.lastrowid
except Exception as e:
logger.error(f"Error saving warning to database: {e}")
if connection:
connection.rollback()
return None
finally:
if cursor:
cursor.close()
if connection:
close_database_connection(connection)
def create_warnings_table():
"""Creates the user_warnings table if it doesn't exist"""
connection = None
cursor = None
try:
connection = connect_to_database()
cursor = connection.cursor()
create_table_query = """
CREATE TABLE IF NOT EXISTS user_warnings (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
guild_id BIGINT NOT NULL,
moderator_id BIGINT NOT NULL,
reason TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_guild (user_id, guild_id),
INDEX idx_created_at (created_at)
)
"""
cursor.execute(create_table_query)
connection.commit()
logger.info("User warnings table checked/created successfully")
except Exception as e:
logger.error(f"Error creating warnings table: {e}")
finally:
if cursor:
cursor.close()
if connection:
close_database_connection(connection)
async def save_user_roles(user_id, guild_id, roles): async def save_user_roles(user_id, guild_id, roles):
"""Saves a user's roles before a mute""" """Saves a user's roles before a mute"""
connection = None connection = None
@@ -2669,46 +2785,157 @@ async def warn(ctx, user: discord.User, *, reason: str = "No reason provided"):
# Check moderation rights # Check moderation rights
if not check_moderation_permission(mod_data["permission"]): if not check_moderation_permission(mod_data["permission"]):
await ctx.send("❌ You don't have permission to use this command. (Requires Permission Level 5 or higher)") embed = discord.Embed(
title="❌ Insufficient Permissions",
description="You need moderation permissions (Level 5 or higher) to use this command.",
color=0xff0000
)
await ctx.send(embed=embed, ephemeral=True)
return
# Cannot warn yourself
if user.id == ctx.author.id:
embed = discord.Embed(
title="❌ Invalid Action",
description="You cannot warn yourself!",
color=0xff0000
)
await ctx.send(embed=embed, ephemeral=True)
return
# Check if target has higher permissions
target_data = await load_user_data(user.id, ctx.guild.id)
if target_data["permission"] >= mod_data["permission"]:
embed = discord.Embed(
title="❌ Insufficient Permissions",
description="You cannot warn someone with equal or higher permissions than you.",
color=0xff0000
)
await ctx.send(embed=embed, ephemeral=True)
return return
# Load user data
user_data = await load_user_data(user.id, ctx.guild.id)
# Increase warn count # Increase warn count
user_data["warns"] += 1 target_data["warns"] += 1
update_user_data(user.id, ctx.guild.id, "warns", user_data["warns"]) update_user_data(user.id, ctx.guild.id, "warns", target_data["warns"])
# Save detailed warning record to database
warning_id = await save_warning_to_database(
user_id=user.id,
guild_id=ctx.guild.id,
moderator_id=ctx.author.id,
reason=reason
)
# Get guild settings for threshold checking
guild_settings = get_guild_settings(ctx.guild.id)
warn_threshold = guild_settings.get("max_warn_threshold", 3)
# Create embed # Create embed
embed = discord.Embed( embed = discord.Embed(
title="⚠️ Warning issued", title="⚠️ Warning Issued",
description=f"{user.mention} has been warned.", description=f"{user.mention} has been warned.",
color=0xff9500, color=0xff9500,
timestamp=datetime.now() timestamp=datetime.now()
) )
embed.add_field(name="Reason", value=reason, inline=False) embed.add_field(name="📝 Reason", value=reason, inline=False)
embed.add_field(name="Moderator", value=ctx.author.mention, inline=True) embed.add_field(name="👮 Moderator", value=ctx.author.mention, inline=True)
embed.add_field(name="Warning Count", value=f"{user_data['warns']}", inline=True) embed.add_field(name="⚠️ Warning Count", value=f"{target_data['warns']}/{warn_threshold}", inline=True)
if warning_id:
embed.add_field(name="🆔 Warning ID", value=str(warning_id), inline=True)
embed.set_footer(text=f"User ID: {user.id}") embed.set_footer(text=f"User ID: {user.id}")
embed.set_thumbnail(url=user.display_avatar.url)
# Check if user has reached the warning threshold
if target_data['warns'] >= warn_threshold:
auto_mute_enabled = guild_settings.get("auto_mute_on_warns", False)
if auto_mute_enabled:
mute_role_id = guild_settings.get("mute_role_id")
if mute_role_id and ctx.guild.get_role(mute_role_id):
mute_role = ctx.guild.get_role(mute_role_id)
try:
member = ctx.guild.get_member(user.id)
if member:
await member.add_roles(mute_role, reason=f"Automatic mute: {warn_threshold} warnings reached")
embed.add_field(
name="🔇 Automatic Action",
value=f"User has been automatically muted for reaching {warn_threshold} warnings.",
inline=False
)
# Log the automatic mute action
await log_moderation_action(
guild=ctx.guild,
action_type="mute",
moderator=ctx.author,
target_user=user,
reason=f"Automatic mute: {warn_threshold} warnings reached",
additional_info={"Trigger": f"Warning #{target_data['warns']}"}
)
except discord.Forbidden:
embed.add_field(
name="⚠️ Warning",
value="Could not automatically mute user due to insufficient permissions.",
inline=False
)
else:
embed.add_field(
name="🚨 Threshold Reached",
value=f"User has reached the warning threshold ({warn_threshold} warnings). Consider further action.",
inline=False
)
await ctx.send(embed=embed) await ctx.send(embed=embed)
# Log the warning action
await log_moderation_action(
guild=ctx.guild,
action_type="warn",
moderator=ctx.author,
target_user=user,
reason=reason,
additional_info={
"Warning Count": f"{target_data['warns']}/{warn_threshold}",
"Warning ID": str(warning_id) if warning_id else "N/A"
}
)
# Try to DM the user
try:
dm_embed = discord.Embed(
title=f"⚠️ Warning from {ctx.guild.name}",
color=0xff9500,
timestamp=datetime.now()
)
dm_embed.add_field(name="👮 Moderator", value=ctx.author.display_name, inline=True)
dm_embed.add_field(name="📝 Reason", value=reason, inline=False)
dm_embed.add_field(name="⚠️ Total Warnings", value=f"{target_data['warns']}/{warn_threshold}", inline=True)
if target_data['warns'] >= warn_threshold:
dm_embed.add_field(
name="🔇 Additional Action",
value="You have reached the warning threshold. Further violations may result in more severe punishments.",
inline=False
)
await user.send(embed=dm_embed)
except discord.Forbidden:
# User has DMs disabled
pass
# Log the action # Log the action
logger.info(f"User {user.id} warned by {ctx.author.id} in guild {ctx.guild.id}. Reason: {reason}") logger.info(f"User {user.id} warned by {ctx.author.id} in guild {ctx.guild.id}. Reason: {reason}")
# Auto-actions based on warning count
if user_data["warns"] >= 3:
embed_auto = discord.Embed(
title="🚨 Auto-action triggered",
description=f"{user.mention} has reached {user_data['warns']} warnings!",
color=0xff0000
)
embed_auto.add_field(name="Recommendation", value="Consider further moderation measures", inline=False)
await ctx.send(embed=embed_auto)
except Exception as e: except Exception as e:
logger.error(f"Error in warn command: {e}") logger.error(f"Error in warn command: {e}")
await ctx.send("❌ An error occurred while warning the user.") embed = discord.Embed(
title="❌ Error",
description="An error occurred while processing the warning. Please try again.",
color=0xff0000
)
await ctx.send(embed=embed)
@client.hybrid_command() @client.hybrid_command()
async def mywarns(ctx): async def mywarns(ctx):
@@ -2723,11 +2950,18 @@ async def mywarns(ctx):
timestamp=datetime.now() timestamp=datetime.now()
) )
# Warning information # Get guild settings for thresholds
warn_color = "🟢" if user_data["warns"] == 0 else "🟡" if user_data["warns"] < 3 else "🔴" guild_settings = get_guild_settings(ctx.guild.id)
# Get detailed warning records
warning_records = await get_user_warnings(ctx.author.id, ctx.guild.id)
# Warning information with threshold
warn_threshold = guild_settings.get("max_warn_threshold", 3)
warn_color = "🟢" if user_data["warns"] == 0 else "🟡" if user_data["warns"] < warn_threshold else "🔴"
embed.add_field( embed.add_field(
name=f"{warn_color} Warnings", name=f"{warn_color} Warnings",
value=f"**{user_data['warns']}** warning(s)", value=f"**{user_data['warns']}/{warn_threshold}** warnings",
inline=True inline=True
) )
@@ -2765,11 +2999,37 @@ async def mywarns(ctx):
embed.add_field(name="📈 Status", value=status, inline=False) embed.add_field(name="📈 Status", value=status, inline=False)
embed.color = status_color embed.color = status_color
# Detailed warning history (show last 5 warnings)
if warning_records:
warning_history = "**Recent Warning History:**\n"
display_count = min(5, len(warning_records))
for i in range(display_count):
record = warning_records[i]
moderator = ctx.guild.get_member(record["moderator_id"])
mod_name = moderator.display_name if moderator else f"ID: {record['moderator_id']}"
# Format date
warning_date = record["created_at"].strftime("%d.%m.%Y %H:%M")
# Truncate reason if too long
reason = record["reason"]
if len(reason) > 50:
reason = reason[:47] + "..."
warning_history += f"`{warning_date}` - **{mod_name}**: {reason}\n"
if len(warning_records) > 5:
warning_history += f"\n*... and {len(warning_records) - 5} more warning(s)*"
embed.add_field(name="📋 Warning Details", value=warning_history, inline=False)
# Get guild settings for thresholds # Get guild settings for thresholds
guild_settings = get_guild_settings(ctx.guild.id) threshold_info = f"Warning threshold: **{warn_threshold}** warnings"
threshold_info = f"Warning threshold: **{guild_settings['max_warn_threshold']}** warnings" auto_mute_enabled = guild_settings.get("auto_mute_on_warns", False)
if guild_settings["auto_mute_on_warns"]: if auto_mute_enabled:
threshold_info += f"\nAuto-mute duration: **{guild_settings['auto_mute_duration']}**" auto_mute_duration = guild_settings.get("auto_mute_duration", "1 hour")
threshold_info += f"\nAuto-mute: **{auto_mute_duration}** (at {warn_threshold} warnings)"
embed.add_field(name="⚙️ Server Settings", value=threshold_info, inline=False) embed.add_field(name="⚙️ Server Settings", value=threshold_info, inline=False)
@@ -3412,6 +3672,10 @@ async def delnotes(ctx):
await ctx.send(f"No notes found for user {ctx.author.name}.") await ctx.send(f"No notes found for user {ctx.author.name}.")
try: try:
# Initialize database tables
create_warnings_table()
logger.info("Database tables initialized successfully")
loop.run_until_complete(client.start(TOKEN)) loop.run_until_complete(client.start(TOKEN))
except KeyboardInterrupt: except KeyboardInterrupt:
loop.run_until_complete(client.logout()) loop.run_until_complete(client.logout())