Maintenance de routine
This commit is contained in:
parent
c330b9a1cc
commit
99ab16098f
62 changed files with 52172 additions and 144 deletions
|
|
@ -100,9 +100,9 @@ class TicketPanelView(discord.ui.View):
|
|||
# Reload config to ensure we have latest permissions/categories
|
||||
self.config = self.storage.load_config(interaction.guild_id)
|
||||
|
||||
if not self._is_whitelisted(interaction):
|
||||
await interaction.response.send_message("❌ Vous n'êtes pas autorisé à utiliser cette fonctionnalité. Veuillez demander à être ajouté à la whitelist.", ephemeral=True)
|
||||
return
|
||||
# Reload config to ensure we have latest permissions/categories
|
||||
self.config = self.storage.load_config(interaction.guild_id)
|
||||
|
||||
|
||||
if not self.config.enabled:
|
||||
await interaction.response.send_message("Le système de tickets est désactivé.", ephemeral=True)
|
||||
|
|
@ -135,9 +135,9 @@ class TicketPanelView(discord.ui.View):
|
|||
# Reload config
|
||||
self.config = self.storage.load_config(interaction.guild_id)
|
||||
|
||||
if not self._is_whitelisted(interaction):
|
||||
await interaction.response.send_message("❌ Vous n'êtes pas autorisé à utiliser cette fonctionnalité. Veuillez demander à être ajouté à la whitelist.", ephemeral=True)
|
||||
return
|
||||
# Reload config
|
||||
self.config = self.storage.load_config(interaction.guild_id)
|
||||
|
||||
|
||||
storage = get_storage()
|
||||
tickets = storage.get_user_tickets(interaction.guild_id, interaction.user.id, open_only=True)
|
||||
|
|
@ -356,9 +356,7 @@ class CategorySelectionView(discord.ui.View):
|
|||
async def _on_category_select(self, interaction: discord.Interaction, category_id: str):
|
||||
"""Handle category selection"""
|
||||
try:
|
||||
if not self._is_whitelisted(interaction):
|
||||
await interaction.response.send_message("❌ Vous n'êtes pas autorisé à utiliser cette fonctionnalité. Veuillez demander à être ajouté à la whitelist.", ephemeral=True)
|
||||
return
|
||||
|
||||
|
||||
category = self.config.get_category(category_id)
|
||||
if not category:
|
||||
|
|
@ -536,6 +534,43 @@ class TicketPriorityModal(discord.ui.Modal):
|
|||
await interaction.response.send_message(f"Ticket créé: {ticket_channel.mention}", ephemeral=True)
|
||||
|
||||
|
||||
class SetCategoryModal(discord.ui.Modal):
|
||||
"""Modal pour définir la catégorie Discord où les tickets seront créés"""
|
||||
|
||||
def __init__(self, bot, storage, config: GuildTicketConfig):
|
||||
super().__init__(title="Définir la Catégorie Discord")
|
||||
self.bot = bot
|
||||
self.storage = storage
|
||||
self.config = config
|
||||
|
||||
self.category = discord.ui.TextInput(
|
||||
label="Catégorie Discord",
|
||||
placeholder="Entrez l'ID de la catégorie (clic droit -> Copier l'ID)",
|
||||
required=True,
|
||||
max_length=20
|
||||
)
|
||||
self.add_item(self.category)
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
cat_id = self.category.value.strip()
|
||||
|
||||
# Verify it's a valid ID
|
||||
if not cat_id.isdigit():
|
||||
await interaction.response.send_message("❌ Veuillez entrer un ID de catégorie valide (que des chiffres).", ephemeral=True)
|
||||
return
|
||||
|
||||
# Check if category exists
|
||||
category = interaction.guild.get_channel(int(cat_id))
|
||||
if not category or not isinstance(category, discord.CategoryChannel):
|
||||
await interaction.response.send_message("❌ Catégorie introuvable ou ce n'est pas une catégorie.", ephemeral=True)
|
||||
return
|
||||
|
||||
self.config.default_category = cat_id
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
await interaction.response.send_message(f"📁 Les tickets seront désormais créés dans la catégorie **{category.name}**!", ephemeral=True)
|
||||
|
||||
|
||||
class TicketManagementView(discord.ui.View):
|
||||
"""Gestion du ticket (dans le salon du ticket)"""
|
||||
|
||||
|
|
@ -883,6 +918,27 @@ class CloseDelayView(discord.ui.View):
|
|||
|
||||
duration = self.ticket.duration_minutes
|
||||
|
||||
# Send Feedback Request to User via DM
|
||||
try:
|
||||
user = interaction.guild.get_member(self.ticket.user_id)
|
||||
if user:
|
||||
from .feedback_view import FeedbackView
|
||||
|
||||
dm_embed = discord.Embed(
|
||||
title="📝 Votre avis nous intéresse !",
|
||||
description=f"Votre ticket **#{self.ticket.channel_id}** a été fermé.\nMerci de prendre un moment pour noter la qualité du support.",
|
||||
color=discord.Color.green(),
|
||||
timestamp=datetime.now()
|
||||
)
|
||||
dm_embed.add_field(name="Durée du ticket", value=f"{duration:.1f} minutes", inline=True)
|
||||
if self.close_reason:
|
||||
dm_embed.add_field(name="Raison de fermeture", value=self.close_reason, inline=False)
|
||||
|
||||
view = FeedbackView(self.bot, self.storage, self.ticket)
|
||||
await user.send(embed=dm_embed, view=view)
|
||||
except Exception as e:
|
||||
print(f"Failed to send feedback DM: {e}")
|
||||
|
||||
# Send transcript to log channel
|
||||
if self.config.log_channel_id and transcript_file and os.path.exists(transcript_file):
|
||||
try:
|
||||
|
|
@ -1642,14 +1698,23 @@ class ConfigPanelView(discord.ui.View):
|
|||
toggle_btn.callback = self._toggle_callback
|
||||
self.add_item(toggle_btn)
|
||||
|
||||
# Default category
|
||||
self.category_btn = discord.ui.Button(
|
||||
label="📁 Catégorie par défaut",
|
||||
style=discord.ButtonStyle.secondary,
|
||||
custom_id="config_category"
|
||||
)
|
||||
self.category_btn.callback = self._category_callback
|
||||
self.add_item(self.category_btn)
|
||||
|
||||
# Ajouter catégorie
|
||||
add_cat_btn = discord.ui.Button(
|
||||
self.add_cat_btn = discord.ui.Button(
|
||||
style=discord.ButtonStyle.blurple,
|
||||
label="Ajouter Catégorie",
|
||||
custom_id="config_add_cat"
|
||||
)
|
||||
add_cat_btn.callback = self._add_cat_callback
|
||||
self.add_item(add_cat_btn)
|
||||
self.add_cat_btn.callback = self._add_cat_callback
|
||||
self.add_item(self.add_cat_btn)
|
||||
|
||||
# Staff permissions
|
||||
staff_btn = discord.ui.Button(
|
||||
|
|
@ -1737,6 +1802,10 @@ class ConfigPanelView(discord.ui.View):
|
|||
embed.add_field(name="Rôles", value=", ".join(role_mentions) if role_mentions else "Aucun", inline=False)
|
||||
embed.add_field(name="Utilisateurs", value=", ".join(user_mentions) if user_mentions else "Aucun", inline=False)
|
||||
|
||||
async def _category_callback(self, interaction: discord.Interaction):
|
||||
modal = SetCategoryModal(self.bot, self.storage, self.config)
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
async def _log_channel_callback(self, interaction: discord.Interaction):
|
||||
modal = SetChannelModal(self.bot, self.storage, self.config, "log")
|
||||
await interaction.response.send_modal(modal)
|
||||
|
|
@ -1944,6 +2013,7 @@ class PermissionConfigView(discord.ui.View):
|
|||
# Add components
|
||||
self._add_role_select()
|
||||
self._add_user_select()
|
||||
self._add_remove_select()
|
||||
|
||||
def _add_role_select(self):
|
||||
select = discord.ui.RoleSelect(
|
||||
|
|
@ -1966,118 +2036,102 @@ class PermissionConfigView(discord.ui.View):
|
|||
self.add_item(select)
|
||||
|
||||
async def _role_callback(self, interaction: discord.Interaction):
|
||||
# Determine which list to update
|
||||
if self.config_type == "staff":
|
||||
target_list = self.config.staff_roles
|
||||
else:
|
||||
target_list = self.config.config_roles
|
||||
|
||||
# Get new selected IDs
|
||||
# Note: RoleSelect/UserSelect returns the objects, not IDs directly in values sometimes depending on lib version,
|
||||
# but interaction.data['values'] is reliable for IDs if we want raw.
|
||||
# However, interaction.values which is bound to callback by library usually contains the objects.
|
||||
# Let's use the view item's values.
|
||||
|
||||
# Actually standard lib behavior: interaction.data['values'] contains IDs.
|
||||
# But let's use the argument 'interaction' and the component.
|
||||
|
||||
# Better: use the values from the specific component that triggered this
|
||||
# But since we have separate callbacks we can just read interaction.data
|
||||
|
||||
selected_ids = [str(r.id) for r in interaction.data.get('values', [])] # But wait, select menu interactions return objects in the view item's values property if mapped? NO, interaction.values is for string selects.
|
||||
# For Entity Select Menus (Role/User), interaction.data['values'] contains IDs.
|
||||
|
||||
# BUT, discord.py 2.0 uses select.values for string selects.
|
||||
# For RoleSelect, values are the list of Role objects.
|
||||
# Let's try to trust the interaction object's resolution.
|
||||
|
||||
# Wait, standard discord.py RoleSelect callback receives interaction.
|
||||
# The select object itself will have 'values' populated with Role objects after processing.
|
||||
# But we need to reference the select item.
|
||||
# Since we added it dynamically, we can't easily reference 'self.role_select'.
|
||||
|
||||
# Workaround: Re-read from interaction.data['values'] which are IDs.
|
||||
values = interaction.data.get('values', [])
|
||||
|
||||
# WE NEED TO MERGE with existing? No, select menu usually replaces selection if it shows current selection.
|
||||
# BUT Discord UI Selects don't show "current selection" natively pre-filled unless we set defaults.
|
||||
# AND we can only set defaults for StringSelect, NOT for RoleSelect/UserSelect (API Limitation).
|
||||
# So RoleSelect/UserSelect always start empty.
|
||||
# This implies we can only ADD/REMOVE or we have to handle it as "Add these", "Remove these"?
|
||||
# OR we treat valid input as "Append these to existing" or "Replace existing"?
|
||||
# Given we can't show pre-selected items, "Replace" is dangerous because user can't see what was there.
|
||||
# "Append" is safer but how to remove?
|
||||
|
||||
# Modification: Make it "Toggle" or just "Add/Remove" via specific actions?
|
||||
# A common pattern is: The select menu creates a list. We Add them.
|
||||
# But how to remove?
|
||||
# Maybe we should stick to STRING SELECT for removal if we want to show lists.
|
||||
# But the user issue is "Can't see all roles".
|
||||
|
||||
# Better approach for Entity Selects:
|
||||
# They are usually used for "Add these items".
|
||||
# To remove, we might need a separate "Remove" workflow or a StringSelect of *current* items to remove.
|
||||
|
||||
# Let's implement: "Add selected roles/users to permission".
|
||||
# And provide a way to "Clear/Remove" via a StringSelect of *existing* configured items.
|
||||
|
||||
# So:
|
||||
# 1. RoleSelect (Add)
|
||||
# 2. UserSelect (Add)
|
||||
# 3. StringSelect (Remove) - Populated with currently configured items.
|
||||
|
||||
new_ids = interaction.data.get('values', [])
|
||||
added_count = 0
|
||||
|
||||
for new_id in new_ids:
|
||||
if new_id not in target_list:
|
||||
target_list.append(new_id)
|
||||
added_count += 1
|
||||
try:
|
||||
# Determine which list to update
|
||||
if self.config_type == "staff":
|
||||
target_list = self.config.staff_roles
|
||||
else:
|
||||
target_list = self.config.config_roles
|
||||
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
await interaction.response.send_message(
|
||||
f"✅ **{added_count}** rôle(s) ajouté(s) à la configuration {self.config_type}.",
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
# Refresh view to update Remove dropdown if we add it
|
||||
await self._refresh_view(interaction)
|
||||
# Get new selected IDs
|
||||
new_ids = interaction.data.get('values', [])
|
||||
added_count = 0
|
||||
|
||||
for new_id in new_ids:
|
||||
if new_id not in target_list:
|
||||
target_list.append(new_id)
|
||||
added_count += 1
|
||||
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
|
||||
await self._refresh_view(interaction)
|
||||
except Exception as e:
|
||||
# Assuming kuby_logger is defined elsewhere, if not, replace with print or logging.error
|
||||
# import kuby_logger # Uncomment if kuby_logger is not globally available
|
||||
# kuby_logger.error(f"Error in _role_callback: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
await interaction.response.send_message("Une erreur est survenue lors de la mise à jour des rôles.", ephemeral=True)
|
||||
|
||||
async def _user_callback(self, interaction: discord.Interaction):
|
||||
if self.config_type == "staff":
|
||||
target_list = self.config.staff_users
|
||||
else:
|
||||
target_list = self.config.config_users
|
||||
|
||||
new_ids = [int(uid) for uid in interaction.data.get('values', [])]
|
||||
added_count = 0
|
||||
|
||||
for new_id in new_ids:
|
||||
if new_id not in target_list:
|
||||
target_list.append(new_id)
|
||||
added_count += 1
|
||||
try:
|
||||
if self.config_type == "staff":
|
||||
target_list = self.config.staff_users
|
||||
else:
|
||||
target_list = self.config.config_users
|
||||
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
await interaction.response.send_message(
|
||||
f"✅ **{added_count}** utilisateur(s) ajouté(s) à la configuration {self.config_type}.",
|
||||
ephemeral=True
|
||||
)
|
||||
await self._refresh_view(interaction)
|
||||
new_ids = [int(uid) for uid in interaction.data.get('values', [])]
|
||||
added_count = 0
|
||||
|
||||
for new_id in new_ids:
|
||||
if new_id not in target_list:
|
||||
target_list.append(new_id)
|
||||
added_count += 1
|
||||
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
|
||||
await self._refresh_view(interaction)
|
||||
except Exception as e:
|
||||
# Assuming kuby_logger is defined elsewhere
|
||||
# import kuby_logger
|
||||
# kuby_logger.error(f"Error in _user_callback: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
await interaction.response.send_message("Une erreur est survenue lors de la mise à jour des utilisateurs.", ephemeral=True)
|
||||
|
||||
async def _refresh_view(self, interaction):
|
||||
# Re-render the view?
|
||||
# We can't easily edit the ephemeral message with a new view from here without 'response.edit_message'
|
||||
# But we already responded to interaction.
|
||||
# So we can followup edit?
|
||||
# Actually we just want to update the "Remove" select menu.
|
||||
# Let's add the Remove Select Menu.
|
||||
self.clear_items()
|
||||
self._add_role_select()
|
||||
self._add_user_select()
|
||||
self._add_remove_select()
|
||||
await interaction.message.edit(view=self)
|
||||
|
||||
# Rebuild Embed
|
||||
if self.config_type == "staff":
|
||||
title = "Permissions Staff"
|
||||
description = "Configurez qui peut gérer les tickets (répondre, fermer, etc.)"
|
||||
color = discord.Color.blue()
|
||||
target_roles = self.config.staff_roles
|
||||
target_users = self.config.staff_users
|
||||
else:
|
||||
title = "Permissions Configuration"
|
||||
description = "Configurez qui peut modifier les paramètres du bot (/ticketconfig)"
|
||||
color = discord.Color.orange()
|
||||
target_roles = self.config.config_roles
|
||||
target_users = self.config.config_users
|
||||
|
||||
embed = discord.Embed(title=title, description=description, color=color)
|
||||
|
||||
# Add fields logic (inline reuse)
|
||||
role_mentions = []
|
||||
for role_id in target_roles:
|
||||
role = self.guild.get_role(int(role_id))
|
||||
if role:
|
||||
role_mentions.append(role.mention)
|
||||
|
||||
user_mentions = []
|
||||
for user_id in target_users:
|
||||
user = self.guild.get_member(user_id)
|
||||
if user:
|
||||
user_mentions.append(user.mention)
|
||||
else:
|
||||
user_mentions.append(f"<@{user_id}>")
|
||||
|
||||
embed.add_field(name="Rôles", value=", ".join(role_mentions) if role_mentions else "Aucun", inline=False)
|
||||
embed.add_field(name="Utilisateurs", value=", ".join(user_mentions) if user_mentions else "Aucun", inline=False)
|
||||
|
||||
await interaction.response.edit_message(embed=embed, view=self)
|
||||
|
||||
def _add_remove_select(self):
|
||||
# Build options from current config
|
||||
|
|
@ -2131,31 +2185,36 @@ class PermissionConfigView(discord.ui.View):
|
|||
self.add_item(select)
|
||||
|
||||
async def _remove_callback(self, interaction: discord.Interaction):
|
||||
values = interaction.data.get('values', [])
|
||||
|
||||
removed_count = 0
|
||||
for val in values:
|
||||
prefix, id_str = val.split('_')
|
||||
id_val = int(id_str)
|
||||
try:
|
||||
values = interaction.data.get('values', [])
|
||||
|
||||
if prefix == 'r': # Role
|
||||
target_list = self.config.staff_roles if self.config_type == "staff" else self.config.config_roles
|
||||
if str(id_val) in target_list:
|
||||
target_list.remove(str(id_val))
|
||||
removed_count += 1
|
||||
elif prefix == 'u': # User
|
||||
target_list = self.config.staff_users if self.config_type == "staff" else self.config.config_users
|
||||
if id_val in target_list:
|
||||
target_list.remove(id_val)
|
||||
removed_count += 1
|
||||
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
await interaction.response.send_message(
|
||||
f"🗑️ **{removed_count}** permission(s) retirée(s).",
|
||||
ephemeral=True
|
||||
)
|
||||
await self._refresh_view(interaction)
|
||||
removed_count = 0
|
||||
for val in values:
|
||||
prefix, id_str = val.split('_')
|
||||
id_val = int(id_str)
|
||||
|
||||
if prefix == 'r': # Role
|
||||
target_list = self.config.staff_roles if self.config_type == "staff" else self.config.config_roles
|
||||
if str(id_val) in target_list:
|
||||
target_list.remove(str(id_val))
|
||||
removed_count += 1
|
||||
elif prefix == 'u': # User
|
||||
target_list = self.config.staff_users if self.config_type == "staff" else self.config.config_users
|
||||
if id_val in target_list:
|
||||
target_list.remove(id_val)
|
||||
removed_count += 1
|
||||
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
|
||||
await self._refresh_view(interaction)
|
||||
except Exception as e:
|
||||
# Assuming kuby_logger is defined elsewhere
|
||||
# import kuby_logger
|
||||
# kuby_logger.error(f"Error in _remove_callback: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
await interaction.response.send_message("Une erreur est survenue lors de la suppression des permissions.", ephemeral=True)
|
||||
|
||||
|
||||
class TicketCommands(commands.Cog):
|
||||
|
|
@ -2289,7 +2348,7 @@ class TicketCommands(commands.Cog):
|
|||
|
||||
embed.set_footer(text="Utilisez les boutons ci-dessous pour configurer le système")
|
||||
|
||||
view = TicketSetupView(self.bot, self.storage, config)
|
||||
view = ConfigPanelView(self.bot, self.storage, config)
|
||||
await ctx.send(embed=embed, view=view, ephemeral=True)
|
||||
|
||||
|
||||
|
|
|
|||
139
commandes/ticket/feedback_view.py
Normal file
139
commandes/ticket/feedback_view.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
import discord
|
||||
from .data.models import TicketData
|
||||
|
||||
class FeedbackView(discord.ui.View):
|
||||
def __init__(self, bot, storage, ticket: TicketData):
|
||||
super().__init__(timeout=86400) # 24h timeout
|
||||
self.bot = bot
|
||||
self.storage = storage
|
||||
self.ticket = ticket
|
||||
self.rating = 0
|
||||
self.comment = ""
|
||||
|
||||
# Add Select Menu for Rating
|
||||
self.add_item(RatingSelect())
|
||||
|
||||
@discord.ui.button(label="📝 Laisser un commentaire", style=discord.ButtonStyle.secondary, custom_id="feedback_comment", row=1)
|
||||
async def comment_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
await interaction.response.send_modal(FeedbackModal(self))
|
||||
|
||||
@discord.ui.button(label="✅ Envoyer", style=discord.ButtonStyle.green, custom_id="feedback_submit", row=1)
|
||||
async def submit_button(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
if self.rating == 0:
|
||||
await interaction.response.send_message("❌ Veuillez sélectionner une note avant d'envoyer.", ephemeral=True)
|
||||
return
|
||||
|
||||
# Save feedback
|
||||
self.ticket.rating = self.rating
|
||||
self.ticket.feedback = self.comment if self.comment else "Aucun commentaire"
|
||||
self.storage.save_ticket(self.ticket)
|
||||
|
||||
# Disable view
|
||||
for child in self.children:
|
||||
child.disabled = True
|
||||
|
||||
await interaction.response.edit_message(content="✅ Merci pour votre retour !", view=self, embed=None)
|
||||
|
||||
# Log feedback if configured
|
||||
try:
|
||||
# Reload ticket to ensure we have latest data (especially claimed_by)
|
||||
# We need to use the channel_id to find the ticket
|
||||
reloaded_ticket = self.storage.load_ticket(self.ticket.channel_id)
|
||||
if reloaded_ticket:
|
||||
self.ticket = reloaded_ticket
|
||||
print(f"DEBUG: Reloaded ticket {self.ticket.channel_id}. Claimed by: {self.ticket.claimed_by}", flush=True)
|
||||
else:
|
||||
print(f"DEBUG: Could not reload ticket {self.ticket.channel_id}", flush=True)
|
||||
|
||||
print(f"DEBUG: Feedback submitted for {self.ticket.channel_id}", flush=True)
|
||||
|
||||
if self.ticket.claimed_by:
|
||||
staff_user = self.bot.get_user(self.ticket.claimed_by)
|
||||
print(f"DEBUG: Staff user from cache: {staff_user}", flush=True)
|
||||
if not staff_user:
|
||||
# Try fetching if not in cache
|
||||
try:
|
||||
staff_user = await self.bot.fetch_user(self.ticket.claimed_by)
|
||||
print(f"DEBUG: Staff user fetched: {staff_user}", flush=True)
|
||||
except Exception as e:
|
||||
print(f"DEBUG: Failed to fetch staff user: {e}", flush=True)
|
||||
pass
|
||||
|
||||
if staff_user:
|
||||
# Create feedback embed
|
||||
embed = discord.Embed(
|
||||
title="📝 Nouveau Commentaire Reçu",
|
||||
description=f"Un utilisateur a laissé un avis sur le ticket #{self.ticket.channel_id}",
|
||||
color=discord.Color.gold() if self.rating < 3 else discord.Color.green(),
|
||||
timestamp=discord.utils.utcnow()
|
||||
)
|
||||
|
||||
embed.add_field(
|
||||
name="Note",
|
||||
value=f"{'⭐' * self.rating} ({self.rating}/5)",
|
||||
inline=True
|
||||
)
|
||||
|
||||
# Add user info if possible
|
||||
user = self.bot.get_user(self.ticket.user_id)
|
||||
user_name = f"{user.name} ({user.id})" if user else f"Utilisateur {self.ticket.user_id}"
|
||||
|
||||
embed.add_field(
|
||||
name="Utilisateur",
|
||||
value=user_name,
|
||||
inline=True
|
||||
)
|
||||
|
||||
feedback_text = self.comment if self.comment else "Aucun commentaire écrit."
|
||||
embed.add_field(
|
||||
name="Commentaire",
|
||||
value=feedback_text,
|
||||
inline=False
|
||||
)
|
||||
|
||||
try:
|
||||
await staff_user.send(embed=embed)
|
||||
print(f"DEBUG: DM sent successfully to {staff_user}", flush=True)
|
||||
except discord.Forbidden:
|
||||
print(f"DEBUG: DM failed - Forbidden (DMs closed)", flush=True)
|
||||
except Exception as e:
|
||||
print(f"DEBUG: Error sending feedback DM: {e}", flush=True)
|
||||
else:
|
||||
print("DEBUG: Staff user object is None", flush=True)
|
||||
else:
|
||||
print("DEBUG: Ticket has no claimed_by value", flush=True)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in feedback notification: {e}", flush=True)
|
||||
|
||||
class RatingSelect(discord.ui.Select):
|
||||
def __init__(self):
|
||||
options = [
|
||||
discord.SelectOption(label="⭐⭐⭐⭐⭐ (Excellent)", value="5", description="Service parfait !"),
|
||||
discord.SelectOption(label="⭐⭐⭐⭐ (Très bien)", value="4", description="Très bon service"),
|
||||
discord.SelectOption(label="⭐⭐⭐ (Bien)", value="3", description="Correct"),
|
||||
discord.SelectOption(label="⭐⭐ (Moyen)", value="2", description="Peut mieux faire"),
|
||||
discord.SelectOption(label="⭐ (Mauvais)", value="1", description="Insatisfaisant")
|
||||
]
|
||||
super().__init__(placeholder="Notez le service...", min_values=1, max_values=1, options=options, row=0)
|
||||
|
||||
async def callback(self, interaction: discord.Interaction):
|
||||
self.view.rating = int(self.values[0])
|
||||
await interaction.response.defer()
|
||||
|
||||
class FeedbackModal(discord.ui.Modal):
|
||||
def __init__(self, view):
|
||||
super().__init__(title="Votre avis")
|
||||
self.view = view
|
||||
self.comment = discord.ui.TextInput(
|
||||
label="Commentaire",
|
||||
style=discord.TextStyle.paragraph,
|
||||
placeholder="Dites-nous ce que vous avez pensé du support...",
|
||||
required=True,
|
||||
max_length=1000
|
||||
)
|
||||
self.add_item(self.comment)
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
self.view.comment = self.comment.value
|
||||
await interaction.response.send_message("Commentaire enregistré ! N'oubliez pas de valider avec 'Envoyer'.", ephemeral=True)
|
||||
Loading…
Add table
Add a link
Reference in a new issue