121 lines
5.1 KiB
JavaScript
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 */ }
|
|
});
|
|
},
|
|
};
|