Fix: récupération des issues_gitlab après incident
This commit is contained in:
parent
ed6e25c219
commit
b6d2995916
8 changed files with 682 additions and 308 deletions
|
|
@ -8,53 +8,75 @@ import os
|
|||
import asyncio
|
||||
|
||||
kuby_logger = logging.getLogger("KubyBot")
|
||||
# Utilisation de chemins absolus pour la persistance après reboot
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
REPORTS_FILE = os.path.join(BASE_DIR, "data", "gitlab_reports.json")
|
||||
|
||||
# ⚡ NOUVEAU: Utilise le même fichier que gitlab_integration.py
|
||||
TRACKING_FILE = os.path.join(BASE_DIR, "commandes", "gitlab_issues.json")
|
||||
LEGACY_REPORTS_FILE = os.path.join(BASE_DIR, "data", "gitlab_reports.json")
|
||||
|
||||
|
||||
def save_report(issue_iid, user_id):
|
||||
os.makedirs(os.path.dirname(REPORTS_FILE), exist_ok=True)
|
||||
try:
|
||||
data = {}
|
||||
if os.path.exists(REPORTS_FILE):
|
||||
try:
|
||||
with open(REPORTS_FILE, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
except json.JSONDecodeError:
|
||||
kuby_logger.warning("REPORTS_FILE corrupted, re-initializing to avoid tracking loss.")
|
||||
def load_tracking():
|
||||
"""Charge le tracking depuis gitlab_issues.json (avec migration automatique)"""
|
||||
tracking = {}
|
||||
if os.path.exists(TRACKING_FILE):
|
||||
try:
|
||||
with open(TRACKING_FILE, "r", encoding="utf-8") as f:
|
||||
tracking = json.load(f)
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur chargement gitlab_issues.json: {e}")
|
||||
|
||||
# Migration automatique depuis l'ancien fichier
|
||||
if os.path.exists(LEGACY_REPORTS_FILE):
|
||||
try:
|
||||
with open(LEGACY_REPORTS_FILE, "r", encoding="utf-8") as f:
|
||||
legacy_data = json.load(f)
|
||||
for issue_iid, user_id in legacy_data.items():
|
||||
if issue_iid not in tracking:
|
||||
tracking[issue_iid] = {
|
||||
"requester_id": user_id,
|
||||
"last_note_id": 0,
|
||||
"type": "legacy_report"
|
||||
}
|
||||
kuby_logger.info(f"Migration automatique: {len(legacy_data)} issues fusionnées")
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur migration gitlab_reports.json: {e}")
|
||||
|
||||
return tracking
|
||||
|
||||
data[str(issue_iid)] = user_id
|
||||
|
||||
temp_file = f"{REPORTS_FILE}.tmp"
|
||||
with open(temp_file, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
os.replace(temp_file, REPORTS_FILE)
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Error saving report to JSON: {e}")
|
||||
def save_tracking(data: Dict[str, Any]) -> None:
|
||||
"""Sauvegarde dans gitlab_issues.json"""
|
||||
os.makedirs(os.path.dirname(TRACKING_FILE), exist_ok=True)
|
||||
temp_file = f"{TRACKING_FILE}.tmp"
|
||||
with open(temp_file, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
os.replace(temp_file, TRACKING_FILE)
|
||||
|
||||
|
||||
class BugReportModal(disnake.ui.Modal):
|
||||
def __init__(self):
|
||||
def __init__(self, cog):
|
||||
self.cog = cog # ⚡ NOUVEAU: Reçoit le cog pour tracking
|
||||
components = [
|
||||
disnake.ui.TextInput(
|
||||
label="Titre du bug",
|
||||
placeholder="Décrivez brièvement le problème...",
|
||||
custom_id="bug_title",
|
||||
required=True,
|
||||
max_length=100,
|
||||
),
|
||||
disnake.ui.TextInput(
|
||||
label="Description détaillée",
|
||||
style=disnake.TextInputStyle.paragraph,
|
||||
placeholder="Que s'est-il passé ?",
|
||||
custom_id="bug_description",
|
||||
required=True,
|
||||
max_length=1000,
|
||||
),
|
||||
]
|
||||
super().__init__(
|
||||
title="Signaler un Bug",
|
||||
components=[
|
||||
disnake.ui.TextInput(
|
||||
label="Titre du bug",
|
||||
placeholder="Décrivez brièvement le problème...",
|
||||
custom_id="bug_title",
|
||||
required=True,
|
||||
max_length=100,
|
||||
),
|
||||
disnake.ui.TextInput(
|
||||
label="Description détaillée",
|
||||
style=disnake.TextInputStyle.paragraph,
|
||||
placeholder="Que s'est-il passé ?",
|
||||
custom_id="bug_description",
|
||||
required=True,
|
||||
max_length=1000,
|
||||
),
|
||||
]
|
||||
custom_id="bug_modal",
|
||||
components=components,
|
||||
)
|
||||
|
||||
async def callback(self, interaction: disnake.ModalInteraction):
|
||||
|
|
@ -66,7 +88,6 @@ class BugReportModal(disnake.ui.Modal):
|
|||
|
||||
priority_name = "Normale"
|
||||
priority_value = "Normal"
|
||||
|
||||
description_value = interaction.text_values.get("bug_description") or ""
|
||||
|
||||
description_text = f"**Rapporté par:** {interaction.user} ({interaction.user.id})\n"
|
||||
|
|
@ -82,8 +103,14 @@ class BugReportModal(disnake.ui.Modal):
|
|||
)
|
||||
|
||||
if result:
|
||||
issue_iid = result.get("iid")
|
||||
save_report(issue_iid, interaction.user.id)
|
||||
issue_iid = str(result.get("iid"))
|
||||
# ⚡ NOUVEAU: Utilise le tracking unifié
|
||||
self.cog.issue_data[issue_iid] = {
|
||||
"requester_id": interaction.user.id,
|
||||
"last_note_id": 0,
|
||||
"type": "manual-report"
|
||||
}
|
||||
save_tracking(self.cog.issue_data)
|
||||
await interaction.edit_original_response(
|
||||
content=(
|
||||
"✅ Votre bug a été signalé avec succès ! "
|
||||
|
|
@ -97,37 +124,30 @@ class BugReportModal(disnake.ui.Modal):
|
|||
)
|
||||
|
||||
|
||||
class BugReportView(disnake.ui.View):
|
||||
def __init__(self):
|
||||
super().__init__(timeout=None)
|
||||
|
||||
@disnake.ui.button(label="🎫 Remplir le formulaire", style=disnake.ButtonStyle.primary, custom_id="open_bug_form")
|
||||
async def open_bug_form(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
|
||||
modal = BugReportModal()
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
|
||||
class FeatureSuggestionModal(disnake.ui.Modal):
|
||||
def __init__(self):
|
||||
def __init__(self, cog):
|
||||
self.cog = cog # ⚡ NOUVEAU: Reçoit le cog pour tracking
|
||||
components = [
|
||||
disnake.ui.TextInput(
|
||||
label="Titre de la suggestion",
|
||||
placeholder="Que voulez-vous ajouter ?",
|
||||
custom_id="suggestion_title",
|
||||
required=True,
|
||||
max_length=100,
|
||||
),
|
||||
disnake.ui.TextInput(
|
||||
label="Détails de la fonctionnalité",
|
||||
style=disnake.TextInputStyle.paragraph,
|
||||
placeholder="Décrivez comment cela devrait fonctionner...",
|
||||
custom_id="suggestion_description",
|
||||
required=True,
|
||||
max_length=1000,
|
||||
),
|
||||
]
|
||||
super().__init__(
|
||||
title="Suggérer une fonctionnalité",
|
||||
components=[
|
||||
disnake.ui.TextInput(
|
||||
label="Titre de la suggestion",
|
||||
placeholder="Que voulez-vous ajouter ?",
|
||||
custom_id="suggestion_title",
|
||||
required=True,
|
||||
max_length=100,
|
||||
),
|
||||
disnake.ui.TextInput(
|
||||
label="Détails de la fonctionnalité",
|
||||
style=disnake.TextInputStyle.paragraph,
|
||||
placeholder="Décrivez comment cela devrait fonctionner...",
|
||||
custom_id="suggestion_description",
|
||||
required=True,
|
||||
max_length=1000,
|
||||
)
|
||||
]
|
||||
custom_id="suggestion_modal",
|
||||
components=components,
|
||||
)
|
||||
|
||||
async def callback(self, interaction: disnake.ModalInteraction):
|
||||
|
|
@ -148,8 +168,14 @@ class FeatureSuggestionModal(disnake.ui.Modal):
|
|||
)
|
||||
|
||||
if result:
|
||||
issue_iid = result.get("iid")
|
||||
save_report(issue_iid, interaction.user.id)
|
||||
issue_iid = str(result.get("iid"))
|
||||
# ⚡ NOUVEAU: Utilise le tracking unifié
|
||||
self.cog.issue_data[issue_iid] = {
|
||||
"requester_id": interaction.user.id,
|
||||
"last_note_id": 0,
|
||||
"type": "manual-suggestion"
|
||||
}
|
||||
save_tracking(self.cog.issue_data)
|
||||
await interaction.edit_original_response(
|
||||
content=(
|
||||
"✅ Votre suggestion a été envoyée avec succès ! "
|
||||
|
|
@ -163,23 +189,36 @@ class FeatureSuggestionModal(disnake.ui.Modal):
|
|||
)
|
||||
|
||||
|
||||
class BugReportView(disnake.ui.View):
|
||||
def __init__(self, cog):
|
||||
self.cog = cog # ⚡ NOUVEAU: Reçoit le cog
|
||||
super().__init__(timeout=None)
|
||||
|
||||
@disnake.ui.button(label="🎫 Remplir le formulaire", style=disnake.ButtonStyle.primary, custom_id="open_bug_form")
|
||||
async def open_bug_form(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
|
||||
modal = BugReportModal(self.cog)
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
|
||||
class FeatureSuggestionView(disnake.ui.View):
|
||||
def __init__(self):
|
||||
def __init__(self, cog):
|
||||
self.cog = cog # ⚡ NOUVEAU: Reçoit le cog
|
||||
super().__init__(timeout=None)
|
||||
|
||||
@disnake.ui.button(label="🎫 Remplir le formulaire", style=disnake.ButtonStyle.green, custom_id="open_suggestion_form")
|
||||
async def open_suggestion_form(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
|
||||
modal = FeatureSuggestionModal()
|
||||
modal = FeatureSuggestionModal(self.cog)
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
|
||||
class BugReport(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.issue_data = load_tracking() # ⚡ NOUVEAU: Charge le tracking unifié
|
||||
|
||||
async def cog_load(self):
|
||||
kuby_logger.info("BugReport cog chargé. Démarrage du serveur de relais interne (port 5001)...")
|
||||
REPORTS_DIR = os.path.dirname(REPORTS_FILE)
|
||||
REPORTS_DIR = os.path.dirname(LEGACY_REPORTS_FILE)
|
||||
os.makedirs(REPORTS_DIR, exist_ok=True)
|
||||
await self._start_webhook_server()
|
||||
|
||||
|
|
@ -205,13 +244,10 @@ class BugReport(commands.Cog):
|
|||
kuby_logger.info("Internal Bot Webhook Server stopped and cleaned up.")
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Error during webhook server cleanup: {e}")
|
||||
|
||||
self.bot.loop.create_task(cleanup())
|
||||
|
||||
async def handle_bot_event(self, request):
|
||||
provided_token = request.headers.get("X-Gitlab-Token")
|
||||
# On ignore la vérification du token pour faciliter le relais local
|
||||
|
||||
"""Gère les webhooks GitLab (notifications instantanées)"""
|
||||
try:
|
||||
if not self.bot.is_ready():
|
||||
kuby_logger.info("Webhook received but bot is not ready yet. Waiting up to 10s...")
|
||||
|
|
@ -221,206 +257,106 @@ class BugReport(commands.Cog):
|
|||
kuby_logger.warning("Bot still not ready after 10s. Proceeding anyway (best effort).")
|
||||
|
||||
payload = await request.json()
|
||||
|
||||
event_type = payload.get("object_kind")
|
||||
|
||||
if event_type not in ["issue", "note"]:
|
||||
return web.json_response({"status": "ignored"}, status=200)
|
||||
|
||||
if event_type == "issue":
|
||||
issue_iid = payload.get("object_attributes", {}).get("iid")
|
||||
else:
|
||||
issue_iid = payload.get("issue", {}).get("iid")
|
||||
|
||||
# Récupère l'IID de l'issue
|
||||
issue_iid = str(
|
||||
payload.get("object_attributes", {}).get("iid") or
|
||||
payload.get("issue", {}).get("iid")
|
||||
)
|
||||
|
||||
if not issue_iid:
|
||||
return web.json_response({"status": "no issue id"}, status=200)
|
||||
|
||||
if not os.path.exists(REPORTS_FILE):
|
||||
return web.json_response({"status": "no reports file"}, status=200)
|
||||
|
||||
try:
|
||||
with open(REPORTS_FILE, "r", encoding="utf-8") as f:
|
||||
reports = json.load(f)
|
||||
except json.JSONDecodeError:
|
||||
kuby_logger.error("REPORTS_FILE corrupted during read!")
|
||||
return web.json_response({"status": "corrupted file"}, status=500)
|
||||
|
||||
user_id = reports.get(str(issue_iid))
|
||||
if not user_id:
|
||||
|
||||
# Vérifie si l'issue est trackée
|
||||
issue_data = self.issue_data.get(issue_iid)
|
||||
if not issue_data:
|
||||
return web.json_response({"status": "untracked issue"}, status=200)
|
||||
|
||||
|
||||
user_id = issue_data.get("requester_id")
|
||||
if not user_id:
|
||||
return web.json_response({"status": "no requester"}, status=200)
|
||||
|
||||
user = self.bot.get_user(user_id)
|
||||
if not user:
|
||||
try:
|
||||
user = await self.bot.fetch_user(user_id)
|
||||
except:
|
||||
pass
|
||||
|
||||
if not user:
|
||||
return web.json_response({"status": "user not found"}, status=200)
|
||||
|
||||
# DEBUG: log brute payload minimal pour comprendre pourquoi aucun DM n'est envoyé
|
||||
kuby_logger.info(
|
||||
f"[GitLab webhook] event_type={event_type} issue_iid={issue_iid} "
|
||||
f"tracked_user_id={user_id} payload_keys={list(payload.keys())[:20]}"
|
||||
)
|
||||
|
||||
if event_type == "note":
|
||||
note_obj_attrs = payload.get("object_attributes") or {}
|
||||
kuby_logger.info(
|
||||
f"[GitLab note] system={note_obj_attrs.get('system', False)} "
|
||||
f"note_len={len(str(note_obj_attrs.get('note') or note_obj_attrs.get('body') or payload.get('note') or ''))}"
|
||||
)
|
||||
return web.json_response({"status": "user not found"}, status=200)
|
||||
|
||||
app_info = await self.bot.application_info()
|
||||
dev = app_info.owner
|
||||
issue_title = payload.get("object_attributes", {}).get("title", f"#{issue_iid}")
|
||||
|
||||
if event_type == "note":
|
||||
issue_title = payload.get("issue", {}).get("title", f"#{issue_iid}")
|
||||
|
||||
if event_type == "issue":
|
||||
# ⚡ NOUVEAU: Notifie les commentaires via le webhook (instantané)
|
||||
note_attr = payload.get("object_attributes", {})
|
||||
is_system = note_attr.get("system", False)
|
||||
|
||||
if not is_system:
|
||||
note_body = (
|
||||
note_attr.get("note") or
|
||||
note_attr.get("body") or
|
||||
payload.get("note", "") or
|
||||
""
|
||||
)
|
||||
author_name = payload.get("user", {}).get("name", "Développeur")
|
||||
|
||||
if note_body:
|
||||
try:
|
||||
embed = disnake.Embed(
|
||||
title="💬 Nouveau commentaire sur votre signalement",
|
||||
description=f"Le développeur a répondu à votre rapport **{issue_title}** :\n\n>>> {note_body}\n\n✍️ **Par :** {author_name}",
|
||||
color=disnake.Color.orange()
|
||||
)
|
||||
embed.set_thumbnail(url=self.bot.user.display_avatar.url)
|
||||
await user.send(embed=embed)
|
||||
kuby_logger.info(f"Commentaire GitLab envoyé à {user} pour l'issue #{issue_iid}")
|
||||
except (disnake.Forbidden, disnake.HTTPException) as e:
|
||||
kuby_logger.warning(f"Impossible d'envoyer le DM à {user}: {e}")
|
||||
if dev and dev.id != user.id:
|
||||
try:
|
||||
await dev.send(f"⚠️ [DM BLOQUÉ] Impossible d'envoyer le commentaire à {user} pour l'issue #{issue_iid}")
|
||||
except:
|
||||
pass
|
||||
|
||||
elif event_type == "issue":
|
||||
# Notifie les changements d'état/label
|
||||
action = payload.get("object_attributes", {}).get("action")
|
||||
changes = payload.get("changes", {})
|
||||
|
||||
state = payload.get("object_attributes", {}).get("state")
|
||||
|
||||
if "labels" in changes:
|
||||
curr_labels = [l.get("title") for l in changes["labels"].get("current", []) if l.get("title")]
|
||||
display_labels = [
|
||||
l
|
||||
for l in curr_labels
|
||||
if not l.startswith("Priority::") and l not in ["bug", "manual-report", "manual-suggestion"]
|
||||
]
|
||||
|
||||
if display_labels:
|
||||
current_labels_str = ", ".join(display_labels)
|
||||
else:
|
||||
current_labels_str = "Mis à jour"
|
||||
|
||||
display_labels = [l for l in curr_labels if not l.startswith("Priority::") and l not in ["bug", "manual-report", "manual-suggestion"]]
|
||||
current_labels_str = ", ".join(display_labels) if display_labels else "Mis à jour"
|
||||
|
||||
try:
|
||||
embed = disnake.Embed(
|
||||
title="🛠️ Mise à jour de votre signalement !",
|
||||
description=(
|
||||
f"Le statut de votre rapport **{issue_title}** a été mis à jour par l'équipe.\n\n"
|
||||
f"📌 **Nouveaux Labels / Statuts :** {current_labels_str}"
|
||||
),
|
||||
description=f"Le statut de votre rapport **{issue_title}** a été mis à jour par l'équipe.\n\n📌 **Nouveaux Labels / Statuts :** {current_labels_str}",
|
||||
color=disnake.Color.blue()
|
||||
)
|
||||
embed.set_thumbnail(url=self.bot.user.display_avatar.url)
|
||||
|
||||
try:
|
||||
await user.send(embed=embed)
|
||||
kuby_logger.info(
|
||||
f"Notification de label envoyée à {user} ({user.id}) pour l'issue #{issue_iid}"
|
||||
)
|
||||
if dev and dev.id != user.id:
|
||||
await dev.send(
|
||||
f"✅ [SUIVI] L'utilisateur {user} ({user.id}) a bien reçu la notification de statut "
|
||||
f"**{current_labels_str}** pour l'issue #{issue_iid} ({issue_title})."
|
||||
)
|
||||
except (disnake.Forbidden, disnake.HTTPException) as e:
|
||||
error_code = getattr(e, 'code', None)
|
||||
if isinstance(e, disnake.Forbidden) or error_code == 50007:
|
||||
kuby_logger.warning(
|
||||
f"Impossible d'envoyer un MP à {user} ({user.id}) - MPs désactivés (Code: {error_code})"
|
||||
)
|
||||
if dev and dev.id != user.id:
|
||||
await dev.send(
|
||||
f"⚠️ [DM BLOQUÉ] {user} ({user.id}) a ses MPs fermés. Impossible de notifier pour l'issue #{issue_iid}."
|
||||
)
|
||||
else:
|
||||
kuby_logger.error(f"Erreur HTTP lors de l'envoi du MP de statut à {user}: {e}")
|
||||
await user.send(embed=embed)
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur inattendue dans la notification de label : {e}")
|
||||
|
||||
state = payload.get("object_attributes", {}).get("state")
|
||||
kuby_logger.error(f"Erreur notification label: {e}")
|
||||
|
||||
is_closing_now = action == "close" or (state == "closed" and "state_id" in changes)
|
||||
|
||||
if is_closing_now:
|
||||
try:
|
||||
embed = disnake.Embed(
|
||||
title="🛠️ Bug / Suggestion Terminé(e) !",
|
||||
description=(
|
||||
f"Bonne nouvelle ! Votre signalement **{issue_title}** a été marqué comme terminé ou résolu.\n\n"
|
||||
f"🚀 **Prochaine étape :** La mise à jour arrive prochainement (ou est déjà là) !\n"
|
||||
f"✨ Merci pour votre aide !"
|
||||
),
|
||||
description=f"Bonne nouvelle ! Votre signalement **{issue_title}** a été marqué comme terminé ou résolu.\n\n🚀 **Prochaine étape :** La mise à jour arrive prochainement !\n✨ Merci pour votre aide !",
|
||||
color=disnake.Color.green()
|
||||
)
|
||||
embed.set_thumbnail(url=self.bot.user.display_avatar.url)
|
||||
|
||||
try:
|
||||
await user.send(embed=embed)
|
||||
kuby_logger.info(
|
||||
f"Notification de clôture envoyée à {user} ({user.id}) pour l'issue #{issue_iid}"
|
||||
)
|
||||
if dev and dev.id != user.id:
|
||||
await dev.send(
|
||||
f"✅ [SUIVI] L'utilisateur {user} ({user.id}) a bien reçu la notification de CLÔTURE pour l'issue #{issue_iid}."
|
||||
)
|
||||
except (disnake.Forbidden, disnake.HTTPException) as e:
|
||||
error_code = getattr(e, 'code', None)
|
||||
if isinstance(e, disnake.Forbidden) or error_code == 50007:
|
||||
kuby_logger.warning(f"Impossible d'envoyer le MP de clôture à {user} ({user.id}) - MPs désactivés.")
|
||||
if dev and dev.id != user.id:
|
||||
await dev.send(
|
||||
f"⚠️ [DM BLOQUÉ] Impossible d'annoncer la clôture à {user} ({user.id}) pour l'issue #{issue_iid}."
|
||||
)
|
||||
else:
|
||||
kuby_logger.error(f"Erreur HTTP lors de l'envoi du MP de clôture à {user}: {e}")
|
||||
await user.send(embed=embed)
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur inattendue dans la notification de clôture : {e}")
|
||||
|
||||
elif event_type == "note":
|
||||
note_attr = payload.get("object_attributes", {})
|
||||
is_system = note_attr.get("system", False)
|
||||
|
||||
kuby_logger.info(
|
||||
f"[GitLab note] dispatch started issue_iid={issue_iid} is_system={is_system} "
|
||||
f"note_field_present={bool(note_attr.get('note') or note_attr.get('body'))}"
|
||||
)
|
||||
|
||||
if not is_system:
|
||||
note_body = (
|
||||
note_attr.get("note")
|
||||
or note_attr.get("body")
|
||||
or payload.get("note", "")
|
||||
or payload.get("object_attributes", {}).get("note", "")
|
||||
or ""
|
||||
)
|
||||
author_name = payload.get("user", {}).get("name", "Développeur")
|
||||
|
||||
try:
|
||||
embed = disnake.Embed(
|
||||
title="💬 Nouveau commentaire sur votre signalement",
|
||||
description=(
|
||||
f"Le développeur a répondu à votre rapport **{issue_title}** :\n\n"
|
||||
f">>> {note_body}\n\n"
|
||||
f"✍️ **Par :** {author_name}"
|
||||
),
|
||||
color=disnake.Color.orange()
|
||||
)
|
||||
embed.set_thumbnail(url=self.bot.user.display_avatar.url)
|
||||
|
||||
try:
|
||||
await user.send(embed=embed)
|
||||
kuby_logger.info(
|
||||
f"Commentaire GitLab envoyé à {user} ({user.id}) pour l'issue #{issue_iid}"
|
||||
)
|
||||
if dev and dev.id != user.id:
|
||||
await dev.send(
|
||||
f"✅ [SUIVI] L'utilisateur {user} ({user.id}) a bien reçu votre commentaire pour l'issue #{issue_iid}."
|
||||
)
|
||||
except (disnake.Forbidden, disnake.HTTPException):
|
||||
if dev and dev.id != user.id:
|
||||
try:
|
||||
await dev.send(
|
||||
f"⚠️ [DM BLOQUÉ] Impossible d'envoyer votre commentaire à {user} ({user.id}) pour l'issue #{issue_iid} (DMs désactivés)."
|
||||
)
|
||||
except (disnake.Forbidden, disnake.HTTPException):
|
||||
pass # On ne peut pas envoyer au dev non plus, on abandonne
|
||||
except Exception as e:
|
||||
kuby_logger.error(
|
||||
f"Erreur inattendue dans la notification de commentaire : {e}",
|
||||
exc_info=True,
|
||||
)
|
||||
kuby_logger.error(f"Erreur notification clôture: {e}")
|
||||
|
||||
return web.json_response({"status": "success"}, status=200)
|
||||
|
||||
|
|
@ -428,24 +364,16 @@ class BugReport(commands.Cog):
|
|||
kuby_logger.error(f"Error handling bot event: {e}")
|
||||
return web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
@commands.slash_command(
|
||||
name="signaler_bug",
|
||||
description="Signaler un bug aux développeurs",
|
||||
)
|
||||
@commands.slash_command(name="signaler_bug", description="Signaler un bug aux développeurs")
|
||||
async def signifier_bug(self, interaction: disnake.ApplicationCommandInteraction):
|
||||
"""Ouvre un formulaire pour signaler un bug."""
|
||||
modal = BugReportModal()
|
||||
modal = BugReportModal(self)
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
@commands.slash_command(
|
||||
name="suggerer_fonctionnalite",
|
||||
description="Proposer une nouvelle fonctionnalité pour le bot",
|
||||
)
|
||||
@commands.slash_command(name="suggerer_fonctionnalite", description="Proposer une nouvelle fonctionnalité")
|
||||
async def suggerer_fonctionnalite(self, interaction: disnake.ApplicationCommandInteraction):
|
||||
"""Ouvre un formulaire pour suggérer une fonctionnalité."""
|
||||
modal = FeatureSuggestionModal()
|
||||
modal = FeatureSuggestionModal(self)
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(BugReport(bot))
|
||||
bot.add_cog(BugReport(bot))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue