162 lines
5.8 KiB
JavaScript
162 lines
5.8 KiB
JavaScript
|
const { SlashCommand, CommandOption } = require("../../../interfaces");
|
||
|
const { Constants: { PermissionNames } } = require('../../../../constants');
|
||
|
const Util = require('../../../../Util.js');
|
||
|
|
||
|
class SettingsCommand extends SlashCommand {
|
||
|
|
||
|
constructor(client) {
|
||
|
super(client, {
|
||
|
name: 'settings',
|
||
|
description: "Configure the bot's behaviour in your server",
|
||
|
module: 'administration',
|
||
|
options: [
|
||
|
new CommandOption({
|
||
|
type: 'SUB_COMMAND',
|
||
|
name: 'list',
|
||
|
description: 'List available settings'
|
||
|
})
|
||
|
],
|
||
|
guildOnly: true
|
||
|
});
|
||
|
|
||
|
this.build();
|
||
|
|
||
|
}
|
||
|
|
||
|
// Constructs the command tree for settings
|
||
|
// Idk if this is where we want this functionality to be
|
||
|
build() {
|
||
|
|
||
|
const allSettings = this.client.registry.components
|
||
|
.filter((c) => c._type === 'setting');
|
||
|
// Organise modules into subcommand groups
|
||
|
const modules = new Set(allSettings.map((set) => set.module.name));
|
||
|
|
||
|
for (const module of modules) {
|
||
|
const settingsModule = allSettings.filter((s) => s.module.name === module);
|
||
|
// /settings moderation
|
||
|
const moduleSubcommand = new CommandOption({
|
||
|
name: module,
|
||
|
description: `Configure ${module} settings`,
|
||
|
type: 'SUB_COMMAND_GROUP'
|
||
|
});
|
||
|
for (const setting of settingsModule.values()) {
|
||
|
// Each setting becomes its own subcommand with options defined in the settings
|
||
|
// /settings moderation mute role:@muted permanent:false default:1h type:1
|
||
|
const settingSubcommand = new CommandOption({
|
||
|
name: setting.name,
|
||
|
description: setting.description,
|
||
|
type: 'SUB_COMMAND',
|
||
|
options: setting.commandOptions
|
||
|
});
|
||
|
moduleSubcommand.options.push(settingSubcommand);
|
||
|
}
|
||
|
this.options.push(moduleSubcommand);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async execute(interaction, opts) {
|
||
|
|
||
|
const { guild } = interaction;
|
||
|
const settingName = interaction.subcommand.name;
|
||
|
|
||
|
if (settingName === 'list') return this._listSettings(interaction);
|
||
|
|
||
|
const [setting] = this.client.resolver.components(settingName, 'setting');
|
||
|
if (!setting) return interaction.reply('Something went wrong, could not find setting');
|
||
|
|
||
|
if (setting.clientPermissions.length) {
|
||
|
const missing = guild.me.permissions.missing(setting.clientPermissions);
|
||
|
if (missing.length) return interaction.reply({
|
||
|
emoji: 'failure',
|
||
|
index: 'SETTING_MISSINGCLIENTPERMISSIONS',
|
||
|
params: { permissions: missing.map((m) => `\`${PermissionNames[m]}\``).join(', ') }
|
||
|
});
|
||
|
}
|
||
|
|
||
|
await interaction.deferReply();
|
||
|
const settings = await guild.settings();
|
||
|
if (!Object.keys(opts).length) return this._showSetting(interaction, setting);
|
||
|
|
||
|
try {
|
||
|
// Pass setting values copy so the changes don't persist unless successful and actually saved
|
||
|
const _setting = { ...settings[setting.name] };
|
||
|
const result = await setting.execute(interaction, opts, _setting);
|
||
|
|
||
|
if (result) {
|
||
|
|
||
|
const obj = { components: [], params: {}, ...result };
|
||
|
obj.params.setting = setting.name;
|
||
|
|
||
|
if (!result.error) {
|
||
|
settings[setting.name] = _setting;
|
||
|
await guild.updateSettings(settings);
|
||
|
await interaction.reply({ ...obj, emoji: 'success', _edit: interaction.replied });
|
||
|
} else {
|
||
|
await interaction.reply({ ...obj, emoji: 'failure', _edit: interaction.replied });
|
||
|
}
|
||
|
}
|
||
|
} catch (err) {
|
||
|
this.client.logger.error(`Error during setting execution:\n${err.stack || err}`);
|
||
|
await interaction.editReply({
|
||
|
index: 'SETTINGS_ERROR',
|
||
|
params: { resolveable: setting.resolveable },
|
||
|
emoji: 'failure'
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (!interaction.replied) await interaction.reply({
|
||
|
index: 'SETTINGS_NO_REPLY',
|
||
|
params: { resolveable: setting.resolveable }
|
||
|
});
|
||
|
|
||
|
}
|
||
|
|
||
|
async _listSettings(interaction) {
|
||
|
|
||
|
const { settings } = this.client.registry;
|
||
|
const modules = settings.reduce((acc, setting) => {
|
||
|
const { name } = setting.module;
|
||
|
if (!acc[name]) acc[name] = [];
|
||
|
acc[name].push(setting.name);
|
||
|
return acc;
|
||
|
}, {});
|
||
|
|
||
|
const { guild } = interaction;
|
||
|
const embed = {
|
||
|
title: 'Settings',
|
||
|
description: guild.format('SETTINGS_LIST'),
|
||
|
fields: []
|
||
|
};
|
||
|
const entries = Object.entries(modules);
|
||
|
for (const [module, values] of entries)
|
||
|
embed.fields.push({
|
||
|
name: Util.capitalise(module),
|
||
|
value: `\`${values.join('`\n`')}\``,
|
||
|
inline: true
|
||
|
});
|
||
|
|
||
|
return interaction.reply({ embeds: [embed] });
|
||
|
|
||
|
}
|
||
|
|
||
|
async _showSetting(interaction, setting) {
|
||
|
|
||
|
const { guild } = interaction;
|
||
|
const embed = setting.usageEmbed(guild);
|
||
|
const dataFields = await setting.fields(guild);
|
||
|
// eslint-disable-next-line no-return-assign
|
||
|
dataFields.forEach((field) => {
|
||
|
if (field.name.length > 1) field.name = guild.format(field.name);
|
||
|
});
|
||
|
|
||
|
embed.fields.push(...dataFields);
|
||
|
await interaction.editReply({ embeds: [embed] }).catch((error) => {
|
||
|
this.client.logger.error(`${error.stack || error}\nError context: ${JSON.stringify(embed)}`);
|
||
|
});
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
module.exports = SettingsCommand;
|