fix(rules): améliorer le système de règlement
- Rendu markdown via Container avec TextDisplay au lieu de embed.description - Commandes bug/suggestion utilisables avec arguments directs (copy-paste supporté) - Échappement des mentions @everyone/@here pour éviter notifications involontaires Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e11f0d8b4a
commit
fac7ed1e6b
2 changed files with 96 additions and 8 deletions
|
|
@ -447,11 +447,14 @@ class BugReport(commands.Cog):
|
||||||
async def signaler_bug(
|
async def signaler_bug(
|
||||||
self,
|
self,
|
||||||
interaction: disnake.ApplicationCommandInteraction,
|
interaction: disnake.ApplicationCommandInteraction,
|
||||||
|
titre: str = commands.Param(description="Titre/Courte description du bug"),
|
||||||
|
description: str = commands.Param(description="Description détaillée (copy-paste accepté !)"),
|
||||||
priority: str = commands.Param(
|
priority: str = commands.Param(
|
||||||
description="Priorité du bug",
|
description="Priorité du bug",
|
||||||
choices={"Basse": "Low", "Normale": "Normal", "Haute": "High", "Urgente": "Urgent"},
|
choices={"Basse": "Low", "Normale": "Normal", "Haute": "High", "Urgente": "Urgent"},
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
|
"""Signale un bug directement avec arguments - copy-paste supporté."""
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
Choice = namedtuple('Choice', ['name', 'value'])
|
Choice = namedtuple('Choice', ['name', 'value'])
|
||||||
|
|
@ -461,14 +464,80 @@ class BugReport(commands.Cog):
|
||||||
p_name = reverse.get(priority, "Normal")
|
p_name = reverse.get(priority, "Normal")
|
||||||
choice = Choice(name=p_name, value=priority)
|
choice = Choice(name=p_name, value=priority)
|
||||||
|
|
||||||
await interaction.response.send_modal(BugReportModal(choice))
|
await interaction.response.send_message("Envoi de votre rapport de bug à GitLab...", ephemeral=True)
|
||||||
|
|
||||||
|
bug_title = titre.strip() if titre else "Sans titre"
|
||||||
|
priority_name = choice.name
|
||||||
|
description_value = description
|
||||||
|
|
||||||
|
description_text = f"**Rapporté par:** {interaction.user} ({interaction.user.id})\n"
|
||||||
|
description_text += f"**Priorité:** {priority_name}\n\n"
|
||||||
|
description_text += f"**Description:**\n{description_value}"
|
||||||
|
|
||||||
|
labels = ["bug", "manual-report", f"Priority::{choice.value}"]
|
||||||
|
|
||||||
|
result = await gitlab_client.create_issue(
|
||||||
|
title=f"[MANUAL] {bug_title}",
|
||||||
|
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=(
|
||||||
|
"✅ Votre bug a été signalé avec succès ! "
|
||||||
|
"Nous avons bien été averti et le bug sera réglé dans la prochaine mise à jour. "
|
||||||
|
f"[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."
|
||||||
|
)
|
||||||
|
|
||||||
@commands.slash_command(
|
@commands.slash_command(
|
||||||
name="suggerer_fonctionnalite",
|
name="suggerer_fonctionnalite",
|
||||||
description="Proposer une nouvelle fonctionnalité pour le bot",
|
description="Proposer une nouvelle fonctionnalité pour le bot",
|
||||||
)
|
)
|
||||||
async def suggerer_fonctionnalite(self, interaction: disnake.ApplicationCommandInteraction):
|
async def suggerer_fonctionnalite(
|
||||||
await interaction.response.send_modal(FeatureSuggestionModal())
|
self,
|
||||||
|
interaction: disnake.ApplicationCommandInteraction,
|
||||||
|
titre: str = commands.Param(description="Titre de la suggestion"),
|
||||||
|
description: str = commands.Param(description="Détails de la fonctionnalité (copy-paste accepté !)"),
|
||||||
|
):
|
||||||
|
"""Suggère une fonctionnalité directement avec arguments - copy-paste supporté."""
|
||||||
|
await interaction.response.send_message("Envoi de votre suggestion à GitLab...", ephemeral=True)
|
||||||
|
|
||||||
|
suggestion_title = titre.strip() if titre else "Sans titre"
|
||||||
|
description_value = description
|
||||||
|
|
||||||
|
description_text = f"**Sugéré par:** {interaction.user} ({interaction.user.id})\n\n"
|
||||||
|
description_text += f"**Description:**\n{description_value}"
|
||||||
|
|
||||||
|
labels = ["enhancement", "manual-suggestion"]
|
||||||
|
|
||||||
|
result = await gitlab_client.create_issue(
|
||||||
|
title=f"[SUGGESTION] {suggestion_title}",
|
||||||
|
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=(
|
||||||
|
"✅ Votre suggestion a été envoyée avec succès ! "
|
||||||
|
"Merci de contribuer à l'amélioration du bot. "
|
||||||
|
f"[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."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,14 @@ from typing import Optional
|
||||||
SETTINGS_FILE = "data/security_settings.json"
|
SETTINGS_FILE = "data/security_settings.json"
|
||||||
|
|
||||||
|
|
||||||
|
def escape_mentions(text: str) -> str:
|
||||||
|
"""Échappe les mentions @everyone et @here pour éviter les notifications involontaires"""
|
||||||
|
if not text:
|
||||||
|
return text
|
||||||
|
# Utilise un zero-width space pour briser la mention Discord
|
||||||
|
return text.replace("@everyone", "@\u200beveryone").replace("@here", "@\u200bhere")
|
||||||
|
|
||||||
|
|
||||||
def load_settings(guild_id: int) -> dict:
|
def load_settings(guild_id: int) -> dict:
|
||||||
"""Charge les paramètres de sécurité pour un serveur"""
|
"""Charge les paramètres de sécurité pour un serveur"""
|
||||||
if not os.path.exists(SETTINGS_FILE):
|
if not os.path.exists(SETTINGS_FILE):
|
||||||
|
|
@ -95,7 +103,7 @@ class RulesContentModal(disnake.ui.Modal):
|
||||||
self.on_update_callback = on_update_callback
|
self.on_update_callback = on_update_callback
|
||||||
|
|
||||||
async def callback(self, interaction: disnake.Interaction):
|
async def callback(self, interaction: disnake.Interaction):
|
||||||
self.settings["rules_content"] = self.content_input.value
|
self.settings["rules_content"] = escape_mentions(self.content_input.value)
|
||||||
save_settings(self.guild_id, self.settings)
|
save_settings(self.guild_id, self.settings)
|
||||||
|
|
||||||
if self.on_update_callback:
|
if self.on_update_callback:
|
||||||
|
|
@ -434,10 +442,11 @@ class RulesCog(commands.Cog):
|
||||||
view = RulesAcceptButton(channel.guild.id, accept_role_id)
|
view = RulesAcceptButton(channel.guild.id, accept_role_id)
|
||||||
|
|
||||||
if message_type == "simple":
|
if message_type == "simple":
|
||||||
# Message simple
|
# Message simple - échappe les mentions @everyone/@here pour éviter les notifications involontaires
|
||||||
|
safe_content = content.replace("@everyone", "@\u200beveryone").replace("@here", "@\u200bhere")
|
||||||
text_message = (
|
text_message = (
|
||||||
f"📜 **{title}**\n\n"
|
f"📜 **{title}**\n\n"
|
||||||
f"{content}\n\n"
|
f"{safe_content}\n\n"
|
||||||
"Bienvenue ! Pour accéder à l'ensemble des canaux du serveur, "
|
"Bienvenue ! Pour accéder à l'ensemble des canaux du serveur, "
|
||||||
"vous devez accepter le règlement en cliquant sur le bouton ci-dessous.\n\n"
|
"vous devez accepter le règlement en cliquant sur le bouton ci-dessous.\n\n"
|
||||||
"En acceptant, vous confirmez avoir lu et compris les règles du serveur."
|
"En acceptant, vous confirmez avoir lu et compris les règles du serveur."
|
||||||
|
|
@ -455,19 +464,29 @@ class RulesCog(commands.Cog):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
else: # embed
|
else: # embed
|
||||||
|
# Échappe les mentions @everyone/@here pour éviter les notifications involontaires
|
||||||
|
safe_content = content.replace("@everyone", "@\u200beveryone").replace("@here", "@\u200bhere")
|
||||||
|
|
||||||
|
# Utilise un Container avec TextDisplay pour un meilleur rendu du texte (markdown supporté)
|
||||||
|
components = [
|
||||||
|
disnake.ui.Container(
|
||||||
|
disnake.ui.TextDisplay(safe_content)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
# Créer l'embed
|
# Créer l'embed
|
||||||
embed = disnake.Embed(
|
embed = disnake.Embed(
|
||||||
title=title,
|
title=title,
|
||||||
description=content,
|
|
||||||
color=0x2b2d31
|
color=0x2b2d31
|
||||||
)
|
)
|
||||||
|
|
||||||
embed.set_footer(text="Cliquez sur le bouton ci-dessous pour accepter le règlement")
|
embed.set_footer(text="Cliquez sur le bouton ci-dessous pour accepter le règlement")
|
||||||
|
|
||||||
# Envoyer seulement l'embed
|
# Envoyer l'embed avec le container et la view
|
||||||
try:
|
try:
|
||||||
message = await channel.send(
|
message = await channel.send(
|
||||||
embed=embed,
|
embed=embed,
|
||||||
|
components=components,
|
||||||
view=view
|
view=view
|
||||||
)
|
)
|
||||||
return message
|
return message
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue