From 013860d9881060351ebc002538cc4b0e99f996d7 Mon Sep 17 00:00:00 2001 From: Neko Life Date: Mon, 28 Jun 2021 18:04:54 +0900 Subject: [PATCH] moved --- Main.js | 2 +- cmds/owner/disable.js | 49 ++++++++++++++ cmds/owner/enable.js | 55 ++++++++++++++++ cmds/owner/eval.js | 116 ++++++++++++++++++++++++++++++++++ cmds/owner/groups.js | 30 +++++++++ cmds/owner/load.js | 72 +++++++++++++++++++++ cmds/owner/reload.js | 68 ++++++++++++++++++++ cmds/owner/unknown-command.js | 36 +++++++++++ cmds/owner/unload.js | 52 +++++++++++++++ cmds/owner/update.js | 5 +- cmds/utility/help.js | 105 ++++++++++++++++++++++++++++++ cmds/utility/ping.js | 28 ++++++++ cmds/utility/prefix.js | 67 ++++++++++++++++++++ 13 files changed, 682 insertions(+), 3 deletions(-) create mode 100644 cmds/owner/disable.js create mode 100644 cmds/owner/enable.js create mode 100644 cmds/owner/eval.js create mode 100644 cmds/owner/groups.js create mode 100644 cmds/owner/load.js create mode 100644 cmds/owner/reload.js create mode 100644 cmds/owner/unknown-command.js create mode 100644 cmds/owner/unload.js create mode 100644 cmds/utility/help.js create mode 100644 cmds/utility/ping.js create mode 100644 cmds/utility/prefix.js diff --git a/Main.js b/Main.js index f21948d..af68f5d 100644 --- a/Main.js +++ b/Main.js @@ -23,6 +23,7 @@ const { timestampAt } = require("./resources/debug"); const requireAll = require("require-all"); const lgr = requireAll({ dirname: join(__dirname, "resources/eventsLogger"), recursive: true }); +client.functions = requireAll({ dirname: join(__dirname, "../../resources"), recursive: true }); client.registry .registerGroups([ @@ -34,7 +35,6 @@ client.registry "profile", "owner" ]) - .registerDefaults() .registerCommandsIn(join(__dirname, 'cmds')); client.setProvider( diff --git a/cmds/owner/disable.js b/cmds/owner/disable.js new file mode 100644 index 0000000..4d3f441 --- /dev/null +++ b/cmds/owner/disable.js @@ -0,0 +1,49 @@ +const { oneLine } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class DisableCommandCommand extends Command { + constructor(client) { + super(client, { + name: 'disable', + aliases: ['disable-command', 'cmd-off', 'command-off'], + group: 'commands', + memberName: 'disable', + description: 'Disables a command or command group.', + details: oneLine` + The argument must be the name/ID (partial or whole) of a command or command group. + Only administrators may use this command. + `, + examples: ['disable util', 'disable Utility', 'disable prefix'], + guarded: true, + + args: [ + { + key: 'cmdOrGrp', + label: 'command/group', + prompt: 'Which command or group would you like to disable?', + type: 'group|command' + } + ] + }); + } + + hasPermission(msg) { + if (!msg.guild) return this.client.isOwner(msg.author); + return msg.member.permissions.has('ADMINISTRATOR') || this.client.isOwner(msg.author); + } + + run(msg, args) { + if (!args.cmdOrGrp.isEnabledIn(msg.guild, true)) { + return msg.reply( + `The \`${args.cmdOrGrp.name}\` ${args.cmdOrGrp.group ? 'command' : 'group'} is already disabled.` + ); + } + if (args.cmdOrGrp.guarded) { + return msg.reply( + `You cannot disable the \`${args.cmdOrGrp.name}\` ${args.cmdOrGrp.group ? 'command' : 'group'}.` + ); + } + args.cmdOrGrp.setEnabledIn(msg.guild, false); + return msg.reply(`Disabled the \`${args.cmdOrGrp.name}\` ${args.cmdOrGrp.group ? 'command' : 'group'}.`); + } +}; diff --git a/cmds/owner/enable.js b/cmds/owner/enable.js new file mode 100644 index 0000000..8c97291 --- /dev/null +++ b/cmds/owner/enable.js @@ -0,0 +1,55 @@ +const { oneLine } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class EnableCommandCommand extends Command { + constructor(client) { + super(client, { + name: 'enable', + aliases: ['enable-command', 'cmd-on', 'command-on'], + group: 'commands', + memberName: 'enable', + description: 'Enables a command or command group.', + details: oneLine` + The argument must be the name/ID (partial or whole) of a command or command group. + Only administrators may use this command. + `, + examples: ['enable util', 'enable Utility', 'enable prefix'], + guarded: true, + + args: [ + { + key: 'cmdOrGrp', + label: 'command/group', + prompt: 'Which command or group would you like to enable?', + type: 'group|command' + } + ] + }); + } + + hasPermission(msg) { + if(!msg.guild) return this.client.isOwner(msg.author); + return msg.member.permissions.has('ADMINISTRATOR') || this.client.isOwner(msg.author); + } + + run(msg, args) { + const group = args.cmdOrGrp.group; + if(args.cmdOrGrp.isEnabledIn(msg.guild, true)) { + return msg.reply( + `The \`${args.cmdOrGrp.name}\` ${args.cmdOrGrp.group ? 'command' : 'group'} is already enabled${ + group && !group.isEnabledIn(msg.guild) ? + `, but the \`${group.name}\` group is disabled, so it still can't be used` : + '' + }.` + ); + } + args.cmdOrGrp.setEnabledIn(msg.guild, true); + return msg.reply( + `Enabled the \`${args.cmdOrGrp.name}\` ${group ? 'command' : 'group'}${ + group && !group.isEnabledIn(msg.guild) ? + `, but the \`${group.name}\` group is disabled, so it still can't be used` : + '' + }.` + ); + } +}; diff --git a/cmds/owner/eval.js b/cmds/owner/eval.js new file mode 100644 index 0000000..0789d41 --- /dev/null +++ b/cmds/owner/eval.js @@ -0,0 +1,116 @@ +const util = require('util'); +const discord = require('discord.js'); +const tags = require('common-tags'); +const { escapeRegex } = require('../../node_modules/@iceprod/discord.js-commando/src/util'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +const nl = '!!NL!!'; +const nlPattern = new RegExp(nl, 'g'); + +module.exports = class EvalCommand extends Command { + constructor(client) { + super(client, { + name: 'eval', + group: 'util', + memberName: 'eval', + description: 'Executes JavaScript code.', + details: 'Only the bot owner(s) may use this command.', + ownerOnly: true, + + args: [ + { + key: 'script', + prompt: 'What code would you like to evaluate?', + type: 'string' + } + ] + }); + + this.lastResult = null; + Object.defineProperty(this, '_sensitivePattern', { value: null, configurable: true }); + } + + run(msg, args) { + // Make a bunch of helpers + /* eslint-disable no-unused-vars */ + const message = msg; + const client = msg.client; + const lastResult = this.lastResult; + const doReply = val => { + if (val instanceof Error) { + msg.reply(`Callback error: \`${val}\``); + } else { + const result = this.makeResultMessages(val, process.hrtime(this.hrStart)); + if (Array.isArray(result)) { + for (const item of result) msg.reply(item); + } else { + msg.reply(result); + } + } + }; + /* eslint-enable no-unused-vars */ + + // Remove any surrounding code blocks before evaluation + if (args.script.startsWith('```') && args.script.endsWith('```')) { + args.script = args.script.replace(/(^.*?\s)|(\n.*$)/g, ''); + } + + // Run the code and measure its execution time + let hrDiff; + try { + const hrStart = process.hrtime(); + this.lastResult = eval(args.script); + hrDiff = process.hrtime(hrStart); + } catch (err) { + return msg.reply(`Error while evaluating: \`${err}\``); + } + + // Prepare for callback time and respond + this.hrStart = process.hrtime(); + const result = this.makeResultMessages(this.lastResult, hrDiff, args.script); + if (Array.isArray(result)) { + return result.map(item => msg.reply(item)); + } else { + return msg.reply(result); + } + } + + makeResultMessages(result, hrDiff, input = null) { + const inspected = util.inspect(result, { depth: 0 }) + .replace(nlPattern, '\n') + .replace(this.sensitivePattern, '--snip--'); + const split = inspected.split('\n'); + const last = inspected.length - 1; + const prependPart = inspected[0] !== '{' && inspected[0] !== '[' && inspected[0] !== "'" ? split[0] : inspected[0]; + const appendPart = inspected[last] !== '}' && inspected[last] !== ']' && inspected[last] !== "'" ? + split[split.length - 1] : + inspected[last]; + const prepend = `\`\`\`javascript\n${prependPart}\n`; + const append = `\n${appendPart}\n\`\`\``; + if (input) { + return discord.splitMessage(tags.stripIndents` + *Executed in ${hrDiff[0] > 0 ? `${hrDiff[0]}s ` : ''}${hrDiff[1] / 1000000}ms.* + \`\`\`javascript + ${inspected} + \`\`\` + `, { maxLength: 2000, prepend, append }); + } else { + return discord.splitMessage(tags.stripIndents` + *Callback executed after ${hrDiff[0] > 0 ? `${hrDiff[0]}s ` : ''}${hrDiff[1] / 1000000}ms.* + \`\`\`javascript + ${inspected} + \`\`\` + `, { maxLength: 2000, prepend, append }); + } + } + + get sensitivePattern() { + if (!this._sensitivePattern) { + const client = this.client; + let pattern = ''; + if (client.token) pattern += escapeRegex(client.token); + Object.defineProperty(this, '_sensitivePattern', { value: new RegExp(pattern, 'gi'), configurable: false }); + } + return this._sensitivePattern; + } +}; diff --git a/cmds/owner/groups.js b/cmds/owner/groups.js new file mode 100644 index 0000000..fe7f573 --- /dev/null +++ b/cmds/owner/groups.js @@ -0,0 +1,30 @@ +const { stripIndents } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class ListGroupsCommand extends Command { + constructor(client) { + super(client, { + name: 'groups', + aliases: ['list-groups', 'show-groups'], + group: 'commands', + memberName: 'groups', + description: 'Lists all command groups.', + details: 'Only administrators may use this command.', + guarded: true + }); + } + + hasPermission(msg) { + if(!msg.guild) return this.client.isOwner(msg.author); + return msg.member.permissions.has('ADMINISTRATOR') || this.client.isOwner(msg.author); + } + + run(msg) { + return msg.reply(stripIndents` + __**Groups**__ + ${this.client.registry.groups.map(grp => + `**${grp.name}:** ${grp.isEnabledIn(msg.guild) ? 'Enabled' : 'Disabled'}` + ).join('\n')} + `); + } +}; diff --git a/cmds/owner/load.js b/cmds/owner/load.js new file mode 100644 index 0000000..56f768a --- /dev/null +++ b/cmds/owner/load.js @@ -0,0 +1,72 @@ +const fs = require('fs'); +const { oneLine } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class LoadCommandCommand extends Command { + constructor(client) { + super(client, { + name: 'load', + aliases: ['load-command'], + group: 'commands', + memberName: 'load', + description: 'Loads a new command.', + details: oneLine` + The argument must be full name of the command in the format of \`group:memberName\`. + Only the bot owner(s) may use this command. + `, + examples: ['load some-command'], + ownerOnly: true, + guarded: true, + + args: [ + { + key: 'command', + prompt: 'Which command would you like to load?', + validate: val => new Promise(resolve => { + if(!val) return resolve(false); + const split = val.split(':'); + if(split.length !== 2) return resolve(false); + if(this.client.registry.findCommands(val).length > 0) { + return resolve('That command is already registered.'); + } + const cmdPath = this.client.registry.resolveCommandPath(split[0], split[1]); + fs.access(cmdPath, fs.constants.R_OK, err => err ? resolve(false) : resolve(true)); + return null; + }), + parse: val => { + const split = val.split(':'); + const cmdPath = this.client.registry.resolveCommandPath(split[0], split[1]); + delete require.cache[cmdPath]; + return require(cmdPath); + } + } + ] + }); + } + + async run(msg, args) { + this.client.registry.registerCommand(args.command); + const command = this.client.registry.commands.last(); + + if(this.client.shard) { + try { + await this.client.shard.broadcastEval(` + const ids = [${this.client.shard.ids.join(',')}]; + if(!this.shard.ids.some(id => ids.includes(id))) { + const cmdPath = this.registry.resolveCommandPath('${command.groupID}', '${command.name}'); + delete require.cache[cmdPath]; + this.registry.registerCommand(require(cmdPath)); + } + `); + } catch(err) { + this.client.emit('warn', `Error when broadcasting command load to other shards`); + this.client.emit('error', err); + await msg.reply(`Loaded \`${command.name}\` command, but failed to load on other shards.`); + return null; + } + } + + await msg.reply(`Loaded \`${command.name}\` command${this.client.shard ? ' on all shards' : ''}.`); + return null; + } +}; diff --git a/cmds/owner/reload.js b/cmds/owner/reload.js new file mode 100644 index 0000000..8efb63b --- /dev/null +++ b/cmds/owner/reload.js @@ -0,0 +1,68 @@ +const { oneLine } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class ReloadCommandCommand extends Command { + constructor(client) { + super(client, { + name: 'reload', + aliases: ['reload-command'], + group: 'commands', + memberName: 'reload', + description: 'Reloads a command or command group.', + details: oneLine` + The argument must be the name/ID (partial or whole) of a command or command group. + Providing a command group will reload all of the commands in that group. + Only the bot owner(s) may use this command. + `, + examples: ['reload some-command'], + ownerOnly: true, + guarded: true, + + args: [ + { + key: 'cmdOrGrp', + label: 'command/group', + prompt: 'Which command or group would you like to reload?', + type: 'group|command' + } + ] + }); + } + + async run(msg, args) { + const { cmdOrGrp } = args; + const isCmd = Boolean(cmdOrGrp.groupID); + cmdOrGrp.reload(); + + if(this.client.shard) { + try { + await this.client.shard.broadcastEval(` + const ids = [${this.client.shard.ids.join(',')}]; + if(!this.shard.ids.some(id => ids.includes(id))) { + this.registry.${isCmd ? 'commands' : 'groups'}.get('${isCmd ? cmdOrGrp.name : cmdOrGrp.id}').reload(); + } + `); + } catch(err) { + this.client.emit('warn', `Error when broadcasting command reload to other shards`); + this.client.emit('error', err); + if(isCmd) { + await msg.reply(`Reloaded \`${cmdOrGrp.name}\` command, but failed to reload on other shards.`); + } else { + await msg.reply( + `Reloaded all of the commands in the \`${cmdOrGrp.name}\` group, but failed to reload on other shards.` + ); + } + return null; + } + } + + if(isCmd) { + await msg.reply(`Reloaded \`${cmdOrGrp.name}\` command${this.client.shard ? ' on all shards' : ''}.`); + } else { + await msg.reply( + `Reloaded all of the commands in the \`${cmdOrGrp.name}\` group${this.client.shard ? ' on all shards' : ''}.` + ); + } + return null; + } +}; diff --git a/cmds/owner/unknown-command.js b/cmds/owner/unknown-command.js new file mode 100644 index 0000000..0cf4e5b --- /dev/null +++ b/cmds/owner/unknown-command.js @@ -0,0 +1,36 @@ +const { trySend } = require('../../resources/functions'); +const { chatAnswer } = require('../../resources/shaChat'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class UnknownCommandCommand extends Command { + constructor(client) { + super(client, { + name: 'unknown-command', + group: 'util', + memberName: 'unknown-command', + description: 'Displays help information for when an unknown command is used.', + examples: ['unknown-command kickeverybodyever'], + unknown: true, + hidden: true + }); + } + + // eslint-disable-next-line + async run(msg) { + if (/^<@\!?\d{17,19}>\s.+/.test(msg.content)) { + const s = msg.cleanContent.slice((msg.guild ? msg.guild.member(msg.client.user).displayName.length : msg.client.user.username.length) + 2).trim(); + return msg.channel.startTyping().then(trySend(msg.client, msg, await chatAnswer(s)).then(r => r)).catch(() => { }).finally(msg.channel.stopTyping()); + } + if (!msg.guild && !msg.content.toLowerCase().startsWith(msg.client.commandPrefix)) return msg.channel.startTyping().then(trySend(msg.client, msg, await chatAnswer(msg.cleanContent)).then(r => r)).catch(() => { }).finally(msg.channel.stopTyping()); + try { + return await msg.channel.send( + `Unknown command \`${msg.content}\`. Use ${msg.anyUsage( + 'help', + msg.guild ? undefined : null, + msg.guild ? undefined : null + )} to view the command list.` + ); + // eslint-disable-next-line + } catch (exception) { } + } +}; diff --git a/cmds/owner/unload.js b/cmds/owner/unload.js new file mode 100644 index 0000000..b4fe9de --- /dev/null +++ b/cmds/owner/unload.js @@ -0,0 +1,52 @@ +const { oneLine } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class UnloadCommandCommand extends Command { + constructor(client) { + super(client, { + name: 'unload', + aliases: ['unload-command'], + group: 'commands', + memberName: 'unload', + description: 'Unloads a command.', + details: oneLine` + The argument must be the name/ID (partial or whole) of a command. + Only the bot owner(s) may use this command. + `, + examples: ['unload some-command'], + ownerOnly: true, + guarded: true, + + args: [ + { + key: 'command', + prompt: 'Which command would you like to unload?', + type: 'command' + } + ] + }); + } + + async run(msg, args) { + args.command.unload(); + + if(this.client.shard) { + try { + await this.client.shard.broadcastEval(` + const ids = [${this.client.shard.ids.join(',')}]; + if(!this.shard.ids.some(id => ids.includes(id))) { + this.registry.commands.get('${args.command.name}').unload(); + } + `); + } catch(err) { + this.client.emit('warn', `Error when broadcasting command unload to other shards`); + this.client.emit('error', err); + await msg.reply(`Unloaded \`${args.command.name}\` command, but failed to unload on other shards.`); + return null; + } + } + + await msg.reply(`Unloaded \`${args.command.name}\` command${this.client.shard ? ' on all shards' : ''}.`); + return null; + } +}; diff --git a/cmds/owner/update.js b/cmds/owner/update.js index 9f5a8a0..04e1a3b 100644 --- a/cmds/owner/update.js +++ b/cmds/owner/update.js @@ -9,10 +9,11 @@ module.exports = class update extends commando.Command { memberName: "update", group: "owner", description: "Update Shasha.", - ownerOnly: true + ownerOnly: true, + guarded: true }); } run(msg) { - + } }; \ No newline at end of file diff --git a/cmds/utility/help.js b/cmds/utility/help.js new file mode 100644 index 0000000..fbaef08 --- /dev/null +++ b/cmds/utility/help.js @@ -0,0 +1,105 @@ +const { stripIndents, oneLine } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); +const { disambiguation } = require('../../node_modules/@iceprod/discord.js-commando/src/util'); + +module.exports = class HelpCommand extends Command { + constructor(client) { + super(client, { + name: 'help', + group: 'util', + memberName: 'help', + aliases: ['commands'], + description: 'Displays a list of available commands, or detailed information for a specified command.', + details: oneLine` + The command may be part of a command name or a whole command name. + If it isn't specified, all available commands will be listed. + `, + examples: ['help', 'help prefix'], + guarded: true, + + args: [ + { + key: 'command', + prompt: 'Which command would you like to view the help for?', + type: 'string', + default: '' + } + ] + }); + } + + async run(msg, args) { // eslint-disable-line complexity + const groups = this.client.registry.groups; + const commands = this.client.registry.findCommands(args.command, false, msg); + const showAll = args.command && args.command.toLowerCase() === 'all'; + if (args.command && !showAll) { + if (commands.length === 1) { + let help = stripIndents` + ${oneLine` + __Command **${commands[0].name}**:__ ${commands[0].description} + ${commands[0].guildOnly ? ' (Usable only in servers)' : ''} + ${commands[0].nsfw ? ' (NSFW)' : ''} + `} + + **Format:** ${msg.anyUsage(`${commands[0].name}${commands[0].format ? ` ${commands[0].format}` : ''}`)} + `; + if (commands[0].aliases.length > 0) help += `\n**Aliases:** ${commands[0].aliases.join(', ')}`; + help += `\n${oneLine` + **Group:** ${commands[0].group.name} + (\`${commands[0].groupID}:${commands[0].memberName}\`) + `}`; + if (commands[0].details) help += `\n**Details:** ${commands[0].details}`; + if (commands[0].examples) help += `\n**Examples:**\n${commands[0].examples.join('\n')}`; + + const messages = []; + try { + messages.push(await msg.direct(help)); + if (msg.channel.type !== 'dm') messages.push(await msg.reply('Sent you a DM with information.')); + } catch (err) { + messages.push(await msg.reply('Unable to send you the help DM. You probably have DMs disabled.')); + } + return messages; + } else if (commands.length > 15) { + return msg.reply('Multiple commands found. Please be more specific.'); + } else if (commands.length > 1) { + return msg.reply(disambiguation(commands, 'commands')); + } else { + return msg.reply( + `Unable to identify command. Use ${msg.usage( + null, msg.channel.type === 'dm' ? null : undefined, msg.channel.type === 'dm' ? null : undefined + )} to view the list of all commands.` + ); + } + } else { + const messages = []; + try { + messages.push(await msg.direct(stripIndents` + ${oneLine` + To run a command in ${msg.guild ? msg.guild.name : 'any server'}, + use ${Command.usage('command', msg.guild ? msg.guild.commandPrefix : null, this.client.user)}. + For example, ${Command.usage('prefix', msg.guild ? msg.guild.commandPrefix : null, this.client.user)}. + `} + To run a command in this DM, simply use ${Command.usage('command', null, null)} with no prefix. + + Use ${this.usage('', null, null)} to view detailed information about a specific command. + Use ${this.usage('all', null, null)} to view a list of *all* commands, not just available ones. + + __**${showAll ? 'All commands' : `Available commands in ${msg.guild || 'this DM'}`}**__ + + ${groups.filter(grp => grp.commands.some(cmd => !cmd.hidden && (showAll || cmd.isUsable(msg)))) + .map(grp => stripIndents` + __${grp.name}__ + ${grp.commands.filter(cmd => !cmd.hidden && (showAll || cmd.isUsable(msg))) + .map(cmd => `**${cmd.name}:** ${cmd.description}${cmd.nsfw ? ' (NSFW)' : ''}`).join('\n') + } + `).join('\n\n') + } + `, { split: true })); + if (msg.channel.type !== 'dm') messages.push(await msg.reply('Sent you a DM with information.')); + } catch (err) { + messages.push(await msg.reply('Unable to send you the help DM. You probably have DMs disabled.')); + } + return messages; + } + } +}; diff --git a/cmds/utility/ping.js b/cmds/utility/ping.js new file mode 100644 index 0000000..60ba767 --- /dev/null +++ b/cmds/utility/ping.js @@ -0,0 +1,28 @@ +const { oneLine } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class PingCommand extends Command { + constructor(client) { + super(client, { + name: 'ping', + group: 'util', + memberName: 'ping', + description: 'Checks the bot\'s ping to the Discord server.', + throttling: { + usages: 5, + duration: 10 + } + }); + } + + async run(msg) { + const pingMsg = await msg.reply('Pinging...'); + return pingMsg.edit(oneLine` + ${msg.channel.type !== 'dm' ? `${msg.author},` : ''} + Pong! The message round-trip took ${ + (pingMsg.editedTimestamp || pingMsg.createdTimestamp) - (msg.editedTimestamp || msg.createdTimestamp) + }ms. + ${this.client.ws.ping ? `The heartbeat ping is ${Math.round(this.client.ws.ping)}ms.` : ''} + `); + } +}; diff --git a/cmds/utility/prefix.js b/cmds/utility/prefix.js new file mode 100644 index 0000000..4f0bc16 --- /dev/null +++ b/cmds/utility/prefix.js @@ -0,0 +1,67 @@ +const { stripIndents, oneLine } = require('common-tags'); +const Command = require('../../node_modules/@iceprod/discord.js-commando/src/commands/base'); + +module.exports = class PrefixCommand extends Command { + constructor(client) { + super(client, { + name: 'prefix', + group: 'util', + memberName: 'prefix', + description: 'Shows or sets the command prefix.', + format: '[prefix/"default"/"none"]', + details: oneLine` + If no prefix is provided, the current prefix will be shown. + If the prefix is "default", the prefix will be reset to the bot's default prefix. + If the prefix is "none", the prefix will be removed entirely, only allowing mentions to run commands. + Only administrators may change the prefix. + `, + examples: ['prefix', 'prefix -', 'prefix omg!', 'prefix default', 'prefix none'], + + args: [ + { + key: 'prefix', + prompt: 'What would you like to set the bot\'s prefix to?', + type: 'string', + max: 15, + default: '' + } + ] + }); + } + + async run(msg, args) { + // Just output the prefix + if(!args.prefix) { + const prefix = msg.guild ? msg.guild.commandPrefix : this.client.commandPrefix; + return msg.reply(stripIndents` + ${prefix ? `The command prefix is \`${prefix}\`.` : 'There is no command prefix.'} + To run commands, use ${msg.anyUsage('command')}. + `); + } + + // Check the user's permission before changing anything + if(msg.guild) { + if(!msg.member.permissions.has('ADMINISTRATOR') && !this.client.isOwner(msg.author)) { + return msg.reply('Only administrators may change the command prefix.'); + } + } else if(!this.client.isOwner(msg.author)) { + return msg.reply('Only the bot owner(s) may change the global command prefix.'); + } + + // Save the prefix + const lowercase = args.prefix.toLowerCase(); + const prefix = lowercase === 'none' ? '' : args.prefix; + let response; + if(lowercase === 'default') { + if(msg.guild) msg.guild.commandPrefix = null; else this.client.commandPrefix = null; + const current = this.client.commandPrefix ? `\`${this.client.commandPrefix}\`` : 'no prefix'; + response = `Reset the command prefix to the default (currently ${current}).`; + } else { + if(msg.guild) msg.guild.commandPrefix = prefix; else this.client.commandPrefix = prefix; + response = prefix ? `Set the command prefix to \`${args.prefix}\`.` : 'Removed the command prefix entirely.'; + } + + await msg.reply(`${response} To run commands, use ${msg.anyUsage('command')}.`); + return null; + } +};