modified: bot.py
This commit is contained in:
242
bot.py
242
bot.py
@@ -915,8 +915,34 @@ async def handle_expired_mute(process_uuid, data):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Could not restore roles for user {user_id}: {e}")
|
logger.warning(f"Could not restore roles for user {user_id}: {e}")
|
||||||
|
|
||||||
# Send notification to channel if possible
|
# Send notification to mod log channel (preferred) or original channel as fallback
|
||||||
if channel_id:
|
notification_sent = False
|
||||||
|
|
||||||
|
# Try to send to mod log channel first
|
||||||
|
try:
|
||||||
|
guild_settings = get_guild_settings(guild_id)
|
||||||
|
if guild_settings and guild_settings.get("mod_log_channel_id"):
|
||||||
|
mod_log_channel = guild.get_channel(int(guild_settings["mod_log_channel_id"]))
|
||||||
|
if mod_log_channel:
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="🔊 User Automatically Unmuted",
|
||||||
|
description=f"{member.mention} has been automatically unmuted.",
|
||||||
|
color=0x00ff00,
|
||||||
|
timestamp=datetime.now()
|
||||||
|
)
|
||||||
|
embed.add_field(name="👤 User", value=f"{member.mention}\n`{member.id}`", inline=True)
|
||||||
|
embed.add_field(name="📝 Reason", value="Mute duration expired", inline=True)
|
||||||
|
embed.add_field(name="📍 Original Channel", value=f"<#{channel_id}>" if channel_id else "Unknown", inline=True)
|
||||||
|
embed.set_footer(text=f"Process ID: {process_uuid}")
|
||||||
|
embed.set_thumbnail(url=member.display_avatar.url)
|
||||||
|
await mod_log_channel.send(embed=embed)
|
||||||
|
notification_sent = True
|
||||||
|
logger.info(f"Sent auto-unmute notification to mod log channel for user {user_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Could not send unmute notification to mod log channel: {e}")
|
||||||
|
|
||||||
|
# Fallback to original channel if mod log failed
|
||||||
|
if not notification_sent and channel_id:
|
||||||
try:
|
try:
|
||||||
channel = guild.get_channel(int(channel_id))
|
channel = guild.get_channel(int(channel_id))
|
||||||
if channel:
|
if channel:
|
||||||
@@ -929,8 +955,13 @@ async def handle_expired_mute(process_uuid, data):
|
|||||||
embed.add_field(name="📝 Reason", value="Mute duration expired", inline=False)
|
embed.add_field(name="📝 Reason", value="Mute duration expired", inline=False)
|
||||||
embed.set_footer(text=f"Process ID: {process_uuid}")
|
embed.set_footer(text=f"Process ID: {process_uuid}")
|
||||||
await channel.send(embed=embed)
|
await channel.send(embed=embed)
|
||||||
|
notification_sent = True
|
||||||
|
logger.info(f"Sent auto-unmute notification to original channel for user {user_id}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Could not send unmute notification: {e}")
|
logger.warning(f"Could not send unmute notification to original channel: {e}")
|
||||||
|
|
||||||
|
if not notification_sent:
|
||||||
|
logger.warning(f"No channel available for auto-unmute notification for user {user_id}")
|
||||||
|
|
||||||
# Try to DM the user
|
# Try to DM the user
|
||||||
try:
|
try:
|
||||||
@@ -5498,26 +5529,63 @@ async def mute(ctx, user: discord.User, duration: str, reason: str = "No reason
|
|||||||
|
|
||||||
@client.hybrid_command()
|
@client.hybrid_command()
|
||||||
async def unmute(ctx, user: discord.User):
|
async def unmute(ctx, user: discord.User):
|
||||||
"""Entmutet einen Benutzer manuell (Benötigt Permission Level 5 oder höher)"""
|
"""Unmutes a user manually (Requires Permission Level 5 or higher)"""
|
||||||
|
# Check if it's a slash command and defer if needed
|
||||||
|
is_slash_command = hasattr(ctx, 'interaction') and ctx.interaction
|
||||||
|
if is_slash_command:
|
||||||
|
await ctx.defer()
|
||||||
|
|
||||||
|
# Helper function for sending responses
|
||||||
|
async def send_response(content=None, embed=None, ephemeral=False, file=None):
|
||||||
|
try:
|
||||||
|
if is_slash_command:
|
||||||
|
if hasattr(ctx, 'followup') and ctx.followup:
|
||||||
|
await ctx.followup.send(content=content, embed=embed, ephemeral=ephemeral, file=file)
|
||||||
|
elif hasattr(ctx, 'response') and not ctx.response.is_done():
|
||||||
|
await ctx.response.send_message(content=content, embed=embed, ephemeral=ephemeral, file=file)
|
||||||
|
else:
|
||||||
|
await ctx.send(content=content, embed=embed, file=file)
|
||||||
|
else:
|
||||||
|
await ctx.send(content=content, embed=embed, file=file)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error sending response in unmute command: {e}")
|
||||||
|
try:
|
||||||
|
if embed:
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
elif content:
|
||||||
|
await ctx.send(content=content)
|
||||||
|
except Exception as fallback_error:
|
||||||
|
logger.error(f"Fallback send also failed: {fallback_error}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Lade Moderator-Daten
|
# Load moderator data
|
||||||
mod_data = await load_user_data(ctx.author.id, ctx.guild.id)
|
mod_data = await load_user_data(ctx.author.id, ctx.guild.id)
|
||||||
|
|
||||||
# Überprüfe Moderationsrechte
|
# Check moderation permissions
|
||||||
if not check_moderation_permission(mod_data["permission"]):
|
if not check_moderation_permission(mod_data["permission"]):
|
||||||
await ctx.send("❌ Du hast keine Berechtigung, diesen Befehl zu verwenden. (Benötigt Permission Level 5 oder höher)")
|
embed = discord.Embed(
|
||||||
|
title="❌ Insufficient Permissions",
|
||||||
|
description="You need moderation permissions (Level 5 or higher) to use this command.",
|
||||||
|
color=0xff0000
|
||||||
|
)
|
||||||
|
await send_response(embed=embed, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Hole Member-Objekt
|
# Get member object
|
||||||
member = ctx.guild.get_member(user.id)
|
member = ctx.guild.get_member(user.id)
|
||||||
if not member:
|
if not member:
|
||||||
await ctx.send("❌ Benutzer nicht auf diesem Server gefunden.")
|
embed = discord.Embed(
|
||||||
|
title="❌ User Not Found",
|
||||||
|
description="User not found on this server.",
|
||||||
|
color=0xff0000
|
||||||
|
)
|
||||||
|
await send_response(embed=embed, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Lade Guild-Einstellungen
|
# Load guild settings
|
||||||
guild_settings = get_guild_settings(ctx.guild.id)
|
guild_settings = get_guild_settings(ctx.guild.id)
|
||||||
|
|
||||||
# Finde Mute-Rolle basierend auf Einstellungen
|
# Find mute role based on settings
|
||||||
mute_role = None
|
mute_role = None
|
||||||
if guild_settings["mute_role_id"]:
|
if guild_settings["mute_role_id"]:
|
||||||
mute_role = ctx.guild.get_role(guild_settings["mute_role_id"])
|
mute_role = ctx.guild.get_role(guild_settings["mute_role_id"])
|
||||||
@@ -5526,40 +5594,160 @@ async def unmute(ctx, user: discord.User):
|
|||||||
mute_role = discord.utils.get(ctx.guild.roles, name=guild_settings["mute_role_name"])
|
mute_role = discord.utils.get(ctx.guild.roles, name=guild_settings["mute_role_name"])
|
||||||
|
|
||||||
if not mute_role or mute_role not in member.roles:
|
if not mute_role or mute_role not in member.roles:
|
||||||
await ctx.send("❌ Benutzer ist nicht gemutet.")
|
embed = discord.Embed(
|
||||||
|
title="❌ User Not Muted",
|
||||||
|
description="This user is not currently muted.",
|
||||||
|
color=0xff0000
|
||||||
|
)
|
||||||
|
await send_response(embed=embed, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Entferne Mute-Rolle
|
# Find active mute records in user_mutes table
|
||||||
await member.remove_roles(mute_role, reason=f"Unmuted by {ctx.author}")
|
connection = None
|
||||||
|
cursor = None
|
||||||
|
active_mute_records = []
|
||||||
|
|
||||||
# Stelle Rollen wieder her
|
try:
|
||||||
await restore_user_roles(member, ctx.guild)
|
connection = connect_to_database()
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
# Get active mute records for this user
|
||||||
|
select_query = """
|
||||||
|
SELECT id, process_uuid, reason, start_time, end_time, duration
|
||||||
|
FROM user_mutes
|
||||||
|
WHERE user_id = %s AND guild_id = %s AND aktiv = TRUE AND status = 'active'
|
||||||
|
ORDER BY start_time DESC
|
||||||
|
"""
|
||||||
|
|
||||||
|
cursor.execute(select_query, (user.id, ctx.guild.id))
|
||||||
|
results = cursor.fetchall()
|
||||||
|
|
||||||
|
for result in results:
|
||||||
|
mute_id, process_uuid, reason, start_time, end_time, duration = result
|
||||||
|
active_mute_records.append({
|
||||||
|
'id': mute_id,
|
||||||
|
'process_uuid': process_uuid,
|
||||||
|
'reason': reason,
|
||||||
|
'start_time': start_time,
|
||||||
|
'end_time': end_time,
|
||||||
|
'duration': duration
|
||||||
|
})
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if cursor:
|
||||||
|
cursor.close()
|
||||||
|
if connection:
|
||||||
|
close_database_connection(connection)
|
||||||
|
|
||||||
# Finde und aktualisiere aktiven Mute-Prozess
|
if not active_mute_records:
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="❌ No Active Mutes Found",
|
||||||
|
description="No active mute records found for this user in the database.",
|
||||||
|
color=0xff0000
|
||||||
|
)
|
||||||
|
await send_response(embed=embed, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Remove mute role
|
||||||
|
await member.remove_roles(mute_role, reason=f"Manually unmuted by {ctx.author}")
|
||||||
|
|
||||||
|
# Restore user roles
|
||||||
|
try:
|
||||||
|
restored_roles = await restore_user_roles(member, ctx.guild)
|
||||||
|
restored_count = len(restored_roles) if restored_roles else 0
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Could not restore roles for user {user.id}: {e}")
|
||||||
|
restored_count = 0
|
||||||
|
|
||||||
|
# Deactivate all active mute records
|
||||||
|
deactivated_mutes = []
|
||||||
|
for mute_record in active_mute_records:
|
||||||
|
try:
|
||||||
|
await deactivate_mute(mute_record['id'], unmuted_by=ctx.author.id, auto_unmuted=False)
|
||||||
|
deactivated_mutes.append(mute_record)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error deactivating mute record {mute_record['id']}: {e}")
|
||||||
|
|
||||||
|
# Cancel active processes
|
||||||
|
cancelled_processes = []
|
||||||
active_processes = get_active_processes(process_type="mute", guild_id=ctx.guild.id)
|
active_processes = get_active_processes(process_type="mute", guild_id=ctx.guild.id)
|
||||||
for process in active_processes:
|
for process in active_processes:
|
||||||
if process["target_id"] == user.id:
|
if process["target_id"] == user.id:
|
||||||
update_process_status(process["uuid"], "cancelled_manual")
|
update_process_status(process["uuid"], "cancelled")
|
||||||
break
|
cancelled_processes.append(process["uuid"])
|
||||||
|
|
||||||
# Erstelle Embed
|
# Create success embed
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="🔊 Benutzer entmutet",
|
title="🔊 User Unmuted Successfully",
|
||||||
description=f"{user.mention} wurde entmutet.",
|
description=f"{user.mention} has been manually unmuted.",
|
||||||
color=0x00ff00,
|
color=0x00ff00,
|
||||||
timestamp=datetime.now()
|
timestamp=datetime.now()
|
||||||
)
|
)
|
||||||
embed.add_field(name="Moderator", value=ctx.author.mention, inline=True)
|
|
||||||
embed.set_footer(text=f"User ID: {user.id}")
|
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
embed.add_field(name="👮 Moderator", value=ctx.author.mention, inline=True)
|
||||||
|
embed.add_field(name="🔓 Mutes Deactivated", value=str(len(deactivated_mutes)), inline=True)
|
||||||
|
|
||||||
|
if restored_count > 0:
|
||||||
|
embed.add_field(name="🎭 Roles Restored", value=str(restored_count), inline=True)
|
||||||
|
|
||||||
|
# Show deactivated mute details
|
||||||
|
if deactivated_mutes:
|
||||||
|
mute_details = []
|
||||||
|
for mute in deactivated_mutes[:3]: # Show first 3 mutes
|
||||||
|
mute_info = f"**ID {mute['id']}**: {mute['reason'][:30]}{'...' if len(mute['reason']) > 30 else ''}"
|
||||||
|
mute_info += f" ({mute['duration']})"
|
||||||
|
mute_details.append(mute_info)
|
||||||
|
|
||||||
|
if len(deactivated_mutes) > 3:
|
||||||
|
mute_details.append(f"*+{len(deactivated_mutes) - 3} more mutes deactivated*")
|
||||||
|
|
||||||
|
embed.add_field(name="📋 Deactivated Mutes", value="\n".join(mute_details), inline=False)
|
||||||
|
|
||||||
|
embed.set_footer(text=f"User ID: {user.id} | {len(cancelled_processes)} process(es) cancelled")
|
||||||
|
embed.set_thumbnail(url=user.display_avatar.url)
|
||||||
|
|
||||||
|
await send_response(embed=embed)
|
||||||
|
|
||||||
# Log the action
|
# Log the action
|
||||||
logger.info(f"User {user.id} unmuted by {ctx.author.id} in guild {ctx.guild.id}")
|
log_additional_info = {
|
||||||
|
"Mutes Deactivated": str(len(deactivated_mutes)),
|
||||||
|
"Roles Restored": str(restored_count),
|
||||||
|
"Processes Cancelled": str(len(cancelled_processes))
|
||||||
|
}
|
||||||
|
|
||||||
|
await log_moderation_action(
|
||||||
|
guild=ctx.guild,
|
||||||
|
action_type="unmute",
|
||||||
|
moderator=ctx.author,
|
||||||
|
target_user=user,
|
||||||
|
reason="Manual unmute",
|
||||||
|
additional_info=log_additional_info
|
||||||
|
)
|
||||||
|
|
||||||
|
# Try to DM the user
|
||||||
|
try:
|
||||||
|
dm_embed = discord.Embed(
|
||||||
|
title="🔊 You have been unmuted",
|
||||||
|
description=f"Your mute in **{ctx.guild.name}** has been manually removed by a moderator.",
|
||||||
|
color=0x00ff00,
|
||||||
|
timestamp=datetime.now()
|
||||||
|
)
|
||||||
|
dm_embed.add_field(name="👮 Unmuted by", value=ctx.author.mention, inline=True)
|
||||||
|
dm_embed.set_footer(text=f"Server: {ctx.guild.name}")
|
||||||
|
await user.send(embed=dm_embed)
|
||||||
|
except (discord.Forbidden, discord.NotFound):
|
||||||
|
pass # User has DMs disabled or doesn't exist
|
||||||
|
|
||||||
|
logger.info(f"User {user.id} manually unmuted by {ctx.author.id} in guild {ctx.guild.id} - {len(deactivated_mutes)} mute(s) deactivated")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error in unmute command: {e}")
|
logger.error(f"Error in unmute command: {e}")
|
||||||
await ctx.send("❌ Ein Fehler ist aufgetreten beim Entmuten des Benutzers.")
|
embed = discord.Embed(
|
||||||
|
title="❌ Error",
|
||||||
|
description="An error occurred while unmuting the user.",
|
||||||
|
color=0xff0000
|
||||||
|
)
|
||||||
|
await send_response(embed=embed, ephemeral=True)
|
||||||
|
|
||||||
@client.hybrid_command()
|
@client.hybrid_command()
|
||||||
async def listmutes(ctx, status: str = "active"):
|
async def listmutes(ctx, status: str = "active"):
|
||||||
|
|||||||
Reference in New Issue
Block a user