Refactor log views to use embeds

This commit is contained in:
Codex 2025-06-06 03:51:45 +00:00 committed by Slipstream
parent 42d0fd3ae4
commit 207d294eb4
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD

View File

@ -1,6 +1,6 @@
import discord import discord
from discord.ext import commands, tasks from discord.ext import commands, tasks
from discord import ui, AllowedMentions from discord import AllowedMentions
import datetime import datetime
import asyncio import asyncio
import aiohttp # Added for webhook sending import aiohttp # Added for webhook sending
@ -56,8 +56,8 @@ class LoggingCog(commands.Cog):
else: else:
asyncio.create_task(self.start_audit_log_poller_when_ready()) # Keep this for initial start asyncio.create_task(self.start_audit_log_poller_when_ready()) # Keep this for initial start
class LogView(ui.LayoutView): class LogView(discord.Embed):
"""View for logging messages using Discord's layout UI.""" """Embed wrapper used for logging messages."""
def __init__( def __init__(
self, self,
@ -68,75 +68,15 @@ class LoggingCog(commands.Cog):
author: Optional[discord.abc.User], author: Optional[discord.abc.User],
footer: Optional[str], footer: Optional[str],
) -> None: ) -> None:
super().__init__(timeout=None) super().__init__(title=title, description=description, color=color)
self.container = ui.Container(accent_colour=color)
self.add_item(self.container)
self.description_display: Optional[ui.TextDisplay] = (
ui.TextDisplay(description) if description else None
)
# Header section is only used when an author is provided so we don't
# need a placeholder accessory.
if author is not None: if author is not None:
self.header: Optional[ui.Section] = ui.Section( self.set_author(name=author.display_name, icon_url=author.display_avatar.url)
accessory=ui.Thumbnail(media=author.display_avatar.url)
)
self.header.add_item(ui.TextDisplay(f"**{title}**"))
if self.description_display:
self.header.add_item(self.description_display)
self.container.add_item(self.header)
else:
self.header = None
self.title_display = ui.TextDisplay(f"**{title}**")
self.container.add_item(self.title_display)
if self.description_display:
self.container.add_item(self.description_display)
# Container used for fields so they're inserted before the footer.
self.fields_container = ui.Container()
self.container.add_item(self.fields_container)
self.separator = ui.Separator(spacing=discord.SeparatorSpacing.small)
footer_text = footer or f"Bot ID: {bot.user.id}" + ( footer_text = footer or f"Bot ID: {bot.user.id}" + (
f" | User ID: {author.id}" if author else "" f" | User ID: {author.id}" if author else ""
) )
self.footer_display = ui.TextDisplay(footer_text) self.set_footer(text=footer_text)
self.container.add_item(self.separator)
self.container.add_item(self.footer_display)
# --- Compatibility helpers ---
def add_field(self, name: str, value: str, inline: bool = False):
"""Append a bolded name/value line to the log view."""
self.fields_container.add_item(ui.TextDisplay(f"**{name}:** {value}"))
def set_footer(self, text: str):
"""Replace the footer text display."""
self.footer_display.content = text
def set_author(self, name: str, icon_url: Optional[str] = None):
"""Add or update the author information."""
if self.header is None:
# Remove plain title/description displays and replace with a section.
self.container.remove_item(self.title_display)
if self.description_display:
self.container.remove_item(self.description_display)
self.header = ui.Section(
accessory=ui.Thumbnail(media=icon_url or "")
)
self.header.add_item(ui.TextDisplay(name))
if self.description_display:
self.header.add_item(self.description_display)
self.container.add_item(self.header)
# Move to the beginning to mimic embed header placement
self.container._children.remove(self.header)
self.container._children.insert(0, self.header)
else:
self.header.clear_items()
if icon_url:
self.header.accessory = ui.Thumbnail(media=icon_url)
self.header.add_item(ui.TextDisplay(name))
def _user_display(self, user: Union[discord.Member, discord.User]) -> str: def _user_display(self, user: Union[discord.Member, discord.User]) -> str:
"""Return display name, username and ID string for a user.""" """Return display name, username and ID string for a user."""
display = user.display_name if isinstance(user, discord.Member) else user.name display = user.display_name if isinstance(user, discord.Member) else user.name
@ -192,7 +132,7 @@ class LoggingCog(commands.Cog):
await self.session.close() await self.session.close()
log.info("aiohttp ClientSession closed for LoggingCog.") log.info("aiohttp ClientSession closed for LoggingCog.")
async def _send_log_embed(self, guild: discord.Guild, embed: ui.LayoutView) -> None: async def _send_log_embed(self, guild: discord.Guild, embed: discord.Embed) -> None:
"""Sends the log view via the configured webhook for the guild.""" """Sends the log view via the configured webhook for the guild."""
if not self.session or self.session.closed: if not self.session or self.session.closed:
log.error(f"aiohttp session not available or closed in LoggingCog for guild {guild.id}. Cannot send log.") log.error(f"aiohttp session not available or closed in LoggingCog for guild {guild.id}. Cannot send log.")
@ -211,7 +151,7 @@ class LoggingCog(commands.Cog):
client=self.bot, client=self.bot,
) )
await webhook.send( await webhook.send(
view=embed, embed=embed,
username=f"{self.bot.user.name} Logs", username=f"{self.bot.user.name} Logs",
avatar_url=self.bot.user.display_avatar.url, avatar_url=self.bot.user.display_avatar.url,
allowed_mentions=AllowedMentions.none(), allowed_mentions=AllowedMentions.none(),
@ -240,13 +180,13 @@ class LoggingCog(commands.Cog):
color: discord.Color = discord.Color.blue(), color: discord.Color = discord.Color.blue(),
author: Optional[Union[discord.User, discord.Member]] = None, author: Optional[Union[discord.User, discord.Member]] = None,
footer: Optional[str] = None, footer: Optional[str] = None,
) -> ui.LayoutView: ) -> discord.Embed:
"""Creates a standardized log view.""" """Creates a standardized log embed."""
return self.LogView(self.bot, title, description, color, author, footer) return self.LogView(self.bot, title, description, color, author, footer)
def _add_id_footer( def _add_id_footer(
self, self,
embed: ui.LayoutView, embed: discord.Embed,
obj: Union[ obj: Union[
discord.Member, discord.Member,
discord.User, discord.User,
@ -261,10 +201,10 @@ class LoggingCog(commands.Cog):
) -> None: ) -> None:
"""Adds an ID to the footer text if possible.""" """Adds an ID to the footer text if possible."""
target_id = obj_id or (obj.id if obj else None) target_id = obj_id or (obj.id if obj else None)
if target_id and hasattr(embed, "footer_display"): if target_id:
existing_footer = embed.footer_display.content or "" existing_footer = embed.footer.text or ""
separator = " | " if existing_footer else "" separator = " | " if existing_footer else ""
embed.footer_display.content = f"{existing_footer}{separator}{id_name}: {target_id}" embed.set_footer(text=f"{existing_footer}{separator}{id_name}: {target_id}", icon_url=embed.footer.icon_url)
async def _check_log_enabled(self, guild_id: int, event_key: str) -> bool: async def _check_log_enabled(self, guild_id: int, event_key: str) -> bool:
"""Checks if logging is enabled for a specific event key in a guild.""" """Checks if logging is enabled for a specific event key in a guild."""
@ -382,7 +322,7 @@ class LoggingCog(commands.Cog):
color=discord.Color.green(), color=discord.Color.green(),
) )
await new_webhook.send( await new_webhook.send(
view=test_view, embed=test_view,
username=webhook_name, username=webhook_name,
avatar_url=self.bot.user.display_avatar.url, avatar_url=self.bot.user.display_avatar.url,
allowed_mentions=AllowedMentions.none(), allowed_mentions=AllowedMentions.none(),