Files
ECS-FullStack/discord-bot/commands/manage-commands.js

121 lines
5.1 KiB
JavaScript

const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, PermissionsBitField } = require('discord.js');
const api = require('../api');
module.exports = {
name: 'manage-commands',
description: 'Admin: List bot commands and toggle them Enabled/Disabled for this server.',
enabled: true,
builder: new SlashCommandBuilder()
.setName('manage-commands')
.setDescription('Admin: List bot commands and toggle them Enabled/Disabled for this server.'),
async execute(interaction) {
// Only allow administrators
if (!interaction.member.permissions.has(PermissionsBitField.Flags.Administrator)) {
await interaction.reply({ content: 'You must be a server administrator to use this command.', flags: 64 });
return;
}
const existingSettings = (await api.getServerSettings(interaction.guildId)) || {};
if (!existingSettings.commandToggles) existingSettings.commandToggles = {};
let toggles = existingSettings.commandToggles;
// Include all loaded commands so simple command modules (no SlashCommandBuilder) like
// `ping` are also listed. Filter for objects with a name for safety.
const commands = Array.from(interaction.client.commands.values()).filter(cmd => cmd && cmd.name);
// Build button components (max 5 rows, 5 buttons per row)
const actionRows = [];
let currentRow = new ActionRowBuilder();
let buttonsInRow = 0;
const protectedCommands = ['manage-commands', 'help'];
const buildButton = (cmd) => {
if (protectedCommands.includes(cmd.name)) return null;
const isEnabled = toggles[cmd.name] !== false && cmd.enabled !== false;
return new ButtonBuilder()
.setCustomId(`toggle_cmd_${cmd.name}`)
.setLabel(`${cmd.name} : ${isEnabled ? 'ENABLED' : 'DISABLED'}`)
.setStyle(isEnabled ? ButtonStyle.Success : ButtonStyle.Secondary);
};
for (const cmd of commands) {
const btn = buildButton(cmd);
if (btn) {
currentRow.addComponents(btn);
buttonsInRow++;
if (buttonsInRow === 5) {
actionRows.push(currentRow);
currentRow = new ActionRowBuilder();
buttonsInRow = 0;
}
}
}
if (buttonsInRow > 0) actionRows.push(currentRow);
const description = commands.map(cmd => `${cmd.name}${cmd.description || 'No description.'}${protectedCommands.includes(cmd.name) ? ' (locked)' : ''}`).join('\n');
await interaction.reply({ content: `Manage Commands for this server:\n\n${description}`, components: actionRows, flags: 64 });
const message = await interaction.fetchReply();
// Collector to handle button presses for 5 minutes
const filter = i => i.user.id === interaction.user.id && i.customId.startsWith('toggle_cmd_');
const collector = message.createMessageComponentCollector({ filter, time: 5 * 60 * 1000 });
collector.on('collect', async i => {
const cmdName = i.customId.replace('toggle_cmd_', '');
const newVal = !(toggles[cmdName] !== false);
// persist via backend API
try {
await api.toggleCommand(interaction.guildId, cmdName, newVal);
// fetch authoritative list to rebuild buttons
const fresh = await api.getCommands(interaction.guildId);
toggles = {};
for (const c of fresh) {
toggles[c.name] = c.enabled;
}
} catch (e) {
console.error('Error persisting command toggle:', e);
}
// rebuild buttons to reflect new state
const updatedRows = [];
let r = new ActionRowBuilder();
let count = 0;
for (const cmd of commands) {
if (protectedCommands.includes(cmd.name)) continue;
const btn = new ButtonBuilder()
.setCustomId(`toggle_cmd_${cmd.name}`)
.setLabel(`${cmd.name} : ${(toggles[cmd.name] !== false && cmd.enabled !== false) ? 'ENABLED' : 'DISABLED'}`)
.setStyle((toggles[cmd.name] !== false && cmd.enabled !== false) ? ButtonStyle.Success : ButtonStyle.Secondary);
r.addComponents(btn);
count++;
if (count === 5) { updatedRows.push(r); r = new ActionRowBuilder(); count = 0; }
}
if (count > 0) updatedRows.push(r);
await i.update({ content: `Manage Commands for this server:\n\n${description}`, components: updatedRows });
});
collector.on('end', async () => {
// disable buttons after collector ends
const disabledRows = [];
let rr = new ActionRowBuilder();
let ccount = 0;
for (const cmd of commands) {
if (protectedCommands.includes(cmd.name)) continue;
const btn = new ButtonBuilder()
.setCustomId(`toggle_cmd_${cmd.name}`)
.setLabel(`${cmd.name} : ${(toggles[cmd.name] !== false && cmd.enabled !== false) ? 'ENABLED' : 'DISABLED'}`)
.setStyle((toggles[cmd.name] !== false && cmd.enabled !== false) ? ButtonStyle.Success : ButtonStyle.Secondary)
.setDisabled(true);
rr.addComponents(btn);
ccount++;
if (ccount === 5) { disabledRows.push(rr); rr = new ActionRowBuilder(); ccount = 0; }
}
if (ccount > 0) disabledRows.push(rr);
try { await message.edit({ components: disabledRows }); } catch (e) { /* ignore */ }
});
},
};