import discord import datetime from redbot.core import commands, Config, app_commands from typing import Optional class Modmail(commands.Cog): """ A private, forum-based ModMail system. """ def __init__(self, bot): self.bot = bot self.config = Config.get_conf(self, identifier=1234567890, force_registration=True) default_guild = { "forum_channel": None, "enabled": False, "active_threads": {}, "closed_threads": {} # NEW: To log closed tickets for purging } self.config.register_guild(**default_guild) # ... existing on_message listener ... @commands.Cog.listener() async def on_message(self, message: discord.Message): if message.author.bot: return # --- User to Staff DM Logic --- if isinstance(message.channel, discord.DMChannel): # ... existing user DM logic ... pass # --- Staff to User Reply Logic --- elif isinstance(message.channel, discord.Thread): # ... existing staff reply logic ... pass @app_commands.command(name="close") @app_commands.guild_only() async def modmail_close(self, interaction: discord.Interaction, *, reason: Optional[str] = "No reason provided."): """Close the current ModMail ticket.""" guild = interaction.guild if not guild: await interaction.response.send_message("This command can only be used in a server.", ephemeral=True) return # NEW: Safely check if the interaction has a channel if not interaction.channel: await interaction.response.send_message("This command cannot be used in this context.", ephemeral=True) return # ... existing logic to check if it's a modmail thread ... thread_id_str = str(interaction.channel.id) async with self.config.guild(guild).active_threads() as active_threads: user_id = active_threads.pop(thread_id_str, None) if user_id: # NEW: Log the closed thread with a timestamp async with self.config.guild(guild).closed_threads() as closed_threads: closed_threads[thread_id_str] = datetime.datetime.now(datetime.timezone.utc).isoformat() # ... existing logic to send final message and archive thread ... user = self.bot.get_user(int(user_id)) if user: embed = discord.Embed( title="Ticket Closed", description=f"Your ModMail ticket has been closed.\n**Reason:** {reason}", color=0x8b9ed7 # Pastel Blue ) try: await user.send(embed=embed) except discord.Forbidden: pass await interaction.response.send_message("Ticket has been closed and archived.", ephemeral=True) if isinstance(interaction.channel, discord.Thread): await interaction.channel.edit(archived=True, locked=True) else: await interaction.response.send_message("This does not appear to be an active ModMail ticket.", ephemeral=True) @commands.group(aliases=["mmset"]) # type: ignore @commands.guild_only() @commands.admin_or_permissions(manage_guild=True) async def modmailset(self, ctx: commands.Context): """Configure ModMail settings.""" pass # ... existing modmailset subcommands ...