modified: bot.py

This commit is contained in:
SimolZimol
2026-06-15 22:41:28 +02:00
parent 7edf0e34a6
commit 7b8c82869c

218
bot.py
View File

@@ -2894,12 +2894,33 @@ async def on_message(message):
member_role_ids = {role.id for role in member.roles}
if not (ignore_role_ids & member_role_ids):
archived_message_data = {
"id": message.id,
"channel_id": message.channel.id,
"author_id": member.id,
"author_name": str(member),
"content": message.content,
"attachments": json.dumps(
[
{
"filename": a.filename,
"url": a.url,
"content_type": a.content_type,
"size": a.size
}
for a in message.attachments
]
) if message.attachments else "[]"
}
try:
await message.delete()
except Exception:
pass
action_taken = None
honeypot_mute_id = None
acc_age_min = int(guild_settings.get("honeypot_acc_age_min") or 30)
preserve = guild_settings.get("honeypot_preserve_old_accounts", False)
@@ -2913,7 +2934,7 @@ async def on_message(message):
if is_old_account:
try:
result = await apply_mute_action(
result = await apply_full_mute(
guild=message.guild,
member=member,
moderator=client.user,
@@ -2921,14 +2942,16 @@ async def on_message(message):
duration_label="365d",
reason="Honeypot: wrote in honeypot channel (protected old member)",
source_channel=message.channel,
message_data=None,
message_data=archived_message_data,
message_id=message.id,
remove_existing_roles=False,
save_removed_roles=False,
send_dm=True,
log_action=True,
remove_existing_roles=True,
save_current_roles=True,
increment_mute_count=True
)
action_taken = "mute"
honeypot_mute_id = result["mute_id"]
action_taken = "mute"
except discord.Forbidden:
logger.warning(f"Honeypot: no permission to mute {member.id} in guild {guild_id}")
except Exception as e:
@@ -2964,7 +2987,7 @@ async def on_message(message):
embed.add_field(name="User", value=f"{member} (`{member.id}`)", inline=True)
embed.add_field(name="Channel", value=f"<#{message.channel.id}>", inline=True)
if action_taken == "mute":
if honeypot_mute_id:
embed.add_field(name="Mute Record ID", value=f"`{honeypot_mute_id}`", inline=True)
if preserve:
@@ -6484,7 +6507,7 @@ async def mute(
context_range: int = 3,
silent: bool = False
):
"""Mute a user for a specified duration."""
"""Mutes a user for a specified duration (Requires Permission Level 5 or higher)."""
is_slash_command = hasattr(ctx, "interaction") and ctx.interaction is not None
@@ -6503,17 +6526,16 @@ async def mute(
else:
await ctx.send(content=content, embed=embed, file=file)
except Exception as e:
logger.error(f"Error sending mute response: {e}")
logger.error(f"Error sending response in mute command: {e}")
try:
if embed:
await ctx.send(embed=embed)
elif content:
await ctx.send(content)
await ctx.send(content=content)
except Exception as fallback_error:
logger.error(f"Fallback send failed: {fallback_error}")
logger.error(f"Fallback send also failed: {fallback_error}")
try:
original_reason = reason
message_data = None
parsed_context_range = 3
@@ -6523,16 +6545,13 @@ async def mute(
potential_context = reason_words[-1]
if (
potential_msg_id
and 17 <= len(potential_msg_id) <= 20
and potential_msg_id.isdigit()
and potential_context
and len(potential_context) <= 3
and potential_context.isdigit()
potential_msg_id and 17 <= len(potential_msg_id) <= 20 and potential_msg_id.isdigit()
and potential_context and len(potential_context) <= 3 and potential_context.isdigit()
):
parsed_context_range = int(potential_context)
message_id = potential_msg_id
reason = " ".join(reason_words[:-2])
elif len(reason_words) >= 1:
potential_msg_id = reason_words[-1]
if 17 <= len(potential_msg_id) <= 20 and potential_msg_id.isdigit():
@@ -6610,7 +6629,7 @@ async def mute(
await send_response(embed=embed, ephemeral=True)
return
result = await apply_mute_action(
result = await apply_full_mute(
guild=ctx.guild,
member=member,
moderator=ctx.author,
@@ -6620,15 +6639,16 @@ async def mute(
source_channel=ctx.channel,
message_data=message_data,
message_id=int(message_id) if message_id else None,
send_dm=True,
log_action=True,
remove_existing_roles=True,
save_removed_roles=True,
save_current_roles=True,
increment_mute_count=True
)
end_time = result["end_time"]
mute_id = result["mute_id"]
process_uuid = result["process_uuid"]
mute_role = result["mute_role"]
user_data = result["user_data"]
embed = discord.Embed(
@@ -6641,18 +6661,22 @@ async def mute(
embed.add_field(name="⏰ Ends At", value=f"<t:{int(end_time.timestamp())}:F>", inline=True)
embed.add_field(name="📝 Reason", value=reason or "No reason provided", inline=False)
embed.add_field(name="👮 Moderator", value=ctx.author.mention, inline=True)
embed.add_field(name="🔇 Mute Count", value=str(user_data["mutes"]), inline=True)
embed.add_field(name="🔇 Mute Count", value=f"{user_data['mutes']}", inline=True)
if message_data:
if isinstance(message_data, dict) and "main_message" in message_data:
main_msg = message_data.get("main_message")
context_msgs = message_data.get("context_messages", [])
if main_msg:
message_info = f"**Message ID:** `{main_msg['id']}`\n"
message_info += f"**Channel:** <#{main_msg['channel_id']}>\n"
message_info += f"**Author:** {main_msg['author_name']}\n"
if main_msg.get("content"):
content_preview = main_msg["content"][:200] + "..." if len(main_msg["content"]) > 200 else main_msg["content"]
message_info += f"**Content:** {content_preview}"
embed.add_field(name="📄 Referenced Message", value=message_info, inline=False)
if main_msg.get("attachments"):
@@ -6660,7 +6684,7 @@ async def mute(
attachments_data = json.loads(main_msg["attachments"])
if attachments_data:
attachment_info = ""
for i, att in enumerate(attachments_data[:3]):
for att in attachments_data[:3]:
attachment_info += f"{att.get('filename', 'Unknown file')}\n"
if len(attachments_data) > 3:
attachment_info += f"• +{len(attachments_data) - 3} more attachments"
@@ -6696,84 +6720,20 @@ async def mute(
silent_embed.add_field(name="⏱️ Duration", value=duration, inline=True)
silent_embed.add_field(name="⏰ Ends At", value=f"<t:{int(end_time.timestamp())}:F>", inline=True)
silent_embed.add_field(name="📝 Reason", value=reason or "No reason provided", inline=False)
silent_embed.add_field(name="🔇 Mute Count", value=str(user_data["mutes"]), inline=True)
silent_embed.add_field(name="🔇 Mute Count", value=f"{user_data['mutes']}", inline=True)
silent_embed.add_field(name="🆔 Mute Record ID", value=f"`{mute_id}`", inline=True)
silent_embed.add_field(
name="🔔 Actions Taken",
value="• User muted\n• User received DM notification if possible\n• Mod log entry created\n• No public announcement",
value="• User muted\n Roles saved\n User received DM notification if possible\n• Mod log entry created\n• No public announcement",
inline=False
)
silent_embed.set_footer(text=f"Silent Mode • User ID: {user.id} | Use /viewmute {mute_id} for details")
silent_embed.set_thumbnail(url=user.display_avatar.url)
try:
if is_slash_command:
if hasattr(ctx, "followup") and ctx.followup is not None:
await ctx.followup.send(embed=silent_embed, ephemeral=True)
elif hasattr(ctx, "interaction") and ctx.interaction:
await ctx.interaction.followup.send(embed=silent_embed, ephemeral=True)
else:
raise RuntimeError("No followup available after defer")
else:
await ctx.send(embed=silent_embed)
except Exception as e:
logger.error(f"Error sending silent mute response: {e}")
else:
await send_response(embed=embed)
await send_response(embed=silent_embed, ephemeral=True)
return
log_additional_info = {
"Mute Count": str(user_data["mutes"]),
"Process ID": str(process_uuid)[:8],
"Mute Record ID": str(mute_id)
}
if message_data:
if isinstance(message_data, dict) and "main_message" in message_data:
main_msg = message_data.get("main_message")
if main_msg:
log_additional_info["Referenced Message"] = f"ID: {main_msg['id']} in <#{main_msg['channel_id']}>"
else:
log_additional_info["Referenced Message"] = f"ID: {message_data['id']} in <#{message_data['channel_id']}>"
await log_moderation_action(
guild=ctx.guild,
action_type="mute",
moderator=ctx.author,
target_user=user,
reason=reason,
duration=duration,
additional_info=log_additional_info
)
try:
dm_embed = discord.Embed(
title="🔇 You have been muted",
description=f"You have been muted in **{ctx.guild.name}**",
color=0xff0000,
timestamp=datetime.now()
)
dm_embed.add_field(name="⏱️ Duration", value=duration, inline=True)
dm_embed.add_field(name="⏰ Ends At", value=f"<t:{int(end_time.timestamp())}:F>", inline=True)
dm_embed.add_field(name="📝 Reason", value=reason or "No reason provided", inline=False)
dm_embed.add_field(name="👮 Moderator", value=ctx.author.display_name, inline=True)
if message_data:
preview_content = None
if isinstance(message_data, dict) and "main_message" in message_data:
main_msg = message_data.get("main_message")
if main_msg:
preview_content = main_msg.get("content")
else:
preview_content = message_data.get("content")
if preview_content:
content_preview = preview_content[:200] + "..." if len(preview_content) > 200 else preview_content
dm_embed.add_field(name="📄 Referenced Message", value=f"```{content_preview}```", inline=False)
dm_embed.set_footer(text=f"Server: {ctx.guild.name}")
await user.send(embed=dm_embed)
except discord.Forbidden:
pass
await send_response(embed=embed)
logger.info(f"User {user.id} muted by {ctx.author.id} in guild {ctx.guild.id} for {duration}. Reason: {reason}")
@@ -6786,8 +6746,7 @@ async def mute(
)
await send_response(embed=embed, ephemeral=True)
async def apply_mute_action(
async def apply_full_mute(
*,
guild: discord.Guild,
member: discord.Member,
@@ -6795,16 +6754,18 @@ async def apply_mute_action(
duration_seconds: int,
duration_label: str,
reason: str,
source_channel=None,
source_channel: discord.TextChannel | None = None,
message_data: dict | None = None,
message_id: int | None = None,
send_dm: bool = True,
log_action: bool = True,
remove_existing_roles: bool = True,
save_removed_roles: bool = True,
save_current_roles: bool = True,
increment_mute_count: bool = True
):
guild_settings = get_guild_settings(guild.id)
if save_removed_roles:
if save_current_roles:
await save_user_roles(member.id, guild.id, member.roles)
if remove_existing_roles:
@@ -6823,7 +6784,8 @@ async def apply_mute_action(
user_data["mutes"] += 1
update_user_data(member.id, guild.id, "mutes", user_data["mutes"])
end_time = datetime.now() + timedelta(seconds=duration_seconds)
start_time = datetime.now()
end_time = start_time + timedelta(seconds=duration_seconds)
process_data = {
"user_id": member.id,
@@ -6850,7 +6812,7 @@ async def apply_mute_action(
moderator_id=moderator.id,
reason=reason,
duration=duration_label,
start_time=datetime.now(),
start_time=start_time,
end_time=end_time,
process_uuid=process_uuid,
channel_id=source_channel.id if source_channel else None,
@@ -6859,9 +6821,69 @@ async def apply_mute_action(
message_id=message_id
)
if log_action:
additional_info = {
"Mute Count": str(user_data["mutes"]),
"Process ID": str(process_uuid)[:8],
"Mute Record ID": str(mute_id)
}
if message_data:
if isinstance(message_data, dict) and "main_message" in message_data:
main_msg = message_data.get("main_message")
if main_msg:
additional_info["Referenced Message"] = f"ID: {main_msg['id']} in <#{main_msg['channel_id']}>"
else:
if message_data.get("id") and message_data.get("channel_id"):
additional_info["Referenced Message"] = f"ID: {message_data['id']} in <#{message_data['channel_id']}>"
await log_moderation_action(
guild=guild,
action_type="mute",
moderator=moderator,
target_user=member,
reason=reason,
duration=duration_label,
additional_info=additional_info
)
if send_dm:
try:
dm_embed = discord.Embed(
title="🔇 You have been muted",
description=f"You have been muted in **{guild.name}**",
color=0xff0000,
timestamp=datetime.now()
)
dm_embed.add_field(name="⏱️ Duration", value=duration_label, inline=True)
dm_embed.add_field(name="⏰ Ends At", value=f"<t:{int(end_time.timestamp())}:F>", inline=True)
dm_embed.add_field(name="📝 Reason", value=reason or "No reason provided", inline=False)
dm_embed.add_field(name="👮 Moderator", value=getattr(moderator, "display_name", str(moderator)), inline=True)
preview_content = None
if message_data:
if isinstance(message_data, dict) and "main_message" in message_data:
main_msg = message_data.get("main_message")
if main_msg:
preview_content = main_msg.get("content")
else:
preview_content = message_data.get("content")
if preview_content:
content_preview = preview_content[:200] + "..." if len(preview_content) > 200 else preview_content
dm_embed.add_field(name="📄 Referenced Message", value=f"```{content_preview}```", inline=False)
dm_embed.set_footer(text=f"Server: {guild.name}")
await member.send(embed=dm_embed)
except discord.Forbidden:
pass
except Exception as e:
logger.error(f"Failed to DM muted user {member.id}: {e}")
return {
"mute_role": mute_role,
"user_data": user_data,
"start_time": start_time,
"end_time": end_time,
"process_uuid": process_uuid,
"mute_id": mute_id