Migration de Kuby vers disnake

This commit is contained in:
Mathis 2026-05-06 17:07:09 +02:00
parent dc6e235f27
commit c8c579eefe
36 changed files with 1205 additions and 1253 deletions

File diff suppressed because it is too large Load diff

View file

@ -16,9 +16,8 @@ from PIL import Image, ImageDraw, ImageFont
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
import discord
from discord.ext import commands
from discord import app_commands
import disnake
from disnake.ext import commands
from .data.storage import get_storage
from .data.models import TicketData, TicketStatus, GuildTicketConfig
@ -31,7 +30,7 @@ class TicketAnalytics(commands.Cog):
self.bot = bot
self.storage = get_storage()
def _is_staff(self, interaction: discord.Interaction) -> bool:
def _is_staff(self, interaction: disnake.Interaction) -> bool:
"""Check if user is staff"""
guild = interaction.guild
user = interaction.user
@ -363,9 +362,8 @@ class TicketAnalytics(commands.Cog):
buf.seek(0)
return buf
@app_commands.command(name="ticket_analytics", description="Affiche les statistiques détaillées des tickets (Staff uniquement)")
@app_commands.describe(period="Période d'analyse (7d, 30d, 90d, all)")
async def ticket_analytics(self, interaction: discord.Interaction, period: str = "30d"):
@commands.slash_command(name="ticket_analytics", description="Affiche les statistiques détaillées des tickets (Staff uniquement)")
async def ticket_analytics(self, interaction: disnake.Interaction, period: str = commands.Param(default="30d", choices=["7d", "30d", "90d", "all"], description="Période d'analyse")):
"""Display comprehensive ticket analytics for staff"""
await interaction.response.defer(ephemeral=True)
@ -405,10 +403,10 @@ class TicketAnalytics(commands.Cog):
t.created_at >= cutoff_date for t in filtered_tickets if hasattr(t, 'response_time') and t.response_time == rt)]
# Create main embed
embed = discord.Embed(
embed = disnake.Embed(
title="📊 Analytics des Tickets",
description=f"Statistiques pour la période: **{period}**",
color=discord.Color.blue(),
color=disnake.Color.blue(),
timestamp=datetime.now()
)
@ -444,7 +442,7 @@ class TicketAnalytics(commands.Cog):
rating_chart = self._create_rating_chart(stats['ratings'])
await interaction.followup.send(
"📊 **Distribution des Notes Clients**",
file=discord.File(rating_chart, 'rating_distribution.png'),
file=disnake.File(rating_chart, 'rating_distribution.png'),
ephemeral=True
)
@ -453,7 +451,7 @@ class TicketAnalytics(commands.Cog):
response_chart = self._create_response_time_chart(stats['response_times'])
await interaction.followup.send(
"⏱️ **Temps de Réponse**",
file=discord.File(response_chart, 'response_times.png'),
file=disnake.File(response_chart, 'response_times.png'),
ephemeral=True
)
@ -462,7 +460,7 @@ class TicketAnalytics(commands.Cog):
trend_chart = self._create_trend_chart(stats['tickets_by_day'])
await interaction.followup.send(
"📈 **Évolution des Tickets**",
file=discord.File(trend_chart, 'ticket_trends.png'),
file=disnake.File(trend_chart, 'ticket_trends.png'),
ephemeral=True
)
@ -471,10 +469,10 @@ class TicketAnalytics(commands.Cog):
# Send feedback summary if available
if stats['feedbacks']:
feedback_embed = discord.Embed(
feedback_embed = disnake.Embed(
title="💬 Commentaires Clients",
description=f"Derniers commentaires ({min(5, len(stats['feedbacks']))} affichés)",
color=discord.Color.green()
color=disnake.Color.green()
)
# Sort by rating (lowest first to show areas for improvement)

View file

@ -1,7 +1,7 @@
import discord
import disnake
from .data.models import TicketData
class FeedbackView(discord.ui.View):
class FeedbackView(disnake.ui.View):
def __init__(self, bot, storage, ticket: TicketData, staff_rating_only: bool = False):
super().__init__(timeout=86400) # 24h timeout
self.bot = bot
@ -14,12 +14,12 @@ class FeedbackView(discord.ui.View):
# 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):
@disnake.ui.button(label="📝 Laisser un commentaire", style=disnake.ButtonStyle.secondary, custom_id="feedback_comment", row=1)
async def comment_button(self, interaction: disnake.Interaction, button: disnake.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):
@disnake.ui.button(label="✅ Envoyer", style=disnake.ButtonStyle.green, custom_id="feedback_submit", row=1)
async def submit_button(self, interaction: disnake.Interaction, button: disnake.ui.Button):
if self.rating == 0:
await interaction.response.send_message("❌ Veuillez sélectionner une note avant d'envoyer.", ephemeral=True)
return
@ -66,11 +66,11 @@ class FeedbackView(discord.ui.View):
if staff_user:
# Create feedback embed
embed = discord.Embed(
embed = disnake.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()
color=disnake.Color.gold() if self.rating < 3 else disnake.Color.green(),
timestamp=disnake.utils.utcnow()
)
embed.add_field(
@ -99,7 +99,7 @@ class FeedbackView(discord.ui.View):
try:
await staff_user.send(embed=embed)
print(f"DEBUG: DM sent successfully to {staff_user}", flush=True)
except discord.Forbidden:
except disnake.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)
@ -111,34 +111,34 @@ class FeedbackView(discord.ui.View):
except Exception as e:
print(f"Error in feedback notification: {e}", flush=True)
class RatingSelect(discord.ui.Select):
class RatingSelect(disnake.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")
disnake.SelectOption(label="⭐⭐⭐⭐⭐ (Excellent)", value="5", description="Service parfait !"),
disnake.SelectOption(label="⭐⭐⭐⭐ (Très bien)", value="4", description="Très bon service"),
disnake.SelectOption(label="⭐⭐⭐ (Bien)", value="3", description="Correct"),
disnake.SelectOption(label="⭐⭐ (Moyen)", value="2", description="Peut mieux faire"),
disnake.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):
async def callback(self, interaction: disnake.Interaction):
self.view.rating = int(self.values[0])
await interaction.response.defer()
class FeedbackModal(discord.ui.Modal):
class FeedbackModal(disnake.ui.Modal):
def __init__(self, view):
super().__init__(title="Votre avis")
self.view = view
self.comment = discord.ui.TextInput(
self.comment = disnake.ui.TextInput(
label="Commentaire",
style=discord.TextStyle.paragraph,
style=disnake.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):
async def on_submit(self, interaction: disnake.Interaction):
self.view.comment = self.comment.value
await interaction.response.send_message("Commentaire enregistré ! N'oubliez pas de valider avec 'Envoyer'.", ephemeral=True)

View file

@ -8,7 +8,7 @@ from datetime import datetime, timedelta
from collections import defaultdict
from typing import List, Dict, Any, Optional
import discord
import disnake
import matplotlib.pyplot as plt
import plotly.graph_objects as go
import plotly.express as px
@ -254,7 +254,7 @@ class StaffAnalytics:
return buf
class StaffStatsView(discord.ui.View):
class StaffStatsView(disnake.ui.View):
"""View for selecting individual staff member stats"""
def __init__(self, bot, staff_list: List[Dict[str, Any]], analytics: StaffAnalytics):
@ -272,7 +272,7 @@ class StaffStatsView(discord.ui.View):
description = f"Note: {staff['average_rating']:.1f}" if staff['total_ratings'] > 0 else "Aucune évaluation"
options.append(
discord.SelectOption(
disnake.SelectOption(
label=label,
value=str(staff['user_id']),
description=description[:50]
@ -280,14 +280,14 @@ class StaffStatsView(discord.ui.View):
)
if options:
select = discord.ui.Select(
select = disnake.ui.Select(
placeholder="Sélectionnez un membre du staff...",
options=options
)
select.callback = self._staff_selected
self.add_item(select)
async def _staff_selected(self, interaction: discord.Interaction):
async def _staff_selected(self, interaction: disnake.Interaction):
"""Handle staff selection"""
staff_id = int(interaction.data["values"][0])
staff_data = next((s for s in self.staff_list if s['user_id'] == staff_id), None)
@ -301,10 +301,10 @@ class StaffStatsView(discord.ui.View):
# Create individual chart
chart = self.analytics.create_individual_staff_chart(staff_data)
embed = discord.Embed(
embed = disnake.Embed(
title=f"📊 Statistiques de {staff_data['name']}",
description="Performances détaillées du membre du staff",
color=discord.Color.blue(),
color=disnake.Color.blue(),
timestamp=datetime.now()
)
@ -331,4 +331,4 @@ class StaffStatsView(discord.ui.View):
inline=True
)
await interaction.followup.send(embed=embed, file=discord.File(chart, 'staff_stats.png'), ephemeral=True)
await interaction.followup.send(embed=embed, file=disnake.File(chart, 'staff_stats.png'), ephemeral=True)

View file

@ -5,7 +5,7 @@ Beautiful embed and message formatters for the ticket system.
"""
from datetime import datetime
from typing import Optional, List, Dict, Any
from discord import Embed, Color, User, Member, Role
from disnake import Embed, Color, User, Member, Role
from ..data.models import (
TicketData,

View file

@ -3,13 +3,13 @@ Ticket Permissions Utility
==========================
Centralized permission logic for the ticket system.
"""
import discord
import disnake
from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from ..data.models import GuildTicketConfig, TicketCategory
def is_staff(interaction: discord.Interaction, config: 'GuildTicketConfig', category: Optional['TicketCategory'] = None) -> bool:
def is_staff(interaction: disnake.Interaction, config: 'GuildTicketConfig', category: Optional['TicketCategory'] = None) -> bool:
"""
Check if the user has staff permissions.
@ -51,7 +51,7 @@ def is_staff(interaction: discord.Interaction, config: 'GuildTicketConfig', cate
return False
def can_access_config(interaction: discord.Interaction, config: 'GuildTicketConfig') -> bool:
def can_access_config(interaction: disnake.Interaction, config: 'GuildTicketConfig') -> bool:
"""
Check if the user can access the configuration.
@ -87,7 +87,7 @@ def can_access_config(interaction: discord.Interaction, config: 'GuildTicketConf
return False
def is_whitelisted(interaction: discord.Interaction, config: 'GuildTicketConfig', bot) -> bool:
def is_whitelisted(interaction: disnake.Interaction, config: 'GuildTicketConfig', bot) -> bool:
"""
Check if user is whitelisted or has staff/config permissions.
"""

View file

@ -7,7 +7,7 @@ import json
import os
from datetime import datetime
from typing import Optional, List, Dict, Any
from discord import User, Member
from disnake import User, Member
from ..data.models import TicketData, TicketMessage