aboutsummaryrefslogtreecommitdiff
path: root/src/commands/config/config.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/commands/config/config.ts')
-rw-r--r--src/commands/config/config.ts339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/commands/config/config.ts b/src/commands/config/config.ts
new file mode 100644
index 0000000..7e0ddf1
--- /dev/null
+++ b/src/commands/config/config.ts
@@ -0,0 +1,339 @@
+import { BushCommand, BushMessage, BushSlashMessage, GuildSettings, guildSettingsObj, settingsArr } from '@lib';
+import { ArgumentOptions, Flag } from 'discord-akairo';
+import {
+ Formatters,
+ Message,
+ MessageActionRow,
+ MessageButton,
+ MessageComponentInteraction,
+ MessageEmbed,
+ MessageOptions,
+ MessageSelectMenu
+} from 'discord.js';
+import _ from 'lodash';
+
+export default class SettingsCommand extends BushCommand {
+ public constructor() {
+ super('config', {
+ aliases: ['config', 'settings', 'setting', 'configure'],
+ category: 'config',
+ description: {
+ content: 'Configure server settings.',
+ usage: `settings (${settingsArr.map((s) => `\`${s}\``).join(', ')}) (${['view', 'set', 'add', 'remove'].map(
+ (s) => `\`${s}\``
+ )})`,
+ examples: ['settings', 'config prefix set -']
+ },
+ slash: true,
+ slashOptions: settingsArr.map((setting) => {
+ return {
+ name: _.snakeCase(setting),
+ description: `Manage the server's ${guildSettingsObj[setting].name.toLowerCase()}`,
+ type: 'SUB_COMMAND_GROUP',
+ options: guildSettingsObj[setting].type.includes('-array')
+ ? [
+ {
+ name: 'view',
+ description: `View the server's ${guildSettingsObj[setting].name.toLowerCase()}.`,
+ type: 'SUB_COMMAND'
+ },
+ {
+ name: 'add',
+ description: `Add a value to the server's ${guildSettingsObj[setting].name.toLowerCase()}.`,
+ type: 'SUB_COMMAND',
+ options: [
+ {
+ name: 'value',
+ description: `What would you like to add to the server's ${guildSettingsObj[
+ setting
+ ].name.toLowerCase()}?'`,
+ type: guildSettingsObj[setting].type.replace('-array', '').toUpperCase() as 'ROLE' | 'STRING' | 'CHANNEL',
+ required: true
+ }
+ ]
+ },
+ {
+ name: 'remove',
+ description: `Remove a value from the server's ${guildSettingsObj[setting].name.toLowerCase()}.`,
+ type: 'SUB_COMMAND',
+ options: [
+ {
+ name: 'value',
+ description: `What would you like to remove from the server's ${guildSettingsObj[
+ setting
+ ].name.toLowerCase()}?'`,
+ type: guildSettingsObj[setting].type.replace('-array', '').toUpperCase() as 'ROLE' | 'STRING' | 'CHANNEL',
+ required: true
+ }
+ ]
+ }
+ ]
+ : [
+ {
+ name: 'view',
+ description: `View the server's ${guildSettingsObj[setting].name.toLowerCase()}.`,
+ type: 'SUB_COMMAND'
+ },
+ {
+ name: 'set',
+ description: `Set the server's ${guildSettingsObj[setting].name.toLowerCase()}.`,
+ type: 'SUB_COMMAND',
+ options: [
+ {
+ name: 'value',
+ description: `What would you like to set the server's ${guildSettingsObj[
+ setting
+ ].name.toLowerCase()} to?'`,
+ type: guildSettingsObj[setting].type.toUpperCase() as 'ROLE' | 'STRING' | 'CHANNEL',
+ required: true
+ }
+ ]
+ }
+ ]
+ };
+ }),
+ slashGuilds: ['516977525906341928', '812400566235430912'],
+ channel: 'guild',
+ clientPermissions: ['SEND_MESSAGES'],
+ userPermissions: ['SEND_MESSAGES', 'MANAGE_GUILD'],
+ ownerOnly: true
+ });
+ }
+
+ // I make very readable code :)
+ *args(message: BushMessage): IterableIterator<ArgumentOptions | Flag> {
+ const setting = yield {
+ id: 'setting',
+ type: settingsArr,
+ prompt: {
+ start: `What setting would you like to see or change? You can choose one of the following: ${settingsArr
+ .map((s) => `\`${s}\``)
+ .join(', ')}`,
+ retry: `{error} Choose one of the following settings: ${settingsArr.map((s) => `\`${s}\``).join(', ')}`,
+ optional: message.util.parsed!.alias === 'settings'
+ }
+ };
+
+ const action = setting
+ ? yield {
+ id: 'action',
+ type: guildSettingsObj[setting as unknown as GuildSettings].type.includes('-array')
+ ? ['view', 'add', 'remove']
+ : ['view', 'set'],
+ prompt: {
+ start: `Would you like to ${util.oxford(
+ (guildSettingsObj[setting as unknown as GuildSettings].type.includes('-array')
+ ? ['view', 'add', 'remove']
+ : ['view', 'set']
+ ).map((a) => `\`${a}\``),
+ 'or'
+ )} the \`${setting}\` setting?`,
+ retry: `{error} Choose one of the following actions to perform on the \`${setting}\` setting: ${util.oxford(
+ (guildSettingsObj[setting as unknown as GuildSettings].type.includes('-array')
+ ? ['view', 'add', 'remove']
+ : ['view', 'set']
+ ).map((a) => `\`${a}\``),
+ 'or'
+ )}`,
+ optional: message.util.parsed!.alias === 'settings'
+ }
+ }
+ : undefined;
+
+ const value =
+ setting && action && action !== 'view'
+ ? yield {
+ id: 'value',
+ type: 'string',
+ match: 'restContent',
+ prompt: {
+ start: `What would you like to ${action} ${
+ (action as unknown as 'add' | 'remove' | 'set') === 'add'
+ ? `to the ${setting} setting`
+ : (action as unknown as 'remove' | 'set') === 'remove'
+ ? `from the ${setting} setting`
+ : `the ${setting} setting to`
+ }?`,
+ retry: `{error} You must choose a value to ${action} ${
+ (action as unknown as 'add' | 'remove' | 'set') === 'add'
+ ? `to the ${setting} setting`
+ : (action as unknown as 'remove' | 'set') === 'remove'
+ ? `from the ${setting} setting`
+ : `the ${setting} setting to`
+ }.`,
+ optional: message.util.parsed!.alias === 'settings'
+ }
+ }
+ : undefined;
+
+ return { setting, action, value };
+ }
+
+ public override async exec(
+ message: BushMessage | BushSlashMessage,
+ args: { [x in GuildSettings | ('view' | 'set' | 'add' | 'remove') | ('setting' | 'action') | 'value']: string | undefined }
+ ): Promise<unknown> {
+ if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be used in servers.`);
+ if (!message.member?.permissions.has('MANAGE_GUILD'))
+ return await message.util.reply(
+ `${util.emojis.error} You must have the **MANAGE_GUILD** permissions to run this command.`
+ );
+ const setting = _.camelCase(args[settingsArr.find((s) => args[s]) ?? 'setting']) as GuildSettings | undefined;
+ const action = (args[
+ (['view', 'set', 'add', 'remove'] as ('view' | 'set' | 'add' | 'remove')[]).find((a) => args[a]) ?? 'action'
+ ] ?? 'view') as 'view' | 'set' | 'add' | 'remove';
+ const value = args.value;
+
+ let msg;
+
+ if (!setting || action === 'view') {
+ const messageOptions = await this.generateMessageOptions(message, setting ?? undefined);
+ msg = (await message.util.reply(messageOptions)) as Message;
+ } else {
+ if (!value)
+ return await message.util.reply(
+ `${util.emojis.error} You must choose a value to ${action} ${
+ (action as unknown as 'add' | 'remove' | 'set') === 'add'
+ ? `to the ${setting} setting`
+ : (action as unknown as 'remove' | 'set') === 'remove'
+ ? `from the ${setting} setting`
+ : `the ${setting} setting to`
+ }`
+ );
+ switch (action) {
+ case 'add':
+ case 'remove': {
+ const existing = (await message.guild.getSetting(setting)) as string[];
+ const updated = util.addOrRemoveFromArray('add', existing, value);
+ await message.guild.setSetting(setting, updated);
+ const messageOptions = await this.generateMessageOptions(message);
+ msg = (await message.util.reply(messageOptions)) as Message;
+ break;
+ }
+ case 'set': {
+ await message.guild.setSetting(setting, value);
+ const messageOptions = await this.generateMessageOptions(message);
+ msg = (await message.util.reply(messageOptions)) as Message;
+ break;
+ }
+ }
+ }
+ const collector = msg.createMessageComponentCollector({
+ channel: message.channel ?? undefined,
+ guild: message.guild,
+ message: message as Message,
+ time: 300_000
+ });
+
+ collector.on('collect', async (interaction: MessageComponentInteraction) => {
+ if (interaction.user.id === message.author.id || client.config.owners.includes(interaction.user.id)) {
+ if (!message.guild) throw new Error('message.guild is null');
+ switch (interaction.customId) {
+ case 'command_settingsSel': {
+ if (!interaction.isSelectMenu()) return;
+
+ return interaction.update(
+ await this.generateMessageOptions(message, interaction.values[0] as keyof typeof guildSettingsObj)
+ );
+ }
+ case 'command_settingsBack': {
+ if (!interaction.isButton()) return;
+
+ return interaction.update(await this.generateMessageOptions(message));
+ }
+ }
+ } else {
+ return await interaction?.deferUpdate().catch(() => undefined);
+ }
+ });
+ }
+
+ public async generateMessageOptions(
+ message: BushMessage | BushSlashMessage,
+ feature?: undefined | keyof typeof guildSettingsObj
+ ): Promise<MessageOptions> {
+ if (!message.guild) throw new Error('message.guild is null');
+ const settingsEmbed = new MessageEmbed().setColor(util.colors.default);
+ if (!feature) {
+ settingsEmbed.setTitle(`${message.guild!.name}'s Settings`);
+ const desc = settingsArr.map((s) => `**${guildSettingsObj[s].name}**`).join('\n');
+ settingsEmbed.setDescription(desc);
+
+ const selMenu = new MessageActionRow().addComponents(
+ new MessageSelectMenu()
+ .addOptions(
+ ...settingsArr.map((s) => ({
+ label: guildSettingsObj[s].name,
+ value: s,
+ description: guildSettingsObj[s].description
+ }))
+ )
+ .setPlaceholder('Select A Setting to View')
+ .setMaxValues(1)
+ .setMinValues(1)
+ .setCustomId('command_settingsSel')
+ );
+ return { embeds: [settingsEmbed], components: [selMenu] };
+ } else {
+ settingsEmbed.setTitle(guildSettingsObj[feature].name);
+ const generateCurrentValue = async (
+ type: 'string' | 'channel' | 'channel-array' | 'role' | 'role-array'
+ ): Promise<string> => {
+ const feat = await message.guild!.getSetting(feature);
+ console.debug(feat);
+ console.debug(type.replace('-array', ''));
+ switch (type.replace('-array', '') as 'string' | 'channel' | 'role') {
+ case 'string': {
+ return Array.isArray(feat)
+ ? feat.length
+ ? feat.map((feat) => util.discord.escapeInlineCode(util.inspectAndRedact(feat))).join('\n')
+ : '[Empty Array]'
+ : feat !== null
+ ? util.discord.escapeInlineCode(util.inspectAndRedact(feat))
+ : '[No Value Set]';
+ }
+ case 'channel': {
+ return Array.isArray(feat)
+ ? feat.length
+ ? feat.map((feat) => `<#${feat}>`).join('\n')
+ : '[Empty Array]'
+ : `<#${feat}>`;
+ }
+ case 'role': {
+ return Array.isArray(feat)
+ ? feat.length
+ ? feat.map((feat) => `<@&${feat}>`).join('\n')
+ : '[Empty Array]'
+ : `<@&${feat}>`;
+ }
+ }
+ };
+
+ const components = new MessageActionRow().addComponents(
+ new MessageButton().setStyle('PRIMARY').setCustomId('command_settingsBack').setLabel('Back')
+ );
+ settingsEmbed.setDescription(
+ `${Formatters.italic(guildSettingsObj[feature].description)}\n\n**Type**: ${guildSettingsObj[feature].type}`
+ );
+
+ settingsEmbed.setFooter(
+ `Run "${
+ message.util.isSlash
+ ? '/'
+ : client.config.isDevelopment
+ ? 'dev '
+ : message.util.parsed?.prefix ?? client.config.prefix
+ }settings ${feature} ${
+ guildSettingsObj[feature].type.includes('-array') ? 'add/remove' : 'set'
+ } <value>" to set this setting.`
+ );
+ settingsEmbed.addField(
+ 'value',
+ (await generateCurrentValue(
+ guildSettingsObj[feature].type as 'string' | 'channel' | 'channel-array' | 'role' | 'role-array'
+ )) || '[No Value Set]'
+ );
+ return { embeds: [settingsEmbed], components: [components] };
+ }
+ }
+}