VisionApp/tickets/cog.py
Mathis 4d1e265848
All checks were successful
ci / ci (push) Successful in 47s
feat(ticket): add claim, add member, persistent management view
- ClaimButton: staff claim/unclaim with log
- AddMemberButton: UserSelect to add member to ticket channel
- TicketManagementView: persistent LayoutView with all 3 buttons
- claimed_by field in TicketData
- Buttons registered as persistent views for bot restart survival
2026-09-25 19:28:15 +02:00

201 lines
7.9 KiB
Python

from __future__ import annotations
import logging
import discord
from discord import app_commands
from discord.ext import commands
from tickets import storage
from tickets.data import TicketCategory
from tickets.ui import AddMemberButton, ClaimButton, CloseButton, PanelCreateButton
logger = logging.getLogger("vision")
class PanelView(discord.ui.LayoutView):
def __init__(self):
super().__init__(timeout=None)
container = discord.ui.Container()
container.add_item(
discord.ui.TextDisplay(
"## Systeme de tickets\n"
"Besoin d'aide ? Creez un ticket et notre equipe vous repondra.\n"
"Cliquez sur le bouton ci-dessous pour commencer."
)
)
container.add_item(discord.ui.Separator())
container.add_item(discord.ui.ActionRow(PanelCreateButton()))
self.add_item(container)
class ConfigView(discord.ui.LayoutView):
def __init__(self):
super().__init__(timeout=None)
container = discord.ui.Container()
container.add_item(discord.ui.TextDisplay("## Configuration Tickets\nModifications enregistrees."))
self.add_item(container)
class AddCategoryModal(discord.ui.Modal, title="Ajouter une categorie"):
name = discord.ui.TextInput(label="Nom", max_length=50, required=True)
emoji = discord.ui.TextInput(label="Emoji", max_length=10, required=False)
description = discord.ui.TextInput(
label="Description",
max_length=100,
required=False,
style=discord.TextStyle.paragraph,
)
async def on_submit(self, interaction: discord.Interaction):
config = storage.get_config(interaction.guild_id)
cat_id = self.name.value.lower().replace(" ", "-")[:20]
cat = TicketCategory(
id=cat_id,
name=self.name.value,
emoji=self.emoji.value or "",
description=self.description.value or "",
)
config.categories.append(cat)
storage.save_config(config)
await interaction.response.send_message(f"Categorie **{cat.name}** ajoutee.", ephemeral=True)
class ConfigToggleButton(discord.ui.Button):
def __init__(self, enabled: bool):
super().__init__(
label="Desactiver" if enabled else "Activer",
style=discord.ButtonStyle.danger if enabled else discord.ButtonStyle.success,
custom_id="ticket_cfg_toggle",
)
async def callback(self, interaction: discord.Interaction):
config = storage.get_config(interaction.guild_id)
config.enabled = not config.enabled
storage.save_config(config)
await interaction.response.edit_message(view=ConfigView())
class ConfigAddCatButton(discord.ui.Button):
def __init__(self):
super().__init__(label="Ajouter categorie", style=discord.ButtonStyle.primary, custom_id="ticket_cfg_addcat")
async def callback(self, interaction: discord.Interaction):
await interaction.response.send_modal(AddCategoryModal())
class ConfigSetStaffButton(discord.ui.Button):
def __init__(self):
super().__init__(label="Role staff", style=discord.ButtonStyle.secondary, custom_id="ticket_cfg_staff")
async def callback(self, interaction: discord.Interaction):
view = discord.ui.View(timeout=300)
sel = discord.ui.RoleSelect(
placeholder="Role staff...", custom_id="ticket_staff_role_select", min_values=1, max_values=1
)
async def _cb(interaction: discord.Interaction):
config = storage.get_config(interaction.guild_id)
config.staff_role_id = sel.values[0].id
storage.save_config(config)
await interaction.response.edit_message(content=f"Role staff : {sel.values[0].mention}", view=None)
sel.callback = _cb
view.add_item(sel)
await interaction.response.send_message("Selectionnez le role staff :", view=view, ephemeral=True)
class ConfigSetLogButton(discord.ui.Button):
def __init__(self):
super().__init__(label="Canal logs", style=discord.ButtonStyle.secondary, custom_id="ticket_cfg_log")
async def callback(self, interaction: discord.Interaction):
view = discord.ui.View(timeout=300)
sel = discord.ui.ChannelSelect(
placeholder="Canal de logs...",
custom_id="ticket_log_channel_select",
channel_types=[discord.ChannelType.text],
min_values=1,
max_values=1,
)
async def _cb(interaction: discord.Interaction):
config = storage.get_config(interaction.guild_id)
config.log_channel_id = sel.values[0].id
storage.save_config(config)
await interaction.response.edit_message(content=f"Canal de logs : {sel.values[0].mention}", view=None)
sel.callback = _cb
view.add_item(sel)
await interaction.response.send_message("Selectionnez le canal de logs :", view=view, ephemeral=True)
class TicketManagementView(discord.ui.LayoutView):
def __init__(self):
super().__init__(timeout=None)
container = discord.ui.Container()
container.add_item(discord.ui.ActionRow(ClaimButton(), AddMemberButton(), CloseButton()))
self.add_item(container)
class TicketSystem(commands.Cog):
ticket = app_commands.Group(name="ticket", description="Systeme de tickets")
def __init__(self, bot: commands.Bot):
self.bot = bot
self.bot.add_view(PanelView())
self.bot.add_view(TicketManagementView())
@commands.Cog.listener()
async def on_ready(self):
logger.info("TicketSystem cog charge")
@ticket.command(name="setup", description="Envoyer le panneau de tickets")
@app_commands.describe(channel="Canal pour le panneau")
@app_commands.checks.has_permissions(manage_guild=True)
async def ticket_setup(self, interaction: discord.Interaction, channel: discord.TextChannel):
config = storage.get_config(interaction.guild_id)
config.enabled = True
config.panel_channel_id = channel.id
storage.save_config(config)
view = PanelView()
msg = await channel.send(view=view)
config.panel_message_id = msg.id
storage.save_config(config)
container = discord.ui.Container()
container.add_item(discord.ui.TextDisplay(f"## Panneau envoye\nCanal : {channel.mention}\nStatut : Actif"))
resp_view = discord.ui.LayoutView()
resp_view.add_item(container)
await interaction.response.send_message(view=resp_view, ephemeral=True)
@ticket.command(name="config", description="Configuration du systeme de tickets")
@app_commands.checks.has_permissions(manage_guild=True)
async def ticket_config(self, interaction: discord.Interaction):
config = storage.get_config(interaction.guild_id)
cats = "\n".join(f"- {c.emoji} **{c.name}**" for c in config.categories) or "*Aucune*"
staff_line = f"**Role staff :** <@&{config.staff_role_id}>\n" if config.staff_role_id else ""
log_line = f"**Canal de logs :** <#{config.log_channel_id}>\n" if config.log_channel_id else ""
container = discord.ui.Container()
container.add_item(
discord.ui.TextDisplay(
f"## Configuration Tickets\n"
f"**Statut :** {'Actif' if config.enabled else 'Inactif'}\n"
f"{staff_line}{log_line}### Categories\n{cats}"
)
)
container.add_item(discord.ui.Separator())
container.add_item(
discord.ui.ActionRow(
ConfigToggleButton(config.enabled),
ConfigAddCatButton(),
ConfigSetStaffButton(),
ConfigSetLogButton(),
)
)
view = discord.ui.LayoutView()
view.add_item(container)
await interaction.response.send_message(view=view, ephemeral=True)
async def setup(bot: commands.Bot):
await bot.add_cog(TicketSystem(bot))