Updated modal handling for order and review submissions with more user-friendly error messages. Added `waitlist_entries` to manage waitlist data. Refactored the `waitlist` command for better user mention handling and added error handling for permission issues. Overall enhancements improve functionality and user experience.
179 lines
7.8 KiB
Python
179 lines
7.8 KiB
Python
import discord
|
|
from redbot.core import commands, Config, app_commands
|
|
from typing import Optional, TYPE_CHECKING
|
|
import datetime
|
|
|
|
if TYPE_CHECKING:
|
|
from redbot.core.bot import Red
|
|
|
|
# --- Modals for the Forms ---
|
|
|
|
class OrderModal(discord.ui.Modal, title="Commission Order Form"):
|
|
commission_type = discord.ui.TextInput(label="What type of commission?")
|
|
payment_status = discord.ui.TextInput(label="Is this a Free or Paid commission?")
|
|
description = discord.ui.TextInput(label="Description", style=discord.TextStyle.paragraph)
|
|
questions = discord.ui.TextInput(label="Any questions?", style=discord.TextStyle.paragraph, required=False)
|
|
|
|
def __init__(self, cog: "KofiShop"):
|
|
super().__init__()
|
|
self.cog = cog
|
|
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|
guild = interaction.guild
|
|
if not guild:
|
|
return
|
|
|
|
channel_id = await self.cog.config.guild(guild).order_channel()
|
|
if not channel_id:
|
|
await interaction.response.send_message("The order channel has not been set by an admin.", ephemeral=True)
|
|
return
|
|
|
|
channel = guild.get_channel(channel_id)
|
|
if not isinstance(channel, discord.TextChannel):
|
|
await interaction.response.send_message("The configured order channel is invalid.", ephemeral=True)
|
|
return
|
|
|
|
embed = discord.Embed(title=f"New Order from {interaction.user.name}", color=discord.Color.blurple())
|
|
embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar.url)
|
|
embed.add_field(name="Commission Type", value=self.commission_type.value, inline=False)
|
|
embed.add_field(name="Payment Status", value=self.payment_status.value, inline=False)
|
|
embed.add_field(name="Description", value=self.description.value, inline=False)
|
|
if self.questions.value:
|
|
embed.add_field(name="Questions", value=self.questions.value, inline=False)
|
|
|
|
await channel.send(embed=embed)
|
|
await interaction.response.send_message("Your order has been submitted!", ephemeral=True)
|
|
|
|
|
|
class ReviewModal(discord.ui.Modal, title="Shop Review"):
|
|
item_name = discord.ui.TextInput(label="What item/commission are you reviewing?")
|
|
rating = discord.ui.TextInput(label="Rating (out of 10)", max_length=2)
|
|
review_text = discord.ui.TextInput(label="Your Review", style=discord.TextStyle.paragraph, max_length=1000)
|
|
|
|
def __init__(self, cog: "KofiShop"):
|
|
super().__init__()
|
|
self.cog = cog
|
|
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|
guild = interaction.guild
|
|
if not guild:
|
|
return
|
|
|
|
channel_id = await self.cog.config.guild(guild).review_channel()
|
|
if not channel_id:
|
|
await interaction.response.send_message("The review channel has not been set by an admin.", ephemeral=True)
|
|
return
|
|
|
|
channel = guild.get_channel(channel_id)
|
|
if not isinstance(channel, discord.TextChannel):
|
|
await interaction.response.send_message("The configured review channel is invalid.", ephemeral=True)
|
|
return
|
|
|
|
embed = discord.Embed(title=f"New Review for {self.item_name.value}", color=discord.Color.gold())
|
|
embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar.url)
|
|
embed.add_field(name="Rating", value=f"{self.rating.value}/10")
|
|
embed.add_field(name="Review", value=self.review_text.value, inline=False)
|
|
|
|
await channel.send(embed=embed)
|
|
await interaction.response.send_message("Thank you for your review!", ephemeral=True)
|
|
|
|
|
|
# --- Main Cog Class ---
|
|
|
|
class KofiShop(commands.Cog):
|
|
"""
|
|
An interactive front-end for a Ko-fi store.
|
|
"""
|
|
|
|
def __init__(self, bot: "Red"):
|
|
self.bot = bot
|
|
self.config = Config.get_conf(self, identifier=1234567894, force_registration=True)
|
|
default_guild = {
|
|
"order_channel": None,
|
|
"review_channel": None,
|
|
"waitlist_channel": None,
|
|
"waitlist_entries": {} # For DataManager
|
|
}
|
|
self.config.register_guild(**default_guild)
|
|
|
|
@app_commands.command()
|
|
@app_commands.guild_only()
|
|
async def order(self, interaction: discord.Interaction):
|
|
"""Place an order for a commission."""
|
|
await interaction.response.send_modal(OrderModal(self))
|
|
|
|
@app_commands.command(name="rev")
|
|
@app_commands.guild_only()
|
|
async def review(self, interaction: discord.Interaction):
|
|
"""Leave a review for a completed commission."""
|
|
await interaction.response.send_modal(ReviewModal(self))
|
|
|
|
@commands.hybrid_command() # type: ignore
|
|
@app_commands.guild_only()
|
|
async def waitlist(self, ctx: commands.Context, user: Optional[discord.Member], *, item: str):
|
|
"""Add a user and their requested item to the waitlist."""
|
|
if not ctx.guild:
|
|
return
|
|
|
|
target_user = user or ctx.author
|
|
|
|
waitlist_channel_id = await self.config.guild(ctx.guild).waitlist_channel()
|
|
if not waitlist_channel_id:
|
|
return await ctx.send("The waitlist channel has not been set by an admin.", ephemeral=True)
|
|
|
|
waitlist_channel = ctx.guild.get_channel(waitlist_channel_id)
|
|
if not isinstance(waitlist_channel, discord.TextChannel):
|
|
return await ctx.send("The configured waitlist channel is invalid.", ephemeral=True)
|
|
|
|
message_to_send = f"**{item}** ིྀ {target_user.mention} ✧ in {ctx.channel.mention if isinstance(ctx.channel, discord.TextChannel) else 'this ticket'}"
|
|
|
|
try:
|
|
sent_message = await waitlist_channel.send(message_to_send)
|
|
# For DataManager
|
|
async with self.config.guild(ctx.guild).waitlist_entries() as entries:
|
|
entries[str(sent_message.id)] = datetime.datetime.now(datetime.timezone.utc).isoformat()
|
|
|
|
await ctx.send(f"{target_user.mention} has been added to the waitlist for '{item}'.", ephemeral=True)
|
|
# Also send confirmation to user's ticket if it's a ticket channel
|
|
if isinstance(ctx.channel, discord.TextChannel) and "ticket" in ctx.channel.name.lower():
|
|
await ctx.channel.send(f"You have been added to the waitlist for **{item}**.")
|
|
|
|
except discord.Forbidden:
|
|
await ctx.send("I do not have permission to send messages in the waitlist channel.", ephemeral=True)
|
|
|
|
|
|
@commands.group(aliases=["kset"]) # type: ignore
|
|
@commands.guild_only()
|
|
@commands.admin_or_permissions(manage_guild=True)
|
|
async def kofiset(self, ctx: commands.Context):
|
|
"""Configure KofiShop settings."""
|
|
pass
|
|
|
|
@kofiset.command(name="orderchannel")
|
|
async def set_order_channel(self, ctx: commands.Context, channel: discord.TextChannel):
|
|
"""Set the channel for new orders."""
|
|
if not ctx.guild:
|
|
return
|
|
await self.config.guild(ctx.guild).order_channel.set(channel.id)
|
|
await ctx.send(f"Order channel set to {channel.mention}")
|
|
|
|
@kofiset.command(name="reviewchannel")
|
|
async def set_review_channel(self, ctx: commands.Context, channel: discord.TextChannel):
|
|
"""Set the channel for new reviews."""
|
|
if not ctx.guild:
|
|
return
|
|
await self.config.guild(ctx.guild).review_channel.set(channel.id)
|
|
await ctx.send(f"Review channel set to {channel.mention}")
|
|
|
|
@kofiset.command(name="waitlistchannel")
|
|
async def set_waitlist_channel(self, ctx: commands.Context, channel: discord.TextChannel):
|
|
"""Set the channel for waitlist notifications."""
|
|
if not ctx.guild:
|
|
return
|
|
await self.config.guild(ctx.guild).waitlist_channel.set(channel.id)
|
|
await ctx.send(f"Waitlist channel set to {channel.mention}")
|
|
|
|
async def setup(bot: "Red"):
|
|
await bot.add_cog(KofiShop(bot))
|
|
|