2026-02-07 16:03:16 +01:00
import discord
from discord import app_commands
from discord . ext import commands , tasks
from utils . gitlab_client import gitlab_client
import logging
import json
import os
import asyncio
kuby_logger = logging . getLogger ( " KubyBot " )
REPORTS_FILE = " data/gitlab_reports.json "
def save_report ( issue_iid , user_id ) :
os . makedirs ( " data " , exist_ok = True )
try :
if os . path . exists ( REPORTS_FILE ) :
with open ( REPORTS_FILE , " r " ) as f :
data = json . load ( f )
else :
data = { }
data [ str ( issue_iid ) ] = user_id
with open ( REPORTS_FILE , " w " ) as f :
json . dump ( data , f , indent = 4 )
except Exception as e :
kuby_logger . error ( f " Error saving report to JSON: { e } " )
class BugReportModal ( discord . ui . Modal , title = " Signaler un Bug " ) :
def __init__ ( self , priority_choice ) :
super ( ) . __init__ ( )
self . priority_choice = priority_choice
bug_title = discord . ui . TextInput (
label = " Titre du bug " ,
placeholder = " Décrivez brièvement le problème... " ,
required = True ,
max_length = 100
)
description = discord . ui . TextInput (
label = " Description détaillée " ,
style = discord . TextStyle . paragraph ,
placeholder = " Que s ' est-il passé ? Comment reproduire le bug ? " ,
required = True ,
max_length = 1000
)
async def on_submit ( self , interaction : discord . Interaction ) :
await interaction . response . send_message ( " Envoi de votre rapport de bug à GitLab... " , ephemeral = True )
description_text = f " **Rapporté par:** { interaction . user } ( { interaction . user . id } ) \n "
description_text + = f " **Priorité:** { self . priority_choice . name } \n \n "
description_text + = f " **Description:** \n { self . description . value } "
# Mapping des priorités vers des labels GitLab stylisés (Scoped Labels)
labels = [ " bug " , " manual-report " , f " Priority:: { self . priority_choice . value } " ]
result = await gitlab_client . create_issue (
title = f " [MANUAL] { self . bug_title . value } " ,
description = description_text ,
labels = labels
)
if result :
issue_iid = result . get ( " iid " )
save_report ( issue_iid , interaction . user . id )
await interaction . edit_original_response ( content = f " ✅ Votre bug a été signalé avec succès ! Gameur a bien été averti et le bug sera réglé dans la prochaine mise à jour. [Voir l ' issue]( { result . get ( ' web_url ' ) } ) " )
else :
await interaction . edit_original_response ( content = " ❌ Une erreur est survenue lors de l ' envoi du rapport à GitLab. Veuillez contacter un administrateur. " )
2026-02-08 14:42:40 +01:00
class FeatureSuggestionModal ( discord . ui . Modal , title = " Suggérer une fonctionnalité " ) :
suggestion_title = discord . ui . TextInput (
label = " Titre de la suggestion " ,
placeholder = " Que voulez-vous ajouter ? " ,
required = True ,
max_length = 100
)
description = discord . ui . TextInput (
label = " Détails de la fonctionnalité " ,
style = discord . TextStyle . paragraph ,
placeholder = " Décrivez comment cela devrait fonctionner... " ,
required = True ,
max_length = 1000
)
async def on_submit ( self , interaction : discord . Interaction ) :
await interaction . response . send_message ( " Envoi de votre suggestion à GitLab... " , ephemeral = True )
description_text = f " **Suggéré par:** { interaction . user } ( { interaction . user . id } ) \n \n "
description_text + = f " **Description:** \n { self . description . value } "
labels = [ " enhancement " , " manual-suggestion " ]
result = await gitlab_client . create_issue (
title = f " [SUGGESTION] { self . suggestion_title . value } " ,
description = description_text ,
labels = labels
)
if result :
issue_iid = result . get ( " iid " )
save_report ( issue_iid , interaction . user . id )
await interaction . edit_original_response ( content = f " ✅ Votre suggestion a été envoyée avec succès ! Merci de contribuer à l ' amélioration du bot. [Voir l ' issue]( { result . get ( ' web_url ' ) } ) " )
else :
await interaction . edit_original_response ( content = " ❌ Une erreur est survenue lors de l ' envoi de la suggestion à GitLab. " )
2026-02-07 16:03:16 +01:00
class BugReport ( commands . Cog ) :
def __init__ ( self , bot ) :
self . bot = bot
self . check_gitlab_issues . start ( )
def cog_unload ( self ) :
self . check_gitlab_issues . cancel ( )
@tasks.loop ( minutes = 30 )
async def check_gitlab_issues ( self ) :
""" Vérifie périodiquement si des issues suivies ont été fermées """
if not os . path . exists ( REPORTS_FILE ) :
return
try :
with open ( REPORTS_FILE , " r " ) as f :
reports = json . load ( f )
if not reports :
return
issues_to_remove = [ ]
for issue_iid , user_id in reports . items ( ) :
issue = await gitlab_client . get_issue ( int ( issue_iid ) )
if issue and issue . get ( " state " ) == " closed " :
# L'issue est fermée ! On prévient l'utilisateur
user = self . bot . get_user ( user_id )
if user :
try :
2026-02-08 14:42:40 +01:00
is_suggestion = " [SUGGESTION] " in issue . get ( ' title ' , ' ' )
title_type = " Suggestion Implémentée ! " if is_suggestion else " 🛠️ Bug Résolu ! "
msg_type = " suggestion " if is_suggestion else " bug "
status_val = " Implémenté / Terminé " if is_suggestion else " Terminé / Résolu "
2026-02-07 16:03:16 +01:00
embed = discord . Embed (
2026-02-08 14:42:40 +01:00
title = title_type ,
description = f " Bonne nouvelle ! Votre { msg_type } (** { issue . get ( ' title ' ) } **) a été marqué comme terminé sur GitLab. " ,
2026-02-07 16:03:16 +01:00
color = discord . Color . green ( )
)
2026-02-08 14:42:40 +01:00
embed . add_field ( name = " Statut " , value = status_val )
2026-02-07 16:03:16 +01:00
embed . add_field ( name = " Prochaine étape " , value = " La mise à jour arrive prochainement ! " )
embed . set_footer ( text = " Merci de votre aide pour améliorer le bot. " )
await user . send ( embed = embed )
issues_to_remove . append ( issue_iid )
except Exception as e :
kuby_logger . error ( f " Impossible d ' envoyer un MP à { user_id } : { e } " )
else :
# On ne peut pas trouver l'user, on retire quand même pour ne pas boucler
issues_to_remove . append ( issue_iid )
if issues_to_remove :
for iid in issues_to_remove :
del reports [ iid ]
with open ( REPORTS_FILE , " w " ) as f :
json . dump ( reports , f , indent = 4 )
except Exception as e :
kuby_logger . error ( f " Erreur lors du cycle de vérification GitLab: { e } " )
@app_commands.command ( name = " signaler_bug " , description = " Signaler un bug aux développeurs " )
@app_commands.choices ( priority = [
app_commands . Choice ( name = " Basse " , value = " Low " ) ,
app_commands . Choice ( name = " Normale " , value = " Normal " ) ,
app_commands . Choice ( name = " Haute " , value = " High " ) ,
app_commands . Choice ( name = " Urgente " , value = " Urgent " ) ,
] )
async def signaler_bug ( self , interaction : discord . Interaction , priority : app_commands . Choice [ str ] ) :
await interaction . response . send_modal ( BugReportModal ( priority ) )
2026-02-08 14:42:40 +01:00
@app_commands.command ( name = " suggerer_fonctionnalite " , description = " Proposer une nouvelle fonctionnalité pour le bot " )
async def suggerer_fonctionnalite ( self , interaction : discord . Interaction ) :
await interaction . response . send_modal ( FeatureSuggestionModal ( ) )
2026-02-07 16:03:16 +01:00
async def setup ( bot ) :
await bot . add_cog ( BugReport ( bot ) )