From dfcab5eb6dd07c6485b09a12fa7a7ff0674de1f1 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 5 Jun 2025 16:59:09 +0000 Subject: [PATCH] Improve logging display --- cogs/logging_cog.py | 38 ++++++++++++++++------------ cogs/mod_log_cog.py | 50 ++++++++++++++++++++++++++----------- cogs/real_moderation_cog.py | 37 ++++++++++++++++----------- cogs/role_management_cog.py | 6 +++-- 4 files changed, 84 insertions(+), 47 deletions(-) diff --git a/cogs/logging_cog.py b/cogs/logging_cog.py index 66c9a6c..a5e4390 100644 --- a/cogs/logging_cog.py +++ b/cogs/logging_cog.py @@ -54,6 +54,12 @@ class LoggingCog(commands.Cog): else: asyncio.create_task(self.start_audit_log_poller_when_ready()) # Keep this for initial start + def _user_display(self, user: Union[discord.Member, discord.User]) -> str: + """Return display name, username and ID string for a user.""" + display = user.display_name if isinstance(user, discord.Member) else user.name + username = f"{user.name}#{user.discriminator}" + return f"{display} ({username}) [ID: {user.id}]" + async def initialize_cog(self): """Asynchronous initialization tasks.""" log.info("Initializing LoggingCog...") @@ -418,7 +424,7 @@ class LoggingCog(commands.Cog): user = await self.bot.fetch_user(member.id) # Get user object embed = self._create_log_embed( title="โž• Member Joined Thread", - description=f"{user.mention} joined thread {thread.mention}.", + description=f"{self._user_display(user)} joined thread {thread.mention}.", color=discord.Color.dark_green(), author=user, footer=f"Thread ID: {thread.id} | User ID: {user.id}" @@ -435,7 +441,7 @@ class LoggingCog(commands.Cog): user = await self.bot.fetch_user(member.id) # Get user object embed = self._create_log_embed( title="โž– Member Left Thread", - description=f"{user.mention} left thread {thread.mention}.", + description=f"{self._user_display(user)} left thread {thread.mention}.", color=discord.Color.dark_orange(), author=user, footer=f"Thread ID: {thread.id} | User ID: {user.id}" @@ -509,7 +515,7 @@ class LoggingCog(commands.Cog): embed = self._create_log_embed( title="๐Ÿ“ฅ Member Joined", - description=f"{member.mention} ({member.id}) joined the server.", + description=f"{self._user_display(member)} joined the server.", color=discord.Color.green(), author=member # Footer already includes User ID via _create_log_embed @@ -527,7 +533,7 @@ class LoggingCog(commands.Cog): # We log it as a generic "left" event here. embed = self._create_log_embed( title="๐Ÿ“ค Member Left", - description=f"{member.mention} left the server.", + description=f"{self._user_display(member)} left the server.", color=discord.Color.orange(), author=member ) @@ -542,7 +548,7 @@ class LoggingCog(commands.Cog): # Note: Ban reason isn't available directly in this event. Audit log might have it. embed = self._create_log_embed( title="๐Ÿ”จ Member Banned (Event)", # Clarify this is the event, audit log has more details - description=f"{user.mention} was banned.\n*Audit log may contain moderator and reason.*", + description=f"{self._user_display(user)} was banned.\n*Audit log may contain moderator and reason.*", color=discord.Color.red(), author=user # User who was banned ) @@ -556,7 +562,7 @@ class LoggingCog(commands.Cog): embed = self._create_log_embed( title="๐Ÿ”“ Member Unbanned", - description=f"{user.mention} was unbanned.", + description=f"{self._user_display(user)} was unbanned.", color=discord.Color.blurple(), author=user # User who was unbanned ) @@ -841,7 +847,7 @@ class LoggingCog(commands.Cog): embed = self._create_log_embed( title="๐Ÿ‘ Reaction Added", - description=f"{user.mention} added {reaction.emoji} to a message by {reaction.message.author.mention} in {reaction.message.channel.mention} [Jump to Message]({reaction.message.jump_url})", + description=f"{self._user_display(user)} added {reaction.emoji} to a message by {self._user_display(reaction.message.author)} in {reaction.message.channel.mention} [Jump to Message]({reaction.message.jump_url})", color=discord.Color.gold(), author=user ) @@ -860,7 +866,7 @@ class LoggingCog(commands.Cog): embed = self._create_log_embed( title="๐Ÿ‘Ž Reaction Removed", - description=f"{user.mention} removed {reaction.emoji} from a message by {reaction.message.author.mention} in {reaction.message.channel.mention} [Jump to Message]({reaction.message.jump_url})", + description=f"{self._user_display(user)} removed {reaction.emoji} from a message by {self._user_display(reaction.message.author)} in {reaction.message.channel.mention} [Jump to Message]({reaction.message.jump_url})", color=discord.Color.dark_gold(), author=user ) @@ -959,7 +965,7 @@ class LoggingCog(commands.Cog): embed = self._create_log_embed( title=action, - description=f"{member.mention}\n{details}", + description=f"{self._user_display(member)}\n{details}", color=color, author=member ) @@ -1264,21 +1270,21 @@ class LoggingCog(commands.Cog): audit_event_key = "audit_ban" if not await self._check_log_enabled(guild.id, audit_event_key): return title = "๐Ÿ›ก๏ธ Audit Log: Member Banned" - action_desc = f"{user.mention} banned {target.mention}" + action_desc = f"{self._user_display(user)} banned {self._user_display(target)}" color = discord.Color.red() # self._add_id_footer(embed, target, id_name="Target ID") # Footer set later elif entry.action == discord.AuditLogAction.unban: audit_event_key = "audit_unban" if not await self._check_log_enabled(guild.id, audit_event_key): return title = "๐Ÿ›ก๏ธ Audit Log: Member Unbanned" - action_desc = f"{user.mention} unbanned {target.mention}" + action_desc = f"{self._user_display(user)} unbanned {self._user_display(target)}" color = discord.Color.blurple() # self._add_id_footer(embed, target, id_name="Target ID") # Footer set later elif entry.action == discord.AuditLogAction.kick: audit_event_key = "audit_kick" if not await self._check_log_enabled(guild.id, audit_event_key): return title = "๐Ÿ›ก๏ธ Audit Log: Member Kicked" - action_desc = f"{user.mention} kicked {target.mention}" + action_desc = f"{self._user_display(user)} kicked {self._user_display(target)}" color = discord.Color.brand_red() # self._add_id_footer(embed, target, id_name="Target ID") # Footer set later elif entry.action == discord.AuditLogAction.member_prune: @@ -1287,7 +1293,7 @@ class LoggingCog(commands.Cog): title = "๐Ÿ›ก๏ธ Audit Log: Member Prune" days = entry.extra.get('delete_member_days') count = entry.extra.get('members_removed') - action_desc = f"{user.mention} pruned {count} members inactive for {days} days." + action_desc = f"{self._user_display(user)} pruned {count} members inactive for {days} days." color = discord.Color.dark_red() # No specific target ID here @@ -1301,7 +1307,7 @@ class LoggingCog(commands.Cog): added = [r.mention for r in after_roles if r not in before_roles] removed = [r.mention for r in before_roles if r not in after_roles] if added or removed: # Only log if roles actually changed - action_desc = f"{user.mention} updated roles for {target.mention} ({target.id}):" + action_desc = f"{self._user_display(user)} updated roles for {self._user_display(target)} ({target.id}):" if added: action_desc += f"\n**Added:** {', '.join(added)}" if removed: action_desc += f"\n**Removed:** {', '.join(removed)}" color = discord.Color.blue() @@ -1317,10 +1323,10 @@ class LoggingCog(commands.Cog): title = "๐Ÿ›ก๏ธ Audit Log: Member Timeout Update" if after_timed_out: timeout_duration = discord.utils.format_dt(after_timed_out, style='R') - action_desc = f"{user.mention} timed out {target.mention} ({target.id}) until {timeout_duration}" + action_desc = f"{self._user_display(user)} timed out {self._user_display(target)} ({target.id}) until {timeout_duration}" color = discord.Color.orange() else: - action_desc = f"{user.mention} removed timeout from {target.mention} ({target.id})" + action_desc = f"{self._user_display(user)} removed timeout from {self._user_display(target)} ({target.id})" color = discord.Color.green() # self._add_id_footer(embed, target, id_name="Target ID") # Footer set later else: diff --git a/cogs/mod_log_cog.py b/cogs/mod_log_cog.py index 95d35e9..f518967 100644 --- a/cogs/mod_log_cog.py +++ b/cogs/mod_log_cog.py @@ -32,6 +32,34 @@ class ModLogCog(commands.Cog): # Add command group to the bot's tree self.bot.tree.add_command(self.modlog_group) + def _format_user(self, user: Union[Member, User, Object], guild: Optional[discord.Guild] = None) -> str: + """Return a string with display name, username and ID for a user-like object.""" + if isinstance(user, Object): + return f"Unknown User (ID: {user.id})" + if isinstance(user, Member): + display = user.display_name + elif guild and isinstance(user, User): + member = guild.get_member(user.id) + display = member.display_name if member else user.name + else: + display = user.name + username = f"{user.name}#{user.discriminator}" if isinstance(user, (Member, User)) else "Unknown" + return f"{display} ({username}) [ID: {user.id}]" + + async def _fetch_user_display(self, user_id: int, guild: discord.Guild) -> str: + """Fetch and format a user by ID for display.""" + member = guild.get_member(user_id) + if member: + return self._format_user(member, guild) + user = self.bot.get_user(user_id) + if user: + return self._format_user(user, guild) + try: + user = await self.bot.fetch_user(user_id) + return self._format_user(user, guild) + except discord.HTTPException: + return f"Unknown User (ID: {user_id})" + def register_commands(self): """Register all commands for this cog""" @@ -251,23 +279,12 @@ class ModLogCog(commands.Cog): timestamp=discord.utils.utcnow() ) - # Handle target display - check if it's a Discord Object or User/Member - if isinstance(target, discord.Object): - # For Object, we only have the ID - target_display = f"<@{target.id}> ({target.id})" - else: - # For User/Member, we can use mention - target_display = f"{target.mention} ({target.id})" + target_display = self._format_user(target, guild) - # Determine moderator display based on source if source == "AI_API": moderator_display = f"AI System (ID: {moderator_id_override or 'Unknown'})" - elif isinstance(moderator, discord.Object): - # For Object, we only have the ID - moderator_display = f"<@{moderator.id}> ({moderator.id})" else: - # For User/Member, we can use mention - moderator_display = f"{moderator.mention} ({moderator.id})" + moderator_display = self._format_user(moderator, guild) embed.add_field(name="User", value=target_display, inline=True) @@ -359,9 +376,14 @@ class ModLogCog(commands.Cog): timestamp_str = record['timestamp'].strftime('%Y-%m-%d %H:%M:%S') reason_str = record['reason'] or "N/A" duration_str = f" ({record['duration_seconds']}s)" if record['duration_seconds'] else "" + target_disp = await self._fetch_user_display(record['target_user_id'], interaction.guild) + if record['moderator_id'] == 0: + mod_disp = "AI System" + else: + mod_disp = await self._fetch_user_display(record['moderator_id'], interaction.guild) response_lines.append( f"`Case #{record['case_id']}` [{timestamp_str}] **{record['action_type']}** " - f"Target: <@{record['target_user_id']}> Mod: <@{record['moderator_id']}> " + f"Target: {target_disp} Mod: {mod_disp} " f"Reason: {reason_str}{duration_str}" ) diff --git a/cogs/real_moderation_cog.py b/cogs/real_moderation_cog.py index 249c9a4..e6a05b9 100644 --- a/cogs/real_moderation_cog.py +++ b/cogs/real_moderation_cog.py @@ -30,6 +30,12 @@ class ModerationCog(commands.Cog): # Add command group to the bot's tree self.bot.tree.add_command(self.moderate_group) + def _user_display(self, user: Union[discord.Member, discord.User]) -> str: + """Return display name, username and ID string for a user.""" + display = user.display_name if isinstance(user, discord.Member) else user.name + username = f"{user.name}#{user.discriminator}" + return f"{display} ({username}) [ID: {user.id}]" + def register_commands(self): """Register all commands for this cog""" @@ -285,11 +291,12 @@ class ModerationCog(commands.Cog): # ------------------------- # Send confirmation message with DM status + target_text = self._user_display(member) if send_dm: dm_status = "โœ… DM notification sent" if dm_sent else "โŒ Could not send DM notification (user may have DMs disabled)" - await interaction.response.send_message(f"๐Ÿ”จ **Banned {member.mention}**! Reason: {reason or 'No reason provided'}\n{dm_status}") + await interaction.response.send_message(f"๐Ÿ”จ **Banned {target_text}**! Reason: {reason or 'No reason provided'}\n{dm_status}") else: - await interaction.response.send_message(f"๐Ÿ”จ **Banned {member.mention}**! Reason: {reason or 'No reason provided'}\nโš ๏ธ DM notification was disabled") + await interaction.response.send_message(f"๐Ÿ”จ **Banned {target_text}**! Reason: {reason or 'No reason provided'}\nโš ๏ธ DM notification was disabled") except discord.Forbidden: await interaction.response.send_message("โŒ I don't have permission to ban this member.", ephemeral=True) except discord.HTTPException as e: @@ -349,7 +356,7 @@ class ModerationCog(commands.Cog): # ------------------------- # Send confirmation message - await interaction.response.send_message(f"๐Ÿ”“ **Unbanned {banned_user}**! Reason: {reason or 'No reason provided'}") + await interaction.response.send_message(f"๐Ÿ”“ **Unbanned {self._user_display(banned_user)}**! Reason: {reason or 'No reason provided'}") except discord.Forbidden: await interaction.response.send_message("โŒ I don't have permission to unban this user.", ephemeral=True) except discord.HTTPException as e: @@ -429,7 +436,7 @@ class ModerationCog(commands.Cog): # Send confirmation message with DM status dm_status = "โœ… DM notification sent" if dm_sent else "โŒ Could not send DM notification (user may have DMs disabled)" - await interaction.response.send_message(f"๐Ÿ‘ข **Kicked {member.mention}**! Reason: {reason or 'No reason provided'}\n{dm_status}") + await interaction.response.send_message(f"๐Ÿ‘ข **Kicked {self._user_display(member)}**! Reason: {reason or 'No reason provided'}\n{dm_status}") except discord.Forbidden: await interaction.response.send_message("โŒ I don't have permission to kick this member.", ephemeral=True) except discord.HTTPException as e: @@ -541,7 +548,7 @@ class ModerationCog(commands.Cog): # Send confirmation message with DM status dm_status = "โœ… DM notification sent" if dm_sent else "โŒ Could not send DM notification (user may have DMs disabled)" - await safe_followup(f"โฐ **Timed out {member.mention}** for {duration}! Reason: {reason or 'No reason provided'}\n{dm_status}") + await safe_followup(f"โฐ **Timed out {self._user_display(member)}** for {duration}! Reason: {reason or 'No reason provided'}\n{dm_status}") except discord.Forbidden: await safe_followup("โŒ I don't have permission to timeout this member.", ephemeral=True) except discord.HTTPException as e: @@ -606,7 +613,7 @@ class ModerationCog(commands.Cog): # Send confirmation message with DM status dm_status = "โœ… DM notification sent" if dm_sent else "โŒ Could not send DM notification (user may have DMs disabled)" - await interaction.response.send_message(f"โฐ **Removed timeout from {member.mention}**! Reason: {reason or 'No reason provided'}\n{dm_status}") + await interaction.response.send_message(f"โฐ **Removed timeout from {self._user_display(member)}**! Reason: {reason or 'No reason provided'}\n{dm_status}") except discord.Forbidden: await interaction.response.send_message("โŒ I don't have permission to remove the timeout from this member.", ephemeral=True) except discord.HTTPException as e: @@ -645,7 +652,7 @@ class ModerationCog(commands.Cog): logger.info(f"{len(deleted)} messages from user {user} (ID: {user.id}) were purged from channel {interaction.channel.name} (ID: {interaction.channel.id}) in {interaction.guild.name} (ID: {interaction.guild.id}) by {interaction.user} (ID: {interaction.user.id}).") # Send confirmation message - await interaction.followup.send(f"๐Ÿงน **Purged {len(deleted)} messages** from {user.mention}!", ephemeral=True) + await interaction.followup.send(f"๐Ÿงน **Purged {len(deleted)} messages** from {self._user_display(user)}!", ephemeral=True) else: # Delete messages from anyone deleted = await interaction.channel.purge(limit=amount) @@ -699,7 +706,7 @@ class ModerationCog(commands.Cog): # ------------------------- # Send warning message in the channel - await interaction.response.send_message(f"โš ๏ธ **{member.mention} has been warned**! Reason: {reason}") + await interaction.response.send_message(f"โš ๏ธ **{self._user_display(member)} has been warned**! Reason: {reason}") # Try to DM the user about the warning try: @@ -788,7 +795,7 @@ class ModerationCog(commands.Cog): infractions = await mod_log_db.get_user_mod_logs(self.bot.pg_pool, interaction.guild.id, member.id) if not infractions: - await interaction.response.send_message(f"No infractions found for {member.mention}.", ephemeral=True) + await interaction.response.send_message(f"No infractions found for {self._user_display(member)}.", ephemeral=True) return embed = discord.Embed( @@ -901,11 +908,11 @@ class ModerationCog(commands.Cog): reason=f"Cleared {deleted_count} infractions. Reason: {reason or 'Not specified'}", duration=None ) - await interaction_confirm.response.edit_message(content=f"โœ… Successfully cleared {deleted_count} infractions for {member.mention}. Reason: {reason or 'Not specified'}", view=None) + await interaction_confirm.response.edit_message(content=f"โœ… Successfully cleared {deleted_count} infractions for {self._user_display(member)}. Reason: {reason or 'Not specified'}", view=None) elif deleted_count == 0: - await interaction_confirm.response.edit_message(content=f"โ„น๏ธ No infractions found for {member.mention} to clear.", view=None) + await interaction_confirm.response.edit_message(content=f"โ„น๏ธ No infractions found for {self._user_display(member)} to clear.", view=None) else: # Should not happen if 0 is returned for no logs - await interaction_confirm.response.edit_message(content=f"โŒ Failed to clear infractions for {member.mention}. An error occurred.", view=None) + await interaction_confirm.response.edit_message(content=f"โŒ Failed to clear infractions for {self._user_display(member)}. An error occurred.", view=None) async def cancel_callback(interaction_cancel: discord.Interaction): if interaction_cancel.user.id != interaction.user.id: @@ -919,7 +926,7 @@ class ModerationCog(commands.Cog): view.add_item(cancel_button) await interaction.response.send_message( - f"โš ๏ธ Are you sure you want to clear **ALL** infractions for {member.mention}?\n" + f"โš ๏ธ Are you sure you want to clear **ALL** infractions for {self._user_display(member)}?\n" f"This action is irreversible. Reason: {reason or 'Not specified'}", view=view, ephemeral=True @@ -1044,7 +1051,7 @@ class ModerationCog(commands.Cog): # Send confirmation message with DM status dm_status = "โœ… DM notification sent" if dm_sent else "โŒ Could not send DM notification (user may have DMs disabled)" - await ctx.reply(f"โฐ **Timed out {member.mention}** for {duration}! Reason: {reason or 'No reason provided'}\n{dm_status}") + await ctx.reply(f"โฐ **Timed out {self._user_display(member)}** for {duration}! Reason: {reason or 'No reason provided'}\n{dm_status}") except discord.Forbidden: await ctx.reply("โŒ I don't have permission to timeout this member.") except discord.HTTPException as e: @@ -1124,7 +1131,7 @@ class ModerationCog(commands.Cog): # Send confirmation message with DM status dm_status = "โœ… DM notification sent" if dm_sent else "โŒ Could not send DM notification (user may have DMs disabled)" - await ctx.reply(f"โฐ **Removed timeout from {member.mention}**! Reason: {reason or 'No reason provided'}\n{dm_status}") + await ctx.reply(f"โฐ **Removed timeout from {self._user_display(member)}**! Reason: {reason or 'No reason provided'}\n{dm_status}") except discord.Forbidden: await ctx.reply("โŒ I don't have permission to remove the timeout from this member.") except discord.HTTPException as e: diff --git a/cogs/role_management_cog.py b/cogs/role_management_cog.py index be63fef..f678ef3 100644 --- a/cogs/role_management_cog.py +++ b/cogs/role_management_cog.py @@ -439,9 +439,10 @@ class RoleManagementCog(commands.Cog): # Attempt to DM the user try: + role_info = f"{role.name} (ID: {role.id})" dm_embed = discord.Embed( title="Role Added", - description=f"The role {role.mention} was added to you in **{interaction.guild.name}**.", + description=f"The role {role_info} was added to you in **{interaction.guild.name}**.", color=role.color ) dm_embed.add_field(name="Added by", value=interaction.user.mention, inline=True) @@ -506,9 +507,10 @@ class RoleManagementCog(commands.Cog): # Attempt to DM the user try: + role_info = f"{role.name} (ID: {role.id})" dm_embed = discord.Embed( title="Role Removed", - description=f"The role {role.mention} was removed from you in **{interaction.guild.name}**.", + description=f"The role {role_info} was removed from you in **{interaction.guild.name}**.", color=role.color ) dm_embed.add_field(name="Removed by", value=interaction.user.mention, inline=True)