Première version de la mise à jour du suivie des bugs
This commit is contained in:
parent
fd9251fc6e
commit
d155ebfcb0
2 changed files with 235 additions and 49 deletions
|
|
@ -1,7 +1,8 @@
|
|||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands, tasks
|
||||
from discord.ext import commands
|
||||
from utils.gitlab_client import gitlab_client
|
||||
from aiohttp import web
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
|
|
@ -109,61 +110,139 @@ class FeatureSuggestionModal(discord.ui.Modal, title="Suggérer une fonctionnali
|
|||
class BugReport(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.check_gitlab_issues.start()
|
||||
|
||||
async def cog_load(self):
|
||||
self.web_app = web.Application()
|
||||
self.web_app.router.add_post('/bot_event', self.handle_bot_event)
|
||||
self.runner = web.AppRunner(self.web_app)
|
||||
await self.runner.setup()
|
||||
self.site = web.TCPSite(self.runner, '127.0.0.1', 5001)
|
||||
await self.site.start()
|
||||
kuby_logger.info("Internal Bot Webhook Server started on 127.0.0.1:5001")
|
||||
|
||||
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
|
||||
if hasattr(self, 'runner'):
|
||||
self.bot.loop.create_task(self.runner.cleanup())
|
||||
|
||||
async def handle_bot_event(self, request):
|
||||
try:
|
||||
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")
|
||||
|
||||
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)
|
||||
|
||||
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:
|
||||
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"
|
||||
|
||||
embed = discord.Embed(
|
||||
title=title_type,
|
||||
description=f"Bonne nouvelle ! Votre {msg_type} (**{issue.get('title')}**) a été marqué comme terminé sur GitLab.",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
embed.add_field(name="Statut", value=status_val)
|
||||
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)
|
||||
user_id = reports.get(str(issue_iid))
|
||||
if not user_id:
|
||||
return web.json_response({"status": "untracked issue"}, 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)
|
||||
|
||||
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":
|
||||
action = payload.get("object_attributes", {}).get("action")
|
||||
changes = payload.get("changes", {})
|
||||
|
||||
# Check for label changes
|
||||
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"
|
||||
|
||||
try:
|
||||
embed = discord.Embed(
|
||||
title="🛠️ Mise à jour de votre signalement !",
|
||||
description=f"Le statut de votre rapport **{issue_title}** a été mis à jour par l'équipe.",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
embed.add_field(name="Nouveaux Labels / Statuts", value=current_labels_str)
|
||||
await user.send(embed=embed)
|
||||
|
||||
if dev:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu la notification de statut **{current_labels_str}** pour l'issue #{issue_iid} ({issue_title}).")
|
||||
except Exception as e:
|
||||
if dev:
|
||||
await dev.send(f"❌ [ERREUR] Impossible de notifier l'utilisateur {user} pour l'issue #{issue_iid} : {e}")
|
||||
|
||||
# Check if it was closed
|
||||
if action == "close" or payload.get("object_attributes", {}).get("state") == "closed":
|
||||
try:
|
||||
embed = discord.Embed(
|
||||
title="🛠️ Bug / Suggestion Terminé(e) !",
|
||||
description=f"Bonne nouvelle ! Votre signalement **{issue_title}** a été marqué comme terminé ou résolu.",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
embed.add_field(name="Prochaine étape", value="La mise à jour arrive prochainement (ou est déjà là) !")
|
||||
embed.set_footer(text="Merci pour votre aide !")
|
||||
await user.send(embed=embed)
|
||||
|
||||
if dev:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu la notification de CLÔTURE pour l'issue #{issue_iid}.")
|
||||
|
||||
except Exception as e:
|
||||
if dev:
|
||||
await dev.send(f"❌ [ERREUR] Impossible d'annoncer la clôture à {user} pour l'issue #{issue_iid} : {e}")
|
||||
|
||||
elif event_type == "note":
|
||||
note_attr = payload.get("object_attributes", {})
|
||||
is_system = note_attr.get("system", False)
|
||||
|
||||
if not is_system:
|
||||
note_body = note_attr.get("note", "")
|
||||
author_name = payload.get("user", {}).get("name", "Développeur")
|
||||
|
||||
try:
|
||||
embed = discord.Embed(
|
||||
title="💬 Nouveau commentaire sur votre signalement",
|
||||
description=f"Le développeur a répondu à votre rapport **{issue_title}** :\n\n>>> {note_body}",
|
||||
color=discord.Color.orange()
|
||||
)
|
||||
embed.set_footer(text=f"Par {author_name}")
|
||||
await user.send(embed=embed)
|
||||
|
||||
if dev:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu votre commentaire pour l'issue #{issue_iid}.")
|
||||
|
||||
except Exception as e:
|
||||
if dev:
|
||||
await dev.send(f"❌ [ERREUR] Impossible d'envoyer votre commentaire à {user} pour l'issue #{issue_iid} : {e}")
|
||||
|
||||
return web.json_response({"status": "success"}, status=200)
|
||||
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur lors du cycle de vérification GitLab: {e}")
|
||||
kuby_logger.error(f"Error handling bot event: {e}")
|
||||
return web.json_response({"status": "error", "message": str(e)}, status=500)
|
||||
|
||||
@app_commands.command(name="signaler_bug", description="Signaler un bug aux développeurs")
|
||||
@app_commands.choices(priority=[
|
||||
|
|
@ -172,11 +251,17 @@ class BugReport(commands.Cog):
|
|||
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]):
|
||||
async def signaler_bug(self, interaction: discord.Interaction, priority: app_commands.Choice[str], mot_de_passe: str):
|
||||
if mot_de_passe != "01thisma":
|
||||
await interaction.response.send_message("❌ Mot de passe incorrect. Vous n'êtes pas autorisé à signaler un bug.", ephemeral=True)
|
||||
return
|
||||
await interaction.response.send_modal(BugReportModal(priority))
|
||||
|
||||
@app_commands.command(name="suggerer_fonctionnalite", description="Proposer une nouvelle fonctionnalité pour le bot")
|
||||
async def suggerer_fonctionnalite(self, interaction: discord.Interaction):
|
||||
async def suggerer_fonctionnalite(self, interaction: discord.Interaction, mot_de_passe: str):
|
||||
if mot_de_passe != "01thisma":
|
||||
await interaction.response.send_message("❌ Mot de passe incorrect.", ephemeral=True)
|
||||
return
|
||||
await interaction.response.send_modal(FeatureSuggestionModal())
|
||||
|
||||
async def setup(bot):
|
||||
|
|
|
|||
101
serveur_flask.py
Normal file
101
serveur_flask.py
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import os, subprocess, threading, requests
|
||||
from flask import Flask, request, abort
|
||||
from datetime import datetime, timezone
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
PROJECT_PATH = "/home/discord/Bot/Kuby_V2"
|
||||
WEBHOOK_SECRET = "Nois1"
|
||||
PROCESS_NAME = "kuby-bot"
|
||||
DISCORD_LOG_URL = "https://discord.com/api/webhooks/1482148910888652910/IA9CcOWtjGswbuxMaOu_6uaclv5zojZo4ttxtV6RYyZzJ9gW7BF7xp_Zv3oPIjYEuh8o"
|
||||
|
||||
# Bot Local Proxy
|
||||
BOT_LOCAL_URL = "http://127.0.0.1:5001/bot_event"
|
||||
|
||||
def send_discord_log(status, message, color, author=None, commit_msg=None):
|
||||
embed = {
|
||||
"title": f"🚀 Kuby V2 : {status}",
|
||||
"description": message,
|
||||
"color": color,
|
||||
"timestamp": datetime.now(timezone.utc).isoformat(),
|
||||
"fields": []
|
||||
}
|
||||
|
||||
if author:
|
||||
embed["fields"].append({"name": "👤 Auteur", "value": author, "inline": True})
|
||||
if commit_msg:
|
||||
embed["fields"].append({"name": "📝 Commit", "value": commit_msg, "inline": True})
|
||||
|
||||
payload = {"embeds": [embed]}
|
||||
try:
|
||||
requests.post(DISCORD_LOG_URL, json=payload, timeout=5)
|
||||
except Exception as e:
|
||||
print(f"[!] Erreur envoi Discord : {e}")
|
||||
|
||||
def run_mep_logic(author, commit_msg):
|
||||
start_time = datetime.now()
|
||||
send_discord_log("EN COURS", "Déploiement lancé sur la machine de guerre...", 3447003, author, commit_msg)
|
||||
|
||||
try:
|
||||
os.chdir(PROJECT_PATH)
|
||||
|
||||
# 1. GIT
|
||||
subprocess.run(["git", "fetch", "origin"], check=True)
|
||||
subprocess.run(["git", "reset", "--hard", "origin/main"], check=True)
|
||||
|
||||
# 2. PM2
|
||||
subprocess.run(f"pm2 restart {PROCESS_NAME}", shell=True, check=True, capture_output=True)
|
||||
|
||||
duration = (datetime.now() - start_time).total_seconds()
|
||||
msg = f"✅ **Déploiement réussi en {duration:.2f}s**\nLe bot est à jour et redémarré."
|
||||
send_discord_log("TERMINÉ", msg, 3066993, author, commit_msg)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"❌ **ERREUR de déploiement**\n```python\n{str(e)}\n```"
|
||||
send_discord_log("ÉCHEC", error_msg, 15158332, author, commit_msg)
|
||||
|
||||
@app.route('/deploy', methods=['POST'])
|
||||
def deploy():
|
||||
# Sécurité
|
||||
if request.headers.get('X-Gitlab-Token') != WEBHOOK_SECRET:
|
||||
abort(403)
|
||||
|
||||
# Extraction des infos GitLab
|
||||
data = request.json
|
||||
author = "Inconnu"
|
||||
commit_msg = "Pas de message"
|
||||
|
||||
if data and 'commits' in data and len(data['commits']) > 0:
|
||||
author = data['commits'][0].get('author', {}).get('name', 'Inconnu')
|
||||
commit_msg = data['commits'][0].get('message', 'Pas de message')
|
||||
|
||||
# Threading pour répondre vite à GitLab
|
||||
threading.Thread(target=run_mep_logic, args=(author, commit_msg)).start()
|
||||
|
||||
return {"status": "accepted"}, 202
|
||||
|
||||
@app.route('/gitlab_webhook', methods=['POST'])
|
||||
def gitlab_webhook():
|
||||
# Protection stricte Anti-Crawler
|
||||
user_agent = request.headers.get('User-Agent', '')
|
||||
if 'GitLab' not in user_agent:
|
||||
abort(404) # Retourne une 404 pour simuler que la page n'existe pas
|
||||
|
||||
if request.headers.get('X-Gitlab-Token') != WEBHOOK_SECRET:
|
||||
abort(404)
|
||||
|
||||
# Transférer la payload au bot Discord localement sur le port 5001
|
||||
payload = request.json
|
||||
try:
|
||||
# Timeout très court car c'est en local
|
||||
requests.post(BOT_LOCAL_URL, json=payload, timeout=2)
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"[!] Erreur de relais vers le bot Discord : {e}")
|
||||
# On renvoie 200 à GitLab quand même car GitLab n'a pas à savoir l'état interne
|
||||
|
||||
return {"status": "received"}, 200
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(f"[*] Webhook opérationnel. En attente de push ou d'events...")
|
||||
app.run(host='0.0.0.0', port=5000)
|
||||
Loading…
Add table
Add a link
Reference in a new issue