- Improved exception handling in `create_ticket` for better user feedback. - Added "Apply for PM Position" button in `WorkView` to facilitate PM applications. - Updated `Hiring` class to manage guild settings and ensure persistent views. - Restructured `OrderModal` and `ReviewModal` in `KofiShop` for improved user experience and error handling. - Refactored `ModMail` class for better thread management and added ticket closure functionality with logging. - Converted several commands in `KofiShop` from hybrid to app commands for better interaction. - Enhanced overall code structure for readability and maintainability.
91 lines
3.5 KiB
Python
91 lines
3.5 KiB
Python
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 ...
|
|
|