The begining
This commit is contained in:
commit
dee311e709
71 changed files with 8349 additions and 0 deletions
207
commandes/ticket.py
Normal file
207
commandes/ticket.py
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
import discord
|
||||
from discord.ext import commands, tasks
|
||||
from discord.ui import View, Button, Modal, TextInput
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
import asyncio
|
||||
|
||||
# --- Fonctions de gestion de données ---
|
||||
|
||||
def load_config():
|
||||
"""Charge la configuration des tickets"""
|
||||
path = "data/tickets/config.json"
|
||||
if not os.path.exists("data/tickets"):
|
||||
os.makedirs("data/tickets")
|
||||
if not os.path.exists(path):
|
||||
with open(path, "w") as f:
|
||||
json.dump({}, f, indent=4)
|
||||
with open(path, "r") as f:
|
||||
return json.load(f)
|
||||
|
||||
def save_config(config):
|
||||
"""Sauvegarde la configuration des tickets"""
|
||||
path = "data/tickets/config.json"
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(config, f, indent=4, ensure_ascii=False)
|
||||
|
||||
# --- Vues (Interactions) ---
|
||||
|
||||
class TicketView(View):
|
||||
def __init__(self, bot, config):
|
||||
super().__init__(timeout=None)
|
||||
self.bot = bot
|
||||
self.config = config
|
||||
|
||||
@discord.ui.button(label="Créer un ticket", style=discord.ButtonStyle.blurple, custom_id="create_ticket")
|
||||
async def create_ticket(self, interaction: discord.Interaction, button: Button):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
guild_id = str(interaction.guild_id)
|
||||
|
||||
if guild_id not in self.config:
|
||||
return await interaction.followup.send("Le système n'est pas configuré.", ephemeral=True)
|
||||
|
||||
guild_config = self.config[guild_id]
|
||||
|
||||
# Vérifier si l'utilisateur a déjà un ticket
|
||||
for channel in interaction.guild.text_channels:
|
||||
if channel.name.startswith(f"ticket-{interaction.user.id}"):
|
||||
return await interaction.followup.send(f"Vous avez déjà un ticket : {channel.mention}", ephemeral=True)
|
||||
|
||||
# Configuration des permissions
|
||||
category = interaction.guild.get_channel(int(guild_config["category_id"]))
|
||||
overwrites = {
|
||||
interaction.guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
||||
interaction.user: discord.PermissionOverwrite(read_messages=True, send_messages=True, attach_files=True),
|
||||
interaction.guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True)
|
||||
}
|
||||
|
||||
for role_id in guild_config["staff_roles"]:
|
||||
role = interaction.guild.get_role(int(role_id))
|
||||
if role:
|
||||
overwrites[role] = discord.PermissionOverwrite(read_messages=True, send_messages=True)
|
||||
|
||||
# Création du salon
|
||||
channel_name = f"ticket-{interaction.user.id}-{datetime.now().strftime('%m%d%H%M')}"
|
||||
ticket_channel = await interaction.guild.create_text_channel(
|
||||
name=channel_name,
|
||||
category=category,
|
||||
overwrites=overwrites,
|
||||
topic=f"Ticket de {interaction.user} ({interaction.user.id})"
|
||||
)
|
||||
|
||||
embed = discord.Embed(
|
||||
title="Nouveau Ticket",
|
||||
description=guild_config["ticket_message"],
|
||||
color=discord.Color.blue(),
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
embed.set_author(name=interaction.user.display_name, icon_url=interaction.user.display_avatar.url)
|
||||
|
||||
await ticket_channel.send(embed=embed, view=TicketCloseView(self.bot, self.config))
|
||||
|
||||
# Logs
|
||||
if guild_config.get("log_channel"):
|
||||
log_ch = self.bot.get_channel(int(guild_config["log_channel"]))
|
||||
if log_ch:
|
||||
log_embed = discord.Embed(title="Ticket Créé", color=discord.Color.green())
|
||||
log_embed.add_field(name="Auteur", value=interaction.user.mention)
|
||||
log_embed.add_field(name="Salon", value=ticket_channel.mention)
|
||||
await log_ch.send(embed=log_embed)
|
||||
|
||||
await interaction.followup.send(f"Ticket créé : {ticket_channel.mention}", ephemeral=True)
|
||||
|
||||
class TicketCloseView(View):
|
||||
def __init__(self, bot, config):
|
||||
super().__init__(timeout=None)
|
||||
self.bot = bot
|
||||
self.config = config
|
||||
|
||||
@discord.ui.button(label="Fermer le ticket", style=discord.ButtonStyle.red, custom_id="close_ticket")
|
||||
async def close_ticket(self, interaction: discord.Interaction, button: Button):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
guild_config = self.config.get(str(interaction.guild_id))
|
||||
|
||||
# Modifier permissions (bloquer l'écriture)
|
||||
overwrites = interaction.channel.overwrites
|
||||
for target in overwrites:
|
||||
if isinstance(target, discord.Member) and target != interaction.guild.me:
|
||||
overwrites[target] = discord.PermissionOverwrite(read_messages=True, send_messages=False)
|
||||
|
||||
await interaction.channel.edit(name=f"closed-{interaction.channel.name}", overwrites=overwrites)
|
||||
|
||||
embed = discord.Embed(title="Ticket Fermé", description=f"Fermé par {interaction.user.mention}", color=discord.Color.red())
|
||||
await interaction.channel.send(embed=embed, view=TicketReopenView(self.bot, self.config))
|
||||
await interaction.followup.send("Ticket fermé.", ephemeral=True)
|
||||
|
||||
class TicketReopenView(View):
|
||||
def __init__(self, bot, config):
|
||||
super().__init__(timeout=None)
|
||||
self.bot = bot
|
||||
self.config = config
|
||||
|
||||
@discord.ui.button(label="Rouvrir", style=discord.ButtonStyle.green, custom_id="reopen_ticket")
|
||||
async def reopen(self, interaction: discord.Interaction, button: Button):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
new_name = interaction.channel.name.replace("closed-", "")
|
||||
await interaction.channel.edit(name=new_name)
|
||||
await interaction.channel.send(f"Ticket rouvert par {interaction.user.mention}", view=TicketCloseView(self.bot, self.config))
|
||||
|
||||
@discord.ui.button(label="Supprimer", style=discord.ButtonStyle.grey, custom_id="delete_ticket")
|
||||
async def delete(self, interaction: discord.Interaction, button: Button):
|
||||
await interaction.response.send_message("Suppression dans 3s...")
|
||||
await asyncio.sleep(3)
|
||||
await interaction.channel.delete()
|
||||
|
||||
# --- Modale de Configuration ---
|
||||
|
||||
class TicketConfigModal(Modal):
|
||||
def __init__(self, bot, config, guild_id):
|
||||
super().__init__(title="Configuration Tickets")
|
||||
self.bot = bot
|
||||
self.config = config
|
||||
self.guild_id = str(guild_id)
|
||||
|
||||
self.category_id = TextInput(label="ID Catégorie", placeholder="Ex: 123456789", required=True)
|
||||
self.staff_roles = TextInput(label="IDs Rôles Staff (virgule)", placeholder="ID1, ID2", required=True)
|
||||
self.log_channel = TextInput(label="ID Salon Logs", required=False)
|
||||
self.ticket_msg = TextInput(label="Message Ticket", style=discord.TextStyle.paragraph, required=True)
|
||||
self.welcome_msg = TextInput(label="Message Panel", required=True)
|
||||
|
||||
for item in [self.category_id, self.staff_roles, self.log_channel, self.ticket_msg, self.welcome_msg]:
|
||||
self.add_item(item)
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
role_ids = [r.strip() for r in self.staff_roles.value.split(",")]
|
||||
self.config[self.guild_id] = {
|
||||
"category_id": self.category_id.value,
|
||||
"staff_roles": role_ids,
|
||||
"log_channel": self.log_channel.value,
|
||||
"ticket_message": self.ticket_msg.value,
|
||||
"welcome_message": self.welcome_msg.value
|
||||
}
|
||||
save_config(self.config)
|
||||
await interaction.response.send_message("Configuration sauvegardée !", ephemeral=True)
|
||||
|
||||
# --- Le Cog Principal ---
|
||||
|
||||
class Ticket(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.config = load_config()
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_ready(self):
|
||||
# Enregistrer les vues persistantes (pour qu'elles marchent après reboot)
|
||||
self.bot.add_view(TicketView(self.bot, self.config))
|
||||
self.bot.add_view(TicketCloseView(self.bot, self.config))
|
||||
self.bot.add_view(TicketReopenView(self.bot, self.config))
|
||||
print("Module Ticket prêt")
|
||||
|
||||
@commands.hybrid_group(name="ticket")
|
||||
@commands.has_permissions(administrator=True)
|
||||
async def ticket(self, ctx):
|
||||
if ctx.invoked_subcommand is None:
|
||||
await ctx.send("Utilisez `/ticket setup` ou `/ticket panel`", ephemeral=True)
|
||||
|
||||
@ticket.command(name="setup")
|
||||
async def setup_cmd(self, ctx):
|
||||
await ctx.interaction.response.send_modal(TicketConfigModal(self.bot, self.config, ctx.guild.id))
|
||||
|
||||
@ticket.command(name="panel")
|
||||
async def panel_cmd(self, ctx, channel: discord.TextChannel = None):
|
||||
guild_id = str(ctx.guild.id)
|
||||
if guild_id not in self.config:
|
||||
return await ctx.send("Configurez d'abord le système via `/ticket setup`.")
|
||||
|
||||
target = channel or ctx.channel
|
||||
embed = discord.Embed(
|
||||
title="Support",
|
||||
description=self.config[guild_id]["welcome_message"],
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
await target.send(embed=embed, view=TicketView(self.bot, self.config))
|
||||
await ctx.send("Panel envoyé !", ephemeral=True)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Ticket(bot))
|
||||
Loading…
Add table
Add a link
Reference in a new issue