mirror of
https://github.com/arthur-pbty/LazyBot.git
synced 2026-06-03 15:07:29 +02:00
add role panel
This commit is contained in:
@@ -0,0 +1,382 @@
|
||||
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType } = require('discord.js');
|
||||
const addCommand = require('../../fonctions/addCommand');
|
||||
const db = require('../../db');
|
||||
|
||||
const buttonStyles = {
|
||||
'primary': ButtonStyle.Primary,
|
||||
'secondary': ButtonStyle.Secondary,
|
||||
'success': ButtonStyle.Success,
|
||||
'danger': ButtonStyle.Danger
|
||||
};
|
||||
|
||||
// Fonction pour créer/mettre à jour le message du panel
|
||||
async function updatePanelMessage(client, panel, buttons) {
|
||||
try {
|
||||
const guild = client.guilds.cache.get(panel.guild_id);
|
||||
if (!guild) return null;
|
||||
|
||||
const channel = guild.channels.cache.get(panel.channel_id);
|
||||
if (!channel) return null;
|
||||
|
||||
// Créer l'embed
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(panel.color || '#5865F2')
|
||||
.setTitle(panel.title || '🎭 Choisissez vos rôles')
|
||||
.setDescription(panel.description || 'Cliquez sur les boutons ci-dessous pour obtenir ou retirer des rôles.');
|
||||
|
||||
if (panel.image_url) embed.setImage(panel.image_url);
|
||||
if (panel.thumbnail_url) embed.setThumbnail(panel.thumbnail_url);
|
||||
|
||||
// Infos sur le mode
|
||||
const modeText = panel.exclusive
|
||||
? '⚠️ *Un seul rôle possible à la fois*'
|
||||
: (panel.mode === 'toggle' ? '💡 *Cliquez à nouveau pour retirer un rôle*' : '');
|
||||
|
||||
if (modeText) {
|
||||
embed.setFooter({ text: modeText });
|
||||
}
|
||||
|
||||
// Créer les boutons (max 5 par ligne, max 5 lignes)
|
||||
const rows = [];
|
||||
const enabledButtons = buttons.filter(b => b.enabled).sort((a, b) => a.position - b.position);
|
||||
|
||||
for (let i = 0; i < enabledButtons.length && rows.length < 5; i += 5) {
|
||||
const row = new ActionRowBuilder();
|
||||
const rowButtons = enabledButtons.slice(i, i + 5);
|
||||
|
||||
for (const btn of rowButtons) {
|
||||
const button = new ButtonBuilder()
|
||||
.setCustomId(`role_panel_${btn.id}`)
|
||||
.setLabel(btn.label)
|
||||
.setStyle(buttonStyles[btn.style] || ButtonStyle.Primary);
|
||||
|
||||
if (btn.emoji) {
|
||||
// Vérifier si c'est un emoji custom ou unicode
|
||||
if (btn.emoji.match(/^\d+$/)) {
|
||||
button.setEmoji({ id: btn.emoji });
|
||||
} else {
|
||||
button.setEmoji(btn.emoji);
|
||||
}
|
||||
}
|
||||
|
||||
row.addComponents(button);
|
||||
}
|
||||
|
||||
if (row.components.length > 0) {
|
||||
rows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour ou créer le message
|
||||
if (panel.message_id) {
|
||||
try {
|
||||
const message = await channel.messages.fetch(panel.message_id);
|
||||
await message.edit({ embeds: [embed], components: rows });
|
||||
return panel.message_id;
|
||||
} catch {
|
||||
// Message introuvable, en créer un nouveau
|
||||
}
|
||||
}
|
||||
|
||||
const message = await channel.send({ embeds: [embed], components: rows });
|
||||
|
||||
// Sauvegarder l'ID du message
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run("UPDATE role_panels SET message_id = ? WHERE id = ?", [message.id, panel.id], (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
return message.id;
|
||||
|
||||
} catch (err) {
|
||||
console.error('Erreur mise à jour panel:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = addCommand({
|
||||
name: 'rolepanel',
|
||||
description: 'Créer un panneau de rôles interactif',
|
||||
aliases: ['rp', 'rolebuttons', 'reactionroles'],
|
||||
permissions: ['ManageRoles', 'ManageMessages'],
|
||||
botOwnerOnly: false,
|
||||
dm: false,
|
||||
scope: 'global',
|
||||
slashOptions: [
|
||||
{ type: 'STRING', name: 'action', description: 'Action à effectuer', required: true, choices: [
|
||||
{ name: 'Créer un panel', value: 'create' },
|
||||
{ name: 'Ajouter un bouton', value: 'addbutton' },
|
||||
{ name: 'Supprimer un panel', value: 'delete' },
|
||||
{ name: 'Liste des panels', value: 'list' },
|
||||
{ name: 'Actualiser un panel', value: 'refresh' }
|
||||
]},
|
||||
{ type: 'STRING', name: 'nom', description: 'Nom du panel', required: false },
|
||||
{ type: 'CHANNEL', name: 'salon', description: 'Salon où envoyer le panel', required: false },
|
||||
{ type: 'ROLE', name: 'role', description: 'Rôle à associer (pour addbutton)', required: false },
|
||||
{ type: 'STRING', name: 'label', description: 'Texte du bouton', required: false },
|
||||
{ type: 'STRING', name: 'emoji', description: 'Emoji du bouton', required: false }
|
||||
],
|
||||
|
||||
executeSlash: async (client, interaction) => {
|
||||
const action = interaction.options.getString('action');
|
||||
const guildId = interaction.guild.id;
|
||||
|
||||
switch (action) {
|
||||
case 'create': {
|
||||
const name = interaction.options.getString('nom');
|
||||
const channel = interaction.options.getChannel('salon');
|
||||
|
||||
if (!name || !channel) {
|
||||
return interaction.reply({
|
||||
content: '❌ Vous devez spécifier un nom et un salon.\nUsage: `/rolepanel create nom:MonPanel salon:#roles`',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
if (channel.type !== ChannelType.GuildText) {
|
||||
return interaction.reply({
|
||||
content: '❌ Le salon doit être un salon textuel.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Vérifier si un panel avec ce nom existe déjà
|
||||
const existing = await db.getAsync(
|
||||
"SELECT id FROM role_panels WHERE guild_id = ? AND name = ?",
|
||||
[guildId, name]
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
return interaction.reply({
|
||||
content: '❌ Un panel avec ce nom existe déjà.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Créer le panel
|
||||
const panelId = await new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
"INSERT INTO role_panels (guild_id, channel_id, name, title, description) VALUES (?, ?, ?, ?, ?)",
|
||||
[guildId, channel.id, name, `🎭 ${name}`, 'Cliquez sur les boutons ci-dessous pour obtenir vos rôles.'],
|
||||
function(err) {
|
||||
if (err) reject(err);
|
||||
else resolve(this.lastID);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0x57F287)
|
||||
.setTitle('✅ Panel créé')
|
||||
.setDescription(`Le panel **${name}** a été créé.`)
|
||||
.addFields(
|
||||
{ name: '📁 Salon', value: `${channel}`, inline: true },
|
||||
{ name: '🆔 ID', value: `${panelId}`, inline: true }
|
||||
)
|
||||
.setFooter({ text: 'Ajoutez des boutons avec /rolepanel addbutton' });
|
||||
|
||||
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||
}
|
||||
|
||||
case 'addbutton': {
|
||||
const name = interaction.options.getString('nom');
|
||||
const role = interaction.options.getRole('role');
|
||||
const label = interaction.options.getString('label');
|
||||
const emoji = interaction.options.getString('emoji');
|
||||
|
||||
if (!name || !role) {
|
||||
return interaction.reply({
|
||||
content: '❌ Vous devez spécifier le nom du panel et un rôle.\nUsage: `/rolepanel addbutton nom:MonPanel role:@MonRole label:Mon Rôle emoji:🎮`',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Trouver le panel
|
||||
const panel = await db.getAsync(
|
||||
"SELECT * FROM role_panels WHERE guild_id = ? AND name = ?",
|
||||
[guildId, name]
|
||||
);
|
||||
|
||||
if (!panel) {
|
||||
return interaction.reply({
|
||||
content: `❌ Panel "${name}" non trouvé. Utilisez \`/rolepanel list\` pour voir les panels existants.`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Vérifier le nombre de boutons (max 25)
|
||||
const buttonCount = await db.getAsync(
|
||||
"SELECT COUNT(*) as count FROM role_panel_buttons WHERE panel_id = ?",
|
||||
[panel.id]
|
||||
);
|
||||
|
||||
if (buttonCount.count >= 25) {
|
||||
return interaction.reply({
|
||||
content: '❌ Ce panel a atteint la limite de 25 boutons.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Ajouter le bouton
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
"INSERT INTO role_panel_buttons (panel_id, role_id, label, emoji, position) VALUES (?, ?, ?, ?, ?)",
|
||||
[panel.id, role.id, label || role.name, emoji || null, buttonCount.count],
|
||||
(err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Mettre à jour le message
|
||||
const buttons = await db.allAsync(
|
||||
"SELECT * FROM role_panel_buttons WHERE panel_id = ?",
|
||||
[panel.id]
|
||||
);
|
||||
|
||||
await updatePanelMessage(client, panel, buttons);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0x57F287)
|
||||
.setTitle('✅ Bouton ajouté')
|
||||
.addFields(
|
||||
{ name: '📋 Panel', value: name, inline: true },
|
||||
{ name: '🎭 Rôle', value: `${role}`, inline: true },
|
||||
{ name: '🏷️ Label', value: label || role.name, inline: true }
|
||||
);
|
||||
|
||||
if (emoji) embed.addFields({ name: '😀 Emoji', value: emoji, inline: true });
|
||||
|
||||
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||
}
|
||||
|
||||
case 'delete': {
|
||||
const name = interaction.options.getString('nom');
|
||||
|
||||
if (!name) {
|
||||
return interaction.reply({
|
||||
content: '❌ Vous devez spécifier le nom du panel à supprimer.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
const panel = await db.getAsync(
|
||||
"SELECT * FROM role_panels WHERE guild_id = ? AND name = ?",
|
||||
[guildId, name]
|
||||
);
|
||||
|
||||
if (!panel) {
|
||||
return interaction.reply({
|
||||
content: `❌ Panel "${name}" non trouvé.`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Supprimer le message
|
||||
try {
|
||||
const channel = interaction.guild.channels.cache.get(panel.channel_id);
|
||||
if (channel && panel.message_id) {
|
||||
const message = await channel.messages.fetch(panel.message_id).catch(() => null);
|
||||
if (message) await message.delete();
|
||||
}
|
||||
} catch {}
|
||||
|
||||
// Supprimer de la DB
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run("DELETE FROM role_panel_buttons WHERE panel_id = ?", [panel.id], (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run("DELETE FROM role_panels WHERE id = ?", [panel.id], (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
return interaction.reply({
|
||||
content: `✅ Panel **${name}** supprimé avec succès.`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
case 'list': {
|
||||
const panels = await db.allAsync(
|
||||
"SELECT rp.*, COUNT(rpb.id) as button_count FROM role_panels rp LEFT JOIN role_panel_buttons rpb ON rp.id = rpb.panel_id WHERE rp.guild_id = ? GROUP BY rp.id",
|
||||
[guildId]
|
||||
);
|
||||
|
||||
if (!panels || panels.length === 0) {
|
||||
return interaction.reply({
|
||||
content: 'ℹ️ Aucun panel de rôles configuré. Créez-en un avec `/rolepanel create`.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0x5865F2)
|
||||
.setTitle('📋 Panels de rôles')
|
||||
.setDescription(panels.map(p => {
|
||||
const status = p.enabled ? '🟢' : '🔴';
|
||||
return `${status} **${p.name}** - ${p.button_count} boutons - <#${p.channel_id}>`;
|
||||
}).join('\n'));
|
||||
|
||||
return interaction.reply({ embeds: [embed], ephemeral: true });
|
||||
}
|
||||
|
||||
case 'refresh': {
|
||||
const name = interaction.options.getString('nom');
|
||||
|
||||
if (!name) {
|
||||
return interaction.reply({
|
||||
content: '❌ Vous devez spécifier le nom du panel à actualiser.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
const panel = await db.getAsync(
|
||||
"SELECT * FROM role_panels WHERE guild_id = ? AND name = ?",
|
||||
[guildId, name]
|
||||
);
|
||||
|
||||
if (!panel) {
|
||||
return interaction.reply({
|
||||
content: `❌ Panel "${name}" non trouvé.`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
const buttons = await db.allAsync(
|
||||
"SELECT * FROM role_panel_buttons WHERE panel_id = ?",
|
||||
[panel.id]
|
||||
);
|
||||
|
||||
const messageId = await updatePanelMessage(client, panel, buttons);
|
||||
|
||||
if (messageId) {
|
||||
return interaction.reply({
|
||||
content: `✅ Panel **${name}** actualisé !`,
|
||||
ephemeral: true
|
||||
});
|
||||
} else {
|
||||
return interaction.reply({
|
||||
content: '❌ Erreur lors de l\'actualisation du panel.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
executePrefix: async (client, message, args) => {
|
||||
return message.reply('❌ Cette commande est disponible uniquement en slash command. Utilisez `/rolepanel`.');
|
||||
}
|
||||
});
|
||||
|
||||
// Exporter la fonction de mise à jour pour l'API
|
||||
module.exports.updatePanelMessage = updatePanelMessage;
|
||||
@@ -410,6 +410,37 @@ db.exec(`
|
||||
last_channel_activity INTEGER,
|
||||
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
|
||||
);
|
||||
|
||||
-- Système de rôles par boutons
|
||||
CREATE TABLE IF NOT EXISTS role_panels (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
guild_id TEXT NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
message_id TEXT,
|
||||
name TEXT NOT NULL,
|
||||
title TEXT,
|
||||
description TEXT,
|
||||
color TEXT DEFAULT '#5865F2',
|
||||
image_url TEXT,
|
||||
thumbnail_url TEXT,
|
||||
mode TEXT NOT NULL DEFAULT 'toggle',
|
||||
exclusive INTEGER NOT NULL DEFAULT 0,
|
||||
required_role_id TEXT,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS role_panel_buttons (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
panel_id INTEGER NOT NULL,
|
||||
role_id TEXT NOT NULL,
|
||||
label TEXT NOT NULL,
|
||||
emoji TEXT,
|
||||
style TEXT NOT NULL DEFAULT 'primary',
|
||||
position INTEGER NOT NULL DEFAULT 0,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
FOREIGN KEY (panel_id) REFERENCES role_panels(id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
|
||||
module.exports = db;
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
const { Events, EmbedBuilder } = require("discord.js");
|
||||
const db = require("../db");
|
||||
|
||||
module.exports = {
|
||||
name: Events.InteractionCreate,
|
||||
async execute(client, interaction) {
|
||||
// Gérer uniquement les boutons de rôles
|
||||
if (!interaction.isButton()) return;
|
||||
if (!interaction.customId.startsWith('role_panel_')) return;
|
||||
|
||||
const buttonId = interaction.customId.replace('role_panel_', '');
|
||||
|
||||
try {
|
||||
// Récupérer les infos du bouton
|
||||
const button = await db.getAsync(
|
||||
"SELECT rpb.*, rp.mode, rp.exclusive, rp.required_role_id, rp.enabled as panel_enabled FROM role_panel_buttons rpb JOIN role_panels rp ON rpb.panel_id = rp.id WHERE rpb.id = ?",
|
||||
[buttonId]
|
||||
);
|
||||
|
||||
if (!button) {
|
||||
return interaction.reply({
|
||||
content: '❌ Ce bouton n\'est plus valide.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!button.panel_enabled || !button.enabled) {
|
||||
return interaction.reply({
|
||||
content: '❌ Ce système de rôles est actuellement désactivé.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Vérifier le rôle requis
|
||||
if (button.required_role_id) {
|
||||
if (!interaction.member.roles.cache.has(button.required_role_id)) {
|
||||
return interaction.reply({
|
||||
content: `❌ Vous devez avoir le rôle <@&${button.required_role_id}> pour utiliser ce menu.`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const role = interaction.guild.roles.cache.get(button.role_id);
|
||||
if (!role) {
|
||||
return interaction.reply({
|
||||
content: '❌ Le rôle associé à ce bouton n\'existe plus.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Vérifier que le bot peut gérer ce rôle
|
||||
if (role.position >= interaction.guild.members.me.roles.highest.position) {
|
||||
return interaction.reply({
|
||||
content: '❌ Je ne peux pas gérer ce rôle car il est au-dessus de mon rôle le plus élevé.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
const hasRole = interaction.member.roles.cache.has(role.id);
|
||||
|
||||
// Mode exclusif : retirer les autres rôles du même panel
|
||||
if (button.exclusive && !hasRole) {
|
||||
const panelButtons = await db.allAsync(
|
||||
"SELECT role_id FROM role_panel_buttons WHERE panel_id = ? AND id != ?",
|
||||
[button.panel_id, buttonId]
|
||||
);
|
||||
|
||||
for (const btn of panelButtons) {
|
||||
if (interaction.member.roles.cache.has(btn.role_id)) {
|
||||
await interaction.member.roles.remove(btn.role_id).catch(() => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gérer le rôle selon le mode
|
||||
if (hasRole) {
|
||||
// Mode toggle : retirer le rôle
|
||||
if (button.mode === 'toggle') {
|
||||
await interaction.member.roles.remove(role);
|
||||
return interaction.reply({
|
||||
content: `✅ Le rôle ${role} vous a été retiré.`,
|
||||
ephemeral: true
|
||||
});
|
||||
} else {
|
||||
// Mode add-only : ne pas retirer
|
||||
return interaction.reply({
|
||||
content: `ℹ️ Vous avez déjà le rôle ${role}.`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Ajouter le rôle
|
||||
await interaction.member.roles.add(role);
|
||||
return interaction.reply({
|
||||
content: `✅ Le rôle ${role} vous a été attribué !`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('Erreur interaction role panel:', err);
|
||||
return interaction.reply({
|
||||
content: '❌ Une erreur est survenue.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1286,3 +1286,245 @@ body {
|
||||
color: var(--error-color);
|
||||
background: rgba(237, 66, 69, 0.1);
|
||||
}
|
||||
|
||||
/* ===== Modal ===== */
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
padding: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-lg);
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.modal-content.modal-lg {
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--spacing-lg);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.modal-header h3 {
|
||||
margin: 0;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-muted);
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: var(--spacing-lg);
|
||||
border-top: 1px solid var(--border-color);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--spacing-sm);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ===== Role Panels ===== */
|
||||
.panels-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.panel-item {
|
||||
background: var(--bg-secondary);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--spacing-md);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.panel-item-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.panel-item-info h4 {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.panel-status {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.panel-status.status-active {
|
||||
background: #57F287;
|
||||
}
|
||||
|
||||
.panel-status.status-inactive {
|
||||
background: #ED4245;
|
||||
}
|
||||
|
||||
.panel-meta {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.panel-item-actions {
|
||||
display: flex;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.panel-item-preview {
|
||||
padding: var(--spacing-md);
|
||||
}
|
||||
|
||||
.preview-embed {
|
||||
background: var(--bg-main);
|
||||
border-left: 4px solid #5865F2;
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--spacing-md);
|
||||
}
|
||||
|
||||
.preview-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.preview-desc {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.preview-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.preview-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.preview-btn-primary {
|
||||
background: #5865F2;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.preview-btn-secondary {
|
||||
background: #4f545c;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.preview-btn-success {
|
||||
background: #57F287;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.preview-btn-danger {
|
||||
background: #ED4245;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.preview-more {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.85rem;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
/* Buttons list in modal */
|
||||
.buttons-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.button-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-md);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
background: var(--bg-secondary);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.button-item.button-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.button-preview {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.button-info {
|
||||
flex: 1;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.button-actions {
|
||||
display: flex;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.btn-xs {
|
||||
padding: 4px 8px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 6px 12px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.empty-message, .loading-message {
|
||||
text-align: center;
|
||||
color: var(--text-muted);
|
||||
padding: var(--spacing-lg);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,10 @@
|
||||
<span class="nav-item-icon">🛡️</span>
|
||||
Anti-Raid
|
||||
</a>
|
||||
<a class="nav-item" data-section="rolepanels">
|
||||
<span class="nav-item-icon">🎭</span>
|
||||
Rôles par boutons
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -1898,6 +1902,164 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Section Role Panels -->
|
||||
<section id="section-rolepanels" class="config-section">
|
||||
<div class="config-card">
|
||||
<div class="config-card-header">
|
||||
<div class="config-card-title">
|
||||
<span class="icon">🎭</span>
|
||||
<h2>Rôles par boutons</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="config-card-body">
|
||||
<p class="text-muted">
|
||||
Créez des panneaux de rôles interactifs. Les utilisateurs pourront cliquer sur des boutons pour obtenir ou retirer des rôles.
|
||||
</p>
|
||||
|
||||
<!-- Liste des panels -->
|
||||
<div id="role-panels-list" class="panels-list">
|
||||
<div class="loading-message">Chargement des panels...</div>
|
||||
</div>
|
||||
|
||||
<!-- Bouton pour créer un nouveau panel -->
|
||||
<button type="button" class="btn btn-primary" id="create-panel-btn" style="margin-top: 1rem;">
|
||||
➕ Créer un nouveau panel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal création/édition de panel -->
|
||||
<div id="panel-modal" class="modal" style="display: none;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 id="panel-modal-title">Créer un panel</h3>
|
||||
<button class="modal-close" id="close-panel-modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="edit-panel-id">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">📝 Nom du panel (identifiant unique)</label>
|
||||
<input type="text" class="form-input" id="panel-name" placeholder="ex: couleurs, jeux, notifications">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">📁 Salon</label>
|
||||
<select class="form-select" id="panel-channel"></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">🏷️ Titre de l'embed</label>
|
||||
<input type="text" class="form-input" id="panel-title" placeholder="🎭 Choisissez vos rôles">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">📄 Description</label>
|
||||
<textarea class="form-input" id="panel-description" rows="3" placeholder="Cliquez sur les boutons ci-dessous pour obtenir vos rôles."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">🎨 Couleur</label>
|
||||
<input type="color" class="form-input" id="panel-color" value="#5865F2">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">⚙️ Mode</label>
|
||||
<select class="form-select" id="panel-mode">
|
||||
<option value="toggle">Toggle (ajouter/retirer)</option>
|
||||
<option value="add">Ajouter uniquement</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="panel-exclusive">
|
||||
Rôles exclusifs (un seul à la fois)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">🔒 Rôle requis (optionnel)</label>
|
||||
<select class="form-select" id="panel-required-role">
|
||||
<option value="">Aucun</option>
|
||||
</select>
|
||||
<small class="text-muted">Seuls les membres avec ce rôle pourront utiliser ce panel.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">🖼️ Image URL (optionnel)</label>
|
||||
<input type="text" class="form-input" id="panel-image" placeholder="https://...">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">🔲 Thumbnail URL (optionnel)</label>
|
||||
<input type="text" class="form-input" id="panel-thumbnail" placeholder="https://...">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div id="status-panel-form" class="status-message"></div>
|
||||
<button type="button" class="btn btn-secondary" id="cancel-panel-btn">Annuler</button>
|
||||
<button type="button" class="btn btn-primary" id="save-panel-btn">💾 Sauvegarder</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal édition des boutons -->
|
||||
<div id="buttons-modal" class="modal" style="display: none;">
|
||||
<div class="modal-content modal-lg">
|
||||
<div class="modal-header">
|
||||
<h3 id="buttons-modal-title">Boutons du panel</h3>
|
||||
<button class="modal-close" id="close-buttons-modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="buttons-panel-id">
|
||||
|
||||
<!-- Liste des boutons existants -->
|
||||
<div id="panel-buttons-list" class="buttons-list"></div>
|
||||
|
||||
<!-- Formulaire d'ajout de bouton -->
|
||||
<div class="add-button-form" style="margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--border-color);">
|
||||
<h4>➕ Ajouter un bouton</h4>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">🎭 Rôle</label>
|
||||
<select class="form-select" id="new-button-role"></select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">🏷️ Label</label>
|
||||
<input type="text" class="form-input" id="new-button-label" placeholder="Mon rôle">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">😀 Emoji (optionnel)</label>
|
||||
<input type="text" class="form-input" id="new-button-emoji" placeholder="🎮">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">🎨 Style</label>
|
||||
<select class="form-select" id="new-button-style">
|
||||
<option value="primary">Bleu (Primary)</option>
|
||||
<option value="secondary">Gris (Secondary)</option>
|
||||
<option value="success">Vert (Success)</option>
|
||||
<option value="danger">Rouge (Danger)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success" id="add-button-btn">➕ Ajouter le bouton</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div id="status-buttons-form" class="status-message"></div>
|
||||
<button type="button" class="btn btn-primary" id="publish-panel-btn">🚀 Publier / Actualiser le panel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -1920,5 +2082,6 @@
|
||||
<script src="/guild/botAppearanceForm.js"></script>
|
||||
<script src="/guild/logsForm.js"></script>
|
||||
<script src="/guild/antiraidForm.js"></script>
|
||||
<script src="/guild/rolePanelsForm.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,448 @@
|
||||
// =============================================
|
||||
// ========== ROLE PANELS FORM =================
|
||||
// =============================================
|
||||
|
||||
(function() {
|
||||
let panels = [];
|
||||
let channels = [];
|
||||
let roles = [];
|
||||
let currentPanelId = null;
|
||||
|
||||
// Charger les panels
|
||||
async function loadRolePanels() {
|
||||
try {
|
||||
const res = await fetch(`/api/bot/get-role-panels?guildId=${guildId}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
panels = data.panels || [];
|
||||
channels = data.channels || [];
|
||||
roles = data.roles || [];
|
||||
|
||||
renderPanelsList();
|
||||
populateSelects();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur chargement panels:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Remplir les selects
|
||||
function populateSelects() {
|
||||
// Salon du panel
|
||||
const channelSelect = document.getElementById('panel-channel');
|
||||
if (channelSelect) {
|
||||
channelSelect.innerHTML = channels.map(c => `<option value="${c.id}"># ${c.name}</option>`).join('');
|
||||
}
|
||||
|
||||
// Rôle requis
|
||||
const requiredRoleSelect = document.getElementById('panel-required-role');
|
||||
if (requiredRoleSelect) {
|
||||
requiredRoleSelect.innerHTML = '<option value="">Aucun</option>' +
|
||||
roles.map(r => `<option value="${r.id}">${r.name}</option>`).join('');
|
||||
}
|
||||
|
||||
// Rôle pour nouveau bouton
|
||||
const newButtonRoleSelect = document.getElementById('new-button-role');
|
||||
if (newButtonRoleSelect) {
|
||||
newButtonRoleSelect.innerHTML = roles.map(r => `<option value="${r.id}">${r.name}</option>`).join('');
|
||||
}
|
||||
}
|
||||
|
||||
// Afficher la liste des panels
|
||||
function renderPanelsList() {
|
||||
const container = document.getElementById('role-panels-list');
|
||||
if (!container) return;
|
||||
|
||||
if (panels.length === 0) {
|
||||
container.innerHTML = '<div class="empty-message">Aucun panel de rôles configuré.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = panels.map(panel => {
|
||||
const statusClass = panel.enabled ? 'status-active' : 'status-inactive';
|
||||
const statusText = panel.enabled ? 'Actif' : 'Inactif';
|
||||
const buttonCount = panel.buttons ? panel.buttons.length : 0;
|
||||
const channel = channels.find(c => c.id === panel.channel_id);
|
||||
|
||||
return `
|
||||
<div class="panel-item" data-panel-id="${panel.id}">
|
||||
<div class="panel-item-header">
|
||||
<div class="panel-item-info">
|
||||
<span class="panel-status ${statusClass}"></span>
|
||||
<h4>${panel.name}</h4>
|
||||
<span class="panel-meta">${buttonCount} boutons • #${channel?.name || 'inconnu'}</span>
|
||||
</div>
|
||||
<div class="panel-item-actions">
|
||||
<button class="btn btn-sm btn-secondary" onclick="editPanelButtons(${panel.id})">🔘 Boutons</button>
|
||||
<button class="btn btn-sm btn-secondary" onclick="editPanel(${panel.id})">✏️ Modifier</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="deletePanel(${panel.id})">🗑️</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-item-preview">
|
||||
<div class="preview-embed" style="border-left-color: ${panel.color || '#5865F2'}">
|
||||
<div class="preview-title">${panel.title || '🎭 Choisissez vos rôles'}</div>
|
||||
<div class="preview-desc">${panel.description || ''}</div>
|
||||
<div class="preview-buttons">
|
||||
${(panel.buttons || []).slice(0, 5).map(btn => `
|
||||
<span class="preview-btn preview-btn-${btn.style || 'primary'}">${btn.emoji || ''} ${btn.label}</span>
|
||||
`).join('')}
|
||||
${buttonCount > 5 ? `<span class="preview-more">+${buttonCount - 5} autres</span>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// Ouvrir le modal de création
|
||||
function openCreateModal() {
|
||||
document.getElementById('panel-modal-title').textContent = 'Créer un panel';
|
||||
document.getElementById('edit-panel-id').value = '';
|
||||
document.getElementById('panel-name').value = '';
|
||||
document.getElementById('panel-name').disabled = false;
|
||||
document.getElementById('panel-title').value = '';
|
||||
document.getElementById('panel-description').value = '';
|
||||
document.getElementById('panel-color').value = '#5865F2';
|
||||
document.getElementById('panel-mode').value = 'toggle';
|
||||
document.getElementById('panel-exclusive').checked = false;
|
||||
document.getElementById('panel-required-role').value = '';
|
||||
document.getElementById('panel-image').value = '';
|
||||
document.getElementById('panel-thumbnail').value = '';
|
||||
document.getElementById('panel-modal').style.display = 'flex';
|
||||
}
|
||||
|
||||
// Ouvrir le modal d'édition
|
||||
window.editPanel = function(panelId) {
|
||||
const panel = panels.find(p => p.id === panelId);
|
||||
if (!panel) return;
|
||||
|
||||
document.getElementById('panel-modal-title').textContent = 'Modifier le panel';
|
||||
document.getElementById('edit-panel-id').value = panelId;
|
||||
document.getElementById('panel-name').value = panel.name;
|
||||
document.getElementById('panel-name').disabled = true;
|
||||
document.getElementById('panel-channel').value = panel.channel_id;
|
||||
document.getElementById('panel-title').value = panel.title || '';
|
||||
document.getElementById('panel-description').value = panel.description || '';
|
||||
document.getElementById('panel-color').value = panel.color || '#5865F2';
|
||||
document.getElementById('panel-mode').value = panel.mode || 'toggle';
|
||||
document.getElementById('panel-exclusive').checked = panel.exclusive;
|
||||
document.getElementById('panel-required-role').value = panel.required_role_id || '';
|
||||
document.getElementById('panel-image').value = panel.image_url || '';
|
||||
document.getElementById('panel-thumbnail').value = panel.thumbnail_url || '';
|
||||
document.getElementById('panel-modal').style.display = 'flex';
|
||||
};
|
||||
|
||||
// Fermer le modal
|
||||
function closeModal(modalId) {
|
||||
document.getElementById(modalId).style.display = 'none';
|
||||
}
|
||||
|
||||
// Sauvegarder le panel
|
||||
async function savePanel() {
|
||||
const panelId = document.getElementById('edit-panel-id').value;
|
||||
const isEdit = !!panelId;
|
||||
|
||||
const data = {
|
||||
guildId,
|
||||
name: document.getElementById('panel-name').value,
|
||||
channelId: document.getElementById('panel-channel').value,
|
||||
title: document.getElementById('panel-title').value,
|
||||
description: document.getElementById('panel-description').value,
|
||||
color: document.getElementById('panel-color').value,
|
||||
mode: document.getElementById('panel-mode').value,
|
||||
exclusive: document.getElementById('panel-exclusive').checked,
|
||||
requiredRoleId: document.getElementById('panel-required-role').value || null,
|
||||
imageUrl: document.getElementById('panel-image').value || null,
|
||||
thumbnailUrl: document.getElementById('panel-thumbnail').value || null,
|
||||
enabled: true
|
||||
};
|
||||
|
||||
if (!data.name) {
|
||||
showStatus('status-panel-form', '❌ Le nom est requis', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const statusEl = document.getElementById('status-panel-form');
|
||||
statusEl.textContent = 'Sauvegarde en cours...';
|
||||
|
||||
try {
|
||||
let res;
|
||||
if (isEdit) {
|
||||
data.panelId = panelId;
|
||||
res = await fetch('/api/bot/update-role-panel', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
} else {
|
||||
res = await fetch('/api/bot/create-role-panel', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (result.success) {
|
||||
showStatus('status-panel-form', '✅ Panel sauvegardé !', 'success');
|
||||
setTimeout(() => {
|
||||
closeModal('panel-modal');
|
||||
loadRolePanels();
|
||||
}, 1000);
|
||||
} else {
|
||||
showStatus('status-panel-form', '❌ ' + (result.error || 'Erreur'), 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur sauvegarde panel:', err);
|
||||
showStatus('status-panel-form', '❌ Erreur de connexion', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Supprimer un panel
|
||||
window.deletePanel = async function(panelId) {
|
||||
if (!confirm('Êtes-vous sûr de vouloir supprimer ce panel ? Le message sera également supprimé.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/bot/delete-role-panel', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ guildId, panelId })
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (result.success) {
|
||||
loadRolePanels();
|
||||
} else {
|
||||
alert('Erreur: ' + (result.error || 'Erreur inconnue'));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur suppression panel:', err);
|
||||
alert('Erreur de connexion');
|
||||
}
|
||||
};
|
||||
|
||||
// Ouvrir le modal des boutons
|
||||
window.editPanelButtons = function(panelId) {
|
||||
const panel = panels.find(p => p.id === panelId);
|
||||
if (!panel) return;
|
||||
|
||||
currentPanelId = panelId;
|
||||
document.getElementById('buttons-modal-title').textContent = `Boutons: ${panel.name}`;
|
||||
document.getElementById('buttons-panel-id').value = panelId;
|
||||
|
||||
renderButtonsList(panel.buttons || []);
|
||||
document.getElementById('buttons-modal').style.display = 'flex';
|
||||
};
|
||||
|
||||
// Afficher la liste des boutons
|
||||
function renderButtonsList(buttons) {
|
||||
const container = document.getElementById('panel-buttons-list');
|
||||
|
||||
if (buttons.length === 0) {
|
||||
container.innerHTML = '<div class="empty-message">Aucun bouton configuré. Ajoutez-en un ci-dessous.</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = buttons.map((btn, index) => {
|
||||
const role = roles.find(r => r.id === btn.role_id);
|
||||
const statusClass = btn.enabled ? '' : 'button-disabled';
|
||||
|
||||
return `
|
||||
<div class="button-item ${statusClass}" data-button-id="${btn.id}">
|
||||
<div class="button-preview">
|
||||
<span class="preview-btn preview-btn-${btn.style || 'primary'}">${btn.emoji || ''} ${btn.label}</span>
|
||||
</div>
|
||||
<div class="button-info">
|
||||
<span class="button-role">→ @${role?.name || 'Rôle inconnu'}</span>
|
||||
</div>
|
||||
<div class="button-actions">
|
||||
<button class="btn btn-xs btn-secondary" onclick="toggleButton(${btn.id}, ${!btn.enabled})">${btn.enabled ? '🔴 Désactiver' : '🟢 Activer'}</button>
|
||||
<button class="btn btn-xs btn-danger" onclick="deleteButton(${btn.id})">🗑️</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// Ajouter un bouton
|
||||
async function addButton() {
|
||||
const panelId = document.getElementById('buttons-panel-id').value;
|
||||
const roleId = document.getElementById('new-button-role').value;
|
||||
const label = document.getElementById('new-button-label').value;
|
||||
const emoji = document.getElementById('new-button-emoji').value;
|
||||
const style = document.getElementById('new-button-style').value;
|
||||
|
||||
if (!roleId) {
|
||||
showStatus('status-buttons-form', '❌ Sélectionnez un rôle', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const role = roles.find(r => r.id === roleId);
|
||||
const finalLabel = label || role?.name || 'Rôle';
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/bot/add-panel-button', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
panelId,
|
||||
roleId,
|
||||
label: finalLabel,
|
||||
emoji: emoji || null,
|
||||
style
|
||||
})
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (result.success) {
|
||||
showStatus('status-buttons-form', '✅ Bouton ajouté !', 'success');
|
||||
// Reset le formulaire
|
||||
document.getElementById('new-button-label').value = '';
|
||||
document.getElementById('new-button-emoji').value = '';
|
||||
// Recharger les panels
|
||||
await loadRolePanels();
|
||||
const panel = panels.find(p => p.id == panelId);
|
||||
if (panel) renderButtonsList(panel.buttons || []);
|
||||
} else {
|
||||
showStatus('status-buttons-form', '❌ ' + (result.error || 'Erreur'), 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur ajout bouton:', err);
|
||||
showStatus('status-buttons-form', '❌ Erreur de connexion', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Activer/désactiver un bouton
|
||||
window.toggleButton = async function(buttonId, enabled) {
|
||||
try {
|
||||
const res = await fetch('/api/bot/update-panel-button', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
guildId,
|
||||
buttonId,
|
||||
enabled,
|
||||
// On garde les autres valeurs
|
||||
roleId: panels.flatMap(p => p.buttons || []).find(b => b.id === buttonId)?.role_id,
|
||||
label: panels.flatMap(p => p.buttons || []).find(b => b.id === buttonId)?.label,
|
||||
emoji: panels.flatMap(p => p.buttons || []).find(b => b.id === buttonId)?.emoji,
|
||||
style: panels.flatMap(p => p.buttons || []).find(b => b.id === buttonId)?.style,
|
||||
position: panels.flatMap(p => p.buttons || []).find(b => b.id === buttonId)?.position
|
||||
})
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (result.success) {
|
||||
await loadRolePanels();
|
||||
const panelId = document.getElementById('buttons-panel-id').value;
|
||||
const panel = panels.find(p => p.id == panelId);
|
||||
if (panel) renderButtonsList(panel.buttons || []);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur toggle bouton:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// Supprimer un bouton
|
||||
window.deleteButton = async function(buttonId) {
|
||||
if (!confirm('Supprimer ce bouton ?')) return;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/bot/delete-panel-button', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ guildId, buttonId })
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (result.success) {
|
||||
await loadRolePanels();
|
||||
const panelId = document.getElementById('buttons-panel-id').value;
|
||||
const panel = panels.find(p => p.id == panelId);
|
||||
if (panel) renderButtonsList(panel.buttons || []);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur suppression bouton:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// Publier/actualiser le panel
|
||||
async function publishPanel() {
|
||||
const panelId = document.getElementById('buttons-panel-id').value;
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/bot/publish-role-panel', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ guildId, panelId })
|
||||
});
|
||||
|
||||
const result = await res.json();
|
||||
|
||||
if (result.success) {
|
||||
showStatus('status-buttons-form', '✅ Panel publié/actualisé !', 'success');
|
||||
} else {
|
||||
showStatus('status-buttons-form', '❌ ' + (result.error || 'Erreur'), 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Erreur publication panel:', err);
|
||||
showStatus('status-buttons-form', '❌ Erreur de connexion', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Afficher un message de statut
|
||||
function showStatus(elementId, message, type) {
|
||||
const el = document.getElementById(elementId);
|
||||
if (!el) return;
|
||||
el.textContent = message;
|
||||
el.className = 'status-message ' + (type || '');
|
||||
setTimeout(() => {
|
||||
el.textContent = '';
|
||||
el.className = 'status-message';
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Event Listeners (avec vérification d'existence)
|
||||
const createPanelBtn = document.getElementById('create-panel-btn');
|
||||
const closePanelModalBtn = document.getElementById('close-panel-modal');
|
||||
const cancelPanelBtn = document.getElementById('cancel-panel-btn');
|
||||
const savePanelBtn = document.getElementById('save-panel-btn');
|
||||
const closeButtonsModalBtn = document.getElementById('close-buttons-modal');
|
||||
const addButtonBtn = document.getElementById('add-button-btn');
|
||||
const publishPanelBtn = document.getElementById('publish-panel-btn');
|
||||
const panelModal = document.getElementById('panel-modal');
|
||||
const buttonsModal = document.getElementById('buttons-modal');
|
||||
|
||||
if (createPanelBtn) createPanelBtn.addEventListener('click', openCreateModal);
|
||||
if (closePanelModalBtn) closePanelModalBtn.addEventListener('click', () => closeModal('panel-modal'));
|
||||
if (cancelPanelBtn) cancelPanelBtn.addEventListener('click', () => closeModal('panel-modal'));
|
||||
if (savePanelBtn) savePanelBtn.addEventListener('click', savePanel);
|
||||
if (closeButtonsModalBtn) closeButtonsModalBtn.addEventListener('click', () => closeModal('buttons-modal'));
|
||||
if (addButtonBtn) addButtonBtn.addEventListener('click', addButton);
|
||||
if (publishPanelBtn) publishPanelBtn.addEventListener('click', publishPanel);
|
||||
|
||||
// Fermer les modals en cliquant à l'extérieur
|
||||
if (panelModal) {
|
||||
panelModal.addEventListener('click', (e) => {
|
||||
if (e.target === e.currentTarget) closeModal('panel-modal');
|
||||
});
|
||||
}
|
||||
if (buttonsModal) {
|
||||
buttonsModal.addEventListener('click', (e) => {
|
||||
if (e.target === e.currentTarget) closeModal('buttons-modal');
|
||||
});
|
||||
}
|
||||
|
||||
// Charger au démarrage
|
||||
loadRolePanels();
|
||||
})();
|
||||
@@ -2037,5 +2037,413 @@ module.exports = (app, db, client) => {
|
||||
}
|
||||
});
|
||||
|
||||
// =============================================
|
||||
// ========== ROLE PANELS API ==================
|
||||
// =============================================
|
||||
|
||||
// Récupérer tous les panels d'un serveur
|
||||
router.get("/bot/get-role-panels", async (req, res) => {
|
||||
const { guildId } = req.query;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
const panels = await db.allAsync(
|
||||
"SELECT * FROM role_panels WHERE guild_id = ? ORDER BY created_at DESC",
|
||||
[guildId]
|
||||
);
|
||||
|
||||
// Récupérer les boutons pour chaque panel
|
||||
for (const panel of panels) {
|
||||
panel.buttons = await db.allAsync(
|
||||
"SELECT * FROM role_panel_buttons WHERE panel_id = ? ORDER BY position",
|
||||
[panel.id]
|
||||
);
|
||||
}
|
||||
|
||||
// Récupérer les salons et rôles
|
||||
const guild = client.guilds.cache.get(guildId);
|
||||
const channels = guild?.channels.cache
|
||||
.filter(c => c.type === 0)
|
||||
.map(c => ({ id: c.id, name: c.name })) || [];
|
||||
const roles = guild?.roles.cache
|
||||
.filter(r => r.id !== guildId && !r.managed)
|
||||
.sort((a, b) => b.position - a.position)
|
||||
.map(r => ({ id: r.id, name: r.name, color: r.hexColor })) || [];
|
||||
|
||||
res.json({ success: true, panels, channels, roles });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur get role panels:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Créer un nouveau panel
|
||||
router.post("/bot/create-role-panel", express.json(), async (req, res) => {
|
||||
const { guildId, name, channelId, title, description, color, mode, exclusive, requiredRoleId } = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Vérifier si un panel avec ce nom existe
|
||||
const existing = await db.getAsync(
|
||||
"SELECT id FROM role_panels WHERE guild_id = ? AND name = ?",
|
||||
[guildId, name]
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
return res.json({ success: false, error: "Un panel avec ce nom existe déjà" });
|
||||
}
|
||||
|
||||
const panelId = await new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
`INSERT INTO role_panels (guild_id, channel_id, name, title, description, color, mode, exclusive, required_role_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[guildId, channelId, name, title, description, color || '#5865F2', mode || 'toggle', exclusive ? 1 : 0, requiredRoleId || null],
|
||||
function(err) {
|
||||
if (err) reject(err);
|
||||
else resolve(this.lastID);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
res.json({ success: true, panelId });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur create role panel:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Mettre à jour un panel
|
||||
router.post("/bot/update-role-panel", express.json(), async (req, res) => {
|
||||
const { guildId, panelId, channelId, title, description, color, imageUrl, thumbnailUrl, mode, exclusive, requiredRoleId, enabled } = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
`UPDATE role_panels SET
|
||||
channel_id = ?,
|
||||
title = ?,
|
||||
description = ?,
|
||||
color = ?,
|
||||
image_url = ?,
|
||||
thumbnail_url = ?,
|
||||
mode = ?,
|
||||
exclusive = ?,
|
||||
required_role_id = ?,
|
||||
enabled = ?
|
||||
WHERE id = ? AND guild_id = ?`,
|
||||
[channelId, title, description, color, imageUrl || null, thumbnailUrl || null, mode, exclusive ? 1 : 0, requiredRoleId || null, enabled ? 1 : 0, panelId, guildId],
|
||||
(err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Mettre à jour le message Discord
|
||||
const panel = await db.getAsync("SELECT * FROM role_panels WHERE id = ?", [panelId]);
|
||||
const buttons = await db.allAsync("SELECT * FROM role_panel_buttons WHERE panel_id = ?", [panelId]);
|
||||
|
||||
if (panel && enabled) {
|
||||
const { updatePanelMessage } = require('../commands/🔧 Administration/rolepanel');
|
||||
await updatePanelMessage(client, panel, buttons);
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur update role panel:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Supprimer un panel
|
||||
router.post("/bot/delete-role-panel", express.json(), async (req, res) => {
|
||||
const { guildId, panelId } = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Récupérer le panel pour supprimer le message
|
||||
const panel = await db.getAsync("SELECT * FROM role_panels WHERE id = ? AND guild_id = ?", [panelId, guildId]);
|
||||
|
||||
if (panel && panel.message_id) {
|
||||
try {
|
||||
const guild = client.guilds.cache.get(guildId);
|
||||
const channel = guild?.channels.cache.get(panel.channel_id);
|
||||
if (channel) {
|
||||
const message = await channel.messages.fetch(panel.message_id).catch(() => null);
|
||||
if (message) await message.delete();
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// Supprimer les boutons puis le panel
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run("DELETE FROM role_panel_buttons WHERE panel_id = ?", [panelId], (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run("DELETE FROM role_panels WHERE id = ? AND guild_id = ?", [panelId, guildId], (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur delete role panel:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Ajouter un bouton à un panel
|
||||
router.post("/bot/add-panel-button", express.json(), async (req, res) => {
|
||||
const { guildId, panelId, roleId, label, emoji, style } = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Vérifier le panel
|
||||
const panel = await db.getAsync("SELECT * FROM role_panels WHERE id = ? AND guild_id = ?", [panelId, guildId]);
|
||||
if (!panel) {
|
||||
return res.json({ success: false, error: "Panel non trouvé" });
|
||||
}
|
||||
|
||||
// Vérifier le nombre de boutons
|
||||
const count = await db.getAsync("SELECT COUNT(*) as count FROM role_panel_buttons WHERE panel_id = ?", [panelId]);
|
||||
if (count.count >= 25) {
|
||||
return res.json({ success: false, error: "Limite de 25 boutons atteinte" });
|
||||
}
|
||||
|
||||
// Ajouter le bouton
|
||||
const buttonId = await new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
"INSERT INTO role_panel_buttons (panel_id, role_id, label, emoji, style, position) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
[panelId, roleId, label, emoji || null, style || 'primary', count.count],
|
||||
function(err) {
|
||||
if (err) reject(err);
|
||||
else resolve(this.lastID);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Mettre à jour le message
|
||||
const buttons = await db.allAsync("SELECT * FROM role_panel_buttons WHERE panel_id = ?", [panelId]);
|
||||
const { updatePanelMessage } = require('../commands/🔧 Administration/rolepanel');
|
||||
await updatePanelMessage(client, panel, buttons);
|
||||
|
||||
res.json({ success: true, buttonId });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur add panel button:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Mettre à jour un bouton
|
||||
router.post("/bot/update-panel-button", express.json(), async (req, res) => {
|
||||
const { guildId, buttonId, roleId, label, emoji, style, enabled, position } = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Vérifier que le bouton appartient bien à un panel de ce serveur
|
||||
const button = await db.getAsync(
|
||||
`SELECT rpb.*, rp.guild_id FROM role_panel_buttons rpb
|
||||
JOIN role_panels rp ON rpb.panel_id = rp.id
|
||||
WHERE rpb.id = ? AND rp.guild_id = ?`,
|
||||
[buttonId, guildId]
|
||||
);
|
||||
|
||||
if (!button) {
|
||||
return res.json({ success: false, error: "Bouton non trouvé" });
|
||||
}
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run(
|
||||
"UPDATE role_panel_buttons SET role_id = ?, label = ?, emoji = ?, style = ?, enabled = ?, position = ? WHERE id = ?",
|
||||
[roleId, label, emoji || null, style, enabled ? 1 : 0, position, buttonId],
|
||||
(err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Mettre à jour le message
|
||||
const panel = await db.getAsync("SELECT * FROM role_panels WHERE id = ?", [button.panel_id]);
|
||||
const buttons = await db.allAsync("SELECT * FROM role_panel_buttons WHERE panel_id = ?", [button.panel_id]);
|
||||
const { updatePanelMessage } = require('../commands/🔧 Administration/rolepanel');
|
||||
await updatePanelMessage(client, panel, buttons);
|
||||
|
||||
res.json({ success: true });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur update panel button:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Supprimer un bouton
|
||||
router.post("/bot/delete-panel-button", express.json(), async (req, res) => {
|
||||
const { guildId, buttonId } = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Vérifier que le bouton appartient à un panel de ce serveur
|
||||
const button = await db.getAsync(
|
||||
`SELECT rpb.*, rp.guild_id FROM role_panel_buttons rpb
|
||||
JOIN role_panels rp ON rpb.panel_id = rp.id
|
||||
WHERE rpb.id = ? AND rp.guild_id = ?`,
|
||||
[buttonId, guildId]
|
||||
);
|
||||
|
||||
if (!button) {
|
||||
return res.json({ success: false, error: "Bouton non trouvé" });
|
||||
}
|
||||
|
||||
const panelId = button.panel_id;
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
db.run("DELETE FROM role_panel_buttons WHERE id = ?", [buttonId], (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Mettre à jour le message
|
||||
const panel = await db.getAsync("SELECT * FROM role_panels WHERE id = ?", [panelId]);
|
||||
const buttons = await db.allAsync("SELECT * FROM role_panel_buttons WHERE panel_id = ?", [panelId]);
|
||||
const { updatePanelMessage } = require('../commands/🔧 Administration/rolepanel');
|
||||
await updatePanelMessage(client, panel, buttons);
|
||||
|
||||
res.json({ success: true });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur delete panel button:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Publier/actualiser un panel
|
||||
router.post("/bot/publish-role-panel", express.json(), async (req, res) => {
|
||||
const { guildId, panelId } = req.body;
|
||||
|
||||
if (!req.session.guilds) {
|
||||
return res.status(401).json({ success: false, error: "Non connecté" });
|
||||
}
|
||||
|
||||
const isAdmin = req.session.guilds.find(
|
||||
g => g.id === guildId && (BigInt(g.permissions) & 0x8n) === 0x8n
|
||||
);
|
||||
|
||||
if (!isAdmin) {
|
||||
return res.status(403).json({ success: false, error: "Permission refusée" });
|
||||
}
|
||||
|
||||
try {
|
||||
const panel = await db.getAsync("SELECT * FROM role_panels WHERE id = ? AND guild_id = ?", [panelId, guildId]);
|
||||
if (!panel) {
|
||||
return res.json({ success: false, error: "Panel non trouvé" });
|
||||
}
|
||||
|
||||
const buttons = await db.allAsync("SELECT * FROM role_panel_buttons WHERE panel_id = ?", [panelId]);
|
||||
|
||||
const { updatePanelMessage } = require('../commands/🔧 Administration/rolepanel');
|
||||
const messageId = await updatePanelMessage(client, panel, buttons);
|
||||
|
||||
if (messageId) {
|
||||
res.json({ success: true, messageId });
|
||||
} else {
|
||||
res.json({ success: false, error: "Erreur lors de la publication" });
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error("Erreur publish role panel:", err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.use("/api", router);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user