const { MessageAttachment } = require('discord.js'); const { Command } = require('../../../../interfaces'); const { stripIndents } = require('common-tags'); class SettingsCommand extends Command { constructor(client) { super(client, { name: 'settings', module: 'utility', aliases: [ 'setting', 'set' ], usage: "[list|reset|setting-name] ", arguments: [ { name: 'user', type: 'BOOLEAN', types: ['VERBAL', 'FLAG'], default: true }, { name: 'all', type: 'BOOLEAN', types: ['VERBAL', 'FLAG'], default: true }, { name: 'raw', aliases: ['json'], type: 'BOOLEAN', types: ['VERBAL', 'FLAG'], default: true } ], showUsage: true, examples: [ 'prefix !', 'modlogs #channel' ], throttling: { usages: 1, duration: 3 } }); this.client = client; } async execute(message, { params, args }) { const type = (!message.guild || args.user) ? 'USER' : 'GUILD'; if(args.raw) return this._showRaw(message, type); const target = params[0].toLowerCase(); // params[0] should never be null, see showUsage if(target === 'list') { this._listSettings(message, type, Boolean(args.all)); return undefined; } else if(target === 'reset') { if(type === 'GUILD' && !this._checkAdministrator(message)) return undefined; //does not have admin const prompt = await message.prompt(message.format('C_SETTINGS_RESET', { type: type.toLowerCase() }), { emoji: 'warning' }); return await this._handleReset(prompt, message, type); } const settings = this.client.resolver.components(target, 'setting', false).sort(c=>c.resolve === type); const [ setting ] = settings; if(!setting) { await message.respond(message.format('C_SETTINGS_NONEXISTANT'), { emoji: 'failure' }); return undefined; } //Setting permission handling if(setting.clientPermissions.length > 0 && setting.resolve === 'GUILD') { const missing = message.channel.permissionsFor(message.guild.me).missing(setting.clientPermissions); if(missing.length > 0) { await message.respond(message.format('C_SETTINGS_CLIENTPERMISSIONERROR', { setting: setting.moduleResolveable, missing: missing.join(', ')}), { emoji: 'failure' }); return undefined; } } message._settingCaller = target; if(setting.resolve === 'GUILD' && !this._checkAdministrator(message)) return undefined; //does not have admin const parameters = params.splice(1); if(!parameters || parameters.length === 0) { await this._showSetting(message, setting) return undefined; } if(parameters.join(' ').toLowerCase() === 'reset') { const { msg } = await setting._handleReset(message); return message.respond(msg, { emoji: 'success' }); } const response = await setting.handle(message, parameters); if(response.ignore) return undefined; message.respond(response.msg, { emoji: response.error ? 'failure' : 'success', embed: response.embed || null }); } _listSettings(message, type, all) { if(!message.guild && type === 'GUILD') type = 'USER'; const prefix = message.guild?.prefix; let fields = []; const sorted = this.client.registry.components .filter(c=>c.type == 'module') .sort((a, b) => { const filter = c=>c.type === 'setting'; return b.components.filter(filter).size - a.components.filter(filter).size; }); for(const module of sorted.values()) { let field = { name: module.id, value: '', inline: true }; for(const setting of module.components.values()) { if(setting.type !== 'setting' || (setting.resolve !== type && !all) || (!setting.archivable && !all)) continue; field.value += `\`${setting.display}\`\n`; } if(field.value) fields.push(field); } const embed = { author: { name: `${type === 'GUILD' ? message.format('C_SETTINGS_GUILDSETTINGSTITLE') : message.format('C_SETTINGS_USERSETTINGSTITLE')}`, icon_url: type === 'GUILD' ? message.guild.iconURL() : message.author.avatarURL() }, description: stripIndents`${message.format('C_SETTINGS_LISTSETTINGS', { prefix })} ${type === 'USER' ? '' : message.format('C_SETTINGS_LISTSETTINGSALT', { prefix })}`, fields }; return message.embed(embed); } async _showSetting(message, setting) { const prefix = message.guild.prefix; let description = stripIndents`\`${prefix}settings ${setting.name}${setting.usage ? ` ${setting.usage}` : ''}\` ${setting.resolve === 'GUILD' ? ' *(guild-only)*' : '*(user-only)*'} ${message.format(setting.description)}`; if(setting.examples.length > 0) { description += `\n\n__${message.format('GENERAL_EXAMPLES')}__`; for(let example of setting.examples) { description += `\n\`${prefix}settings ${example}\``; } } let fields = setting.fields(message.guild); if(fields instanceof Promise) fields = await fields; const embed = { author: { name: `${setting.name} (${setting.module.resolveable})`, icon_url: this.client.user.displayAvatarURL() }, description, fields } return await message.embed(embed); } async _handleReset(prompt, message, type) { if(!prompt) return; const response = prompt.content.toLowerCase(); const bool = this.client.resolver.resolveBoolean(response); if(bool === null) return message.respond(message.format('C_SETTINGS_RESETERROR'), { emoji: 'failure' }); if(!bool) return message.respond(message.format('C_SETTINGS_RESETABORT'), { emoji: 'success' }); type === 'USER' ? await message.author._deleteSettings() : await message.guild._deleteSettings(); return message.respond(message.format('C_SETTINGS_RESETSUCCESS', { type: type.toLowerCase() }), { emoji: 'success' }) } async _showRaw(message, type) { const settings = type === 'USER' ? message.author._settings : message.guild._settings; const string = JSON.stringify(settings); const attachment = new MessageAttachment(Buffer.from(string), "settings.json"); return await message.respond(message.format('C_SETTINGS_JSON'), { emoji: 'success', attachments: [ attachment ] }) } _checkAdministrator(message) { const missing = message.channel.permissionsFor(message.member).missing(['ADMINISTRATOR']); if(missing > 0) { message.respond(message.format('C_SETTINGS_ADMINISTRATORERROR'), { emoji: 'failure' }) return false; } else { return true; } } } module.exports = SettingsCommand;