From b32a155fe70f5b51f737444911b7de7ce366a832 Mon Sep 17 00:00:00 2001 From: Matej Voboril Date: Sat, 25 Feb 2017 00:34:48 -0600 Subject: [PATCH 1/7] More message manager consumption consuming message manager settings migrations, message manager initial Generic set/get, adding message manager removed the need for prefix as part of the call * Allowed mentions for command prefix * Allowed custom prefixes per-guild in guilds and per-dm channel * Set up enable and disable with natural syntax. need to get it to flex on switching in/for better * Added settings responses that self-delete continue settings work command disabling and enabling work Still needed: default initialize rows for channels known for each command so that default settings are in work on enable commands, mostly just call structure and processing settings commands, basic commands for now start moving settings to use generic query, easier to debug testing new settings schema add settings schema Enable/disable pings * Still need to set the message for the ping * Still need to set the webhook or automatically fetch a webhook with permission for the channel add initial item tracking commands move optimizations from feature/temp-room break commands into categories removed the need for prefix as part of the call * Allowed mentions for command prefix * Allowed custom prefixes per-guild in guilds and per-dm channel * Set up enable and disable with natural syntax. need to get it to flex on switching in/for better * Added settings responses that self-delete continue settings work command disabling and enabling work Still needed: default initialize rows for channels known for each command so that default settings are in work on enable commands, mostly just call structure and processing settings commands, basic commands for now --- package.json | 1 - src/Command.js | 26 ++- src/CommandHandler.js | 103 +++++++-- src/Tracker.js | 32 ++- src/bot.js | 20 +- src/commands/{ => Core}/Bug.js | 22 +- src/commands/Core/Help.js | 127 +++++++++++ src/commands/{ => Core}/Ping.js | 4 +- src/commands/Help.js | 93 -------- src/commands/{ => Ondemand}/Alerts.js | 13 +- src/commands/{ => Ondemand}/Armor.js | 24 +- .../{ => Ondemand}/ConclaveChallenges.js | 17 +- src/commands/{ => Ondemand}/Damage.js | 4 +- src/commands/{ => Ondemand}/Darvo.js | 8 +- src/commands/{ => Ondemand}/EarthCycle.js | 14 +- src/commands/{ => Ondemand}/Enemies.js | 14 +- src/commands/{ => Ondemand}/FeaturedDeal.js | 17 +- src/commands/{ => Ondemand}/Fissures.js | 14 +- src/commands/{ => Ondemand}/Invasions.js | 14 +- src/commands/{ => Ondemand}/Mod.js | 42 ++-- src/commands/{ => Ondemand}/News.js | 13 +- src/commands/{ => Ondemand}/PopularSale.js | 16 +- src/commands/Ondemand/Pricecheck.js | 46 ++++ src/commands/{ => Ondemand}/PrimeAccess.js | 15 +- src/commands/{ => Ondemand}/Profile.js | 26 +-- src/commands/{ => Ondemand}/Raid.js | 20 +- src/commands/Ondemand/Shields.js | 38 ++++ src/commands/{ => Ondemand}/Simaris.js | 13 +- src/commands/{ => Ondemand}/Sorties.js | 16 +- src/commands/{ => Ondemand}/Syndicates.js | 19 +- src/commands/{ => Ondemand}/Tutorial.js | 25 +-- src/commands/{ => Ondemand}/Updates.js | 13 +- src/commands/{ => Ondemand}/VoidTrader.js | 15 +- src/commands/{ => Ondemand}/WhereIs.js | 8 +- src/commands/{ => Ondemand}/Wiki.js | 8 +- src/commands/{ => Owner}/Avatar.js | 6 +- src/commands/{ => Owner}/LeaveServer.js | 6 +- src/commands/{ => Owner}/Reload.js | 17 +- src/commands/{ => Owner}/Servers.js | 2 +- src/commands/Pricecheck.js | 85 -------- src/commands/Settings/Disable.js | 149 +++++++++++++ src/commands/Settings/DisablePingEvent.js | 89 ++++++++ src/commands/Settings/DisablePingItem.js | 89 ++++++++ src/commands/Settings/Enable.js | 142 ++++++++++++ src/commands/Settings/EnablePingEvent.js | 89 ++++++++ src/commands/Settings/EnablePingItem.js | 89 ++++++++ src/commands/Settings/GetCommandIds.js | 46 ++++ src/commands/Settings/Language.js | 47 ++++ src/commands/{ => Settings}/Platform.js | 12 +- src/commands/Settings/Prefix.js | 85 ++++++++ src/commands/Settings/RespondToSettings.js | 41 ++++ src/commands/Settings/Settings.js | 60 +++++ src/commands/Settings/TrackEvent.js | 89 ++++++++ src/commands/Settings/TrackItem.js | 93 ++++++++ src/commands/Settings/UntrackEvent.js | 93 ++++++++ src/commands/Settings/UntrackItem.js | 92 ++++++++ src/commands/Shields.js | 85 -------- src/embeds/BaseEmbed.js | 2 +- src/embeds/CommandIdEmbed.js | 26 +++ src/embeds/EnableInfoEmbed.js | 37 ++++ src/embeds/EnableUsageEmbed.js | 43 ++++ src/embeds/EnemyEmbed.js | 8 +- src/embeds/PriceCheckEmbed.js | 48 ++++ src/embeds/SettingsEmbed.js | 32 +++ src/embeds/ShieldEmbed.js | 54 +++++ src/resources/strings.json | 19 +- src/resources/trackables.json | 205 ++++++++++++++++++ src/settings/Database.js | 177 ++++++++++----- src/settings/MessageManager.js | 188 ++++++++++++++++ src/settings/StringManager.js | 54 +++++ src/settings/schema.js | 10 +- 71 files changed, 2664 insertions(+), 645 deletions(-) rename src/commands/{ => Core}/Bug.js (79%) create mode 100644 src/commands/Core/Help.js rename src/commands/{ => Core}/Ping.js (96%) delete mode 100644 src/commands/Help.js rename src/commands/{ => Ondemand}/Alerts.js (63%) rename src/commands/{ => Ondemand}/Armor.js (89%) rename src/commands/{ => Ondemand}/ConclaveChallenges.js (61%) rename src/commands/{ => Ondemand}/Damage.js (87%) rename src/commands/{ => Ondemand}/Darvo.js (70%) rename src/commands/{ => Ondemand}/EarthCycle.js (71%) rename src/commands/{ => Ondemand}/Enemies.js (61%) rename src/commands/{ => Ondemand}/FeaturedDeal.js (59%) rename src/commands/{ => Ondemand}/Fissures.js (61%) rename src/commands/{ => Ondemand}/Invasions.js (62%) rename src/commands/{ => Ondemand}/Mod.js (50%) rename src/commands/{ => Ondemand}/News.js (63%) rename src/commands/{ => Ondemand}/PopularSale.js (59%) create mode 100644 src/commands/Ondemand/Pricecheck.js rename src/commands/{ => Ondemand}/PrimeAccess.js (57%) rename src/commands/{ => Ondemand}/Profile.js (64%) rename src/commands/{ => Ondemand}/Raid.js (66%) create mode 100644 src/commands/Ondemand/Shields.js rename src/commands/{ => Ondemand}/Simaris.js (62%) rename src/commands/{ => Ondemand}/Sorties.js (56%) rename src/commands/{ => Ondemand}/Syndicates.js (57%) rename src/commands/{ => Ondemand}/Tutorial.js (64%) rename src/commands/{ => Ondemand}/Updates.js (62%) rename src/commands/{ => Ondemand}/VoidTrader.js (57%) rename src/commands/{ => Ondemand}/WhereIs.js (90%) rename src/commands/{ => Ondemand}/Wiki.js (87%) rename src/commands/{ => Owner}/Avatar.js (80%) rename src/commands/{ => Owner}/LeaveServer.js (83%) rename src/commands/{ => Owner}/Reload.js (54%) rename src/commands/{ => Owner}/Servers.js (94%) delete mode 100644 src/commands/Pricecheck.js create mode 100644 src/commands/Settings/Disable.js create mode 100644 src/commands/Settings/DisablePingEvent.js create mode 100644 src/commands/Settings/DisablePingItem.js create mode 100644 src/commands/Settings/Enable.js create mode 100644 src/commands/Settings/EnablePingEvent.js create mode 100644 src/commands/Settings/EnablePingItem.js create mode 100644 src/commands/Settings/GetCommandIds.js create mode 100644 src/commands/Settings/Language.js rename src/commands/{ => Settings}/Platform.js (71%) create mode 100644 src/commands/Settings/Prefix.js create mode 100644 src/commands/Settings/RespondToSettings.js create mode 100644 src/commands/Settings/Settings.js create mode 100644 src/commands/Settings/TrackEvent.js create mode 100644 src/commands/Settings/TrackItem.js create mode 100644 src/commands/Settings/UntrackEvent.js create mode 100644 src/commands/Settings/UntrackItem.js delete mode 100644 src/commands/Shields.js create mode 100644 src/embeds/CommandIdEmbed.js create mode 100644 src/embeds/EnableInfoEmbed.js create mode 100644 src/embeds/EnableUsageEmbed.js create mode 100644 src/embeds/PriceCheckEmbed.js create mode 100644 src/embeds/SettingsEmbed.js create mode 100644 src/embeds/ShieldEmbed.js create mode 100644 src/resources/trackables.json create mode 100644 src/settings/MessageManager.js create mode 100644 src/settings/StringManager.js diff --git a/package.json b/package.json index cb1119eaa..f04f345ff 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "bluebird": "^3.4.7", "decache": "^4.1.0", "discord.js": "^11.0.0", - "erlpack": "github:hammerandchisel/erlpack#master", "json-fetch-cache": "0.0.5", "mysql2": "^1.1.2", "node-md-config": "^2.0.1", diff --git a/src/Command.js b/src/Command.js index 85272728d..d396c9b56 100644 --- a/src/Command.js +++ b/src/Command.js @@ -31,7 +31,7 @@ class Command { * Command regex for calling the command * @type {RegExp} */ - this.regex = new RegExp(`^${bot.escapedPrefix}${call}s?$`, 'i'); + this.regex = new RegExp(`^${call}s?$`, 'i'); /** * Help command for documenting the function or purpose of a command. * @type {string} @@ -78,6 +78,30 @@ class Command { * @type {boolean} */ this.ownerOnly = false; + + /** + * True if this command is allowed to be disabled. + * @type {Boolean} + */ + this.blacklistable = true; + + /** + * True if this command requires authorization to be executed + * @type {Boolean} + */ + this.requiresAuth = false; + + /** + * True if this command is allowed in direct messages + * @type {Boolean} + */ + this.allowDM = true; + + /** + * Message manager for sending and managing messages + * @type {MessageManager} + */ + this.messageManager = bot.messageManager; } /** diff --git a/src/CommandHandler.js b/src/CommandHandler.js index 2693533e4..463f80b47 100644 --- a/src/CommandHandler.js +++ b/src/CommandHandler.js @@ -29,12 +29,20 @@ class CommandHandler { */ loadCommands() { const commandDir = path.join(__dirname, 'commands'); - const files = fs.readdirSync(commandDir); + let files = fs.readdirSync(commandDir); + + const categories = files.filter(f => f.indexOf('.js') === -1); + files = files.filter(f => f.indexOf('.js') > -1); + + categories.forEach((category) => { + files = files.concat(fs.readdirSync(path.join(commandDir, category)) + .map(f => path.join(category, f))); + }); if (this.commands.length !== 0) { this.logger.debug('Decaching commands'); files.forEach((f) => { - decache(`${commandDir}/${f}`); + decache(path.join(commandDir, f)); }); } @@ -43,7 +51,7 @@ class CommandHandler { this.commands = files.map((f) => { try { // eslint-disable-next-line import/no-dynamic-require, global-require - const Cmd = require(`${commandDir}/${f}`); + const Cmd = require(path.join(commandDir, f)); if (Object.prototype.toString.call(Cmd) === '[object Function]') { const command = new Cmd(this.bot); @@ -64,33 +72,82 @@ class CommandHandler { * @param {Message} message Message whose command should be checked and handled */ handleCommand(message) { - const content = message.cleanContent; - if (!content.startsWith(this.bot.prefix)) { - return; - } - - this.logger.debug(`Handling \`${content}\``); - this.commands.forEach((command) => { - if (command.regex.test(content) && this.checkCanAct(command, message.author)) { - this.logger.debug(`Matched ${command.id}`); - message.react('\u2705').catch(this.logger.error); - command.run(message); - } - }); + let content = message.cleanContent; + const botping = `@${this.bot.client.user.username}`; + this.bot.settings.getChannelPrefix(message.channel) + .then((prefix) => { + if (!content.startsWith(prefix) && !content.startsWith(botping)) { + return; + } + if (content.startsWith(prefix)) { + content = content.replace(prefix, ''); + } + if (content.startsWith(botping)) { + content = content.replace(new RegExp(`${botping}\\s+`, 'i'), ''); + } + const messageWithStrippedContent = message; + messageWithStrippedContent.strippedContent = content; + this.logger.debug(`Handling \`${content}\``); + this.commands.forEach((command) => { + if (command.regex.test(content)) { + this.checkCanAct(command, messageWithStrippedContent) + .then((canAct) => { + if (canAct) { + this.logger.debug(`Matched ${command.id}`); + message.react('\u2705').catch(this.logger.error); + command.run(messageWithStrippedContent); + } + }); + } + }); + }) + .catch(this.logger.error); } /** * Check if the current command being called is able to be performed for the user calling it. * @param {Command} command command to process to see if it can be called - * @param {User} author caller of the message, the author. + * @param {Message} message Discord message object * @returns {boolean} Whether or not the ucrrent command can be called by the author */ - checkCanAct(command, author) { - if (command.ownerOnly && author.id !== this.bot.owner) { - return false; - } - // TODO: Do blacklist checking - return true; + checkCanAct(command, message) { + return new Promise((resolve) => { + if (message.channel.type === 'text') { + if (command.requiresAuth && message.channel.permissionsFor(message.author).hasPermission('MANAGE_ROLES_OR_PERMISSIONS')) { + this.bot.settings + .getChannelPermissionForMember(message.channel, message.author.id, command.id) + .then((userHasPermission) => { + resolve(userHasPermission); + }) + .catch(() => { + this.bot.settings + .getChannelPermissionForUserRoles(message.channel, + message.author, command.id) + .then((userHasPermission) => { + resolve(userHasPermission); + }); + }); + } else { + this.bot.settings + .getChannelPermissionForMember(message.channel, message.author.id, command.id) + .then((userHasPermission) => { + resolve(userHasPermission); + }) + .catch(() => { + this.bot.settings + .getChannelPermissionForUserRoles(message.channel, + message.author, command.id) + .then((userHasPermission) => { + resolve(userHasPermission); + }); + }); + } + } else if (message.channel.type === 'dm' && command.allowDM) { + resolve(true); + } else { + resolve(false); + } + }); } } diff --git a/src/Tracker.js b/src/Tracker.js index fde58faa6..033cc36cf 100644 --- a/src/Tracker.js +++ b/src/Tracker.js @@ -6,6 +6,7 @@ const carbonToken = process.env.DISCORD_CARBON_TOKEN; const botsDiscordPwToken = process.env.DISCORD_BOTS_WEB_TOKEN; const botsDiscordPwUser = process.env.DISCORD_BOTS_WEB_USER; const updateInterval = process.env.TRACKERS_UPDATE_INTERVAL || 2600000; +const discordListToken = process.env.DISCORD_LIST_TOKEN; /** * Describes a tracking service for updating remote sites @@ -28,6 +29,9 @@ class Tracker { if (botsDiscordPwToken && botsDiscordPwUser) { setInterval(() => this.updateDiscordBotsWeb(this.client.guilds.size), updateInterval); } + if (discordListToken) { + setInterval(() => this.updateDiscordList(this.client.guilds.size), updateInterval); + } } /** @@ -50,7 +54,32 @@ class Tracker { .then((parsedBody) => { this.logger.debug(parsedBody); }) - .catch(error => this.logger.error(error)); + .catch(this.logger.error); + } + } + + /** + * Updates discordlist.net if the corresponding token is provided + * @param {number} guildsLen number of guilds that this bot is present on + */ + updateDiscordList(guildsLen) { + if (discordListToken) { + this.logger.debug('Updating DiscordList'); + this.logger.debug(`${this.client.user.username} is on ${guildsLen} servers`); + + const requestBody = { + url: 'https://bots.discordlist.net/api', + body: { + token: discordListToken, + servers: guildsLen, + }, + json: true, + }; + request(requestBody) + .then((parsedBody) => { + this.logger.debug(parsedBody); + }) + .catch(this.logger.error); } } @@ -91,6 +120,7 @@ class Tracker { updateAll(guildsLen) { this.updateCarbonitex(guildsLen); this.updateDiscordBotsWeb(guildsLen); + this.updateDiscordList(guildsLen); } } diff --git a/src/bot.js b/src/bot.js index 8a7c7b209..3a5bc9e11 100644 --- a/src/bot.js +++ b/src/bot.js @@ -6,6 +6,7 @@ const md = require('node-md-config'); const WorldStateCache = require('./WorldStateCache.js'); const Database = require('./settings/Database.js'); const Tracker = require('./Tracker.js'); +const MessageManager = require('./settings/MessageManager.js'); /** * A collection of strings that are used by the parser to produce markdown-formatted text @@ -112,12 +113,6 @@ class Genesis { */ this.owner = owner; - /** - * The status message to use for the bot - * @type {string} - */ - this.statusMessage = `${prefix}help for help (${this.shardId + 1}/${this.shardCount})`; - /** * Persistent storage for settings * @type {Database} @@ -148,8 +143,16 @@ class Genesis { this.worldStates[platform] = new WorldStateCache(platform, worldStateTimeout); }); + /** + * The languages that are useable for the bot + * @type {Array.} + */ + this.languages = ['en-us']; + this.tracker = new Tracker(this.logger, this.client, { shardId, shardCount }); + this.messageManager = new MessageManager(this); + this.commandHandler.loadCommands(); this.setupHandlers(); @@ -178,7 +181,7 @@ class Genesis { * Creates the database schema and logs in the bot to Discord */ start() { - this.settings.createSchema().then(() => { + this.settings.createSchema(this.client).then(() => { this.logger.debug('Schema created'); return this.client.login(this.token); }).then((t) => { @@ -196,7 +199,8 @@ class Genesis { onReady() { this.logger.debug(`${this.client.user.username} ready!`); this.logger.debug(`Bot: ${this.client.user.username}#${this.client.user.discriminator}`); - this.client.user.setGame(this.statusMessage); + this.client.user.setGame(`@${this.client.user.username} help (${this.shardId + 1}/${this.shardCount})`); + this.settings.ensureData(this.client); this.readyToExecute = true; } diff --git a/src/commands/Bug.js b/src/commands/Core/Bug.js similarity index 79% rename from src/commands/Bug.js rename to src/commands/Core/Bug.js index b31b51d1e..0edff9fd7 100644 --- a/src/commands/Bug.js +++ b/src/commands/Core/Bug.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); /** * Send a bug report to owner @@ -12,7 +12,7 @@ class BugReport extends Command { */ constructor(bot) { super(bot, 'core.bug', 'bug', 'Send a bug report to the bot owner'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}${this.call}\\s*(.*)?`, 'i'); + this.regex = new RegExp(`^${this.call}\\s*(.*)?`, 'i'); this.usages = [ { description: 'Send a bug report to bot owner', @@ -37,10 +37,10 @@ class BugReport extends Command { * or perform an action based on parameters. */ run(message) { - const bugReport = message.cleanContent.match(this.regex)[1]; + const bugReport = message.strippedContent.match(this.regex)[1]; if (this.bot.owner) { - if(bugReport) { + if (bugReport) { const params = bugReport.split('|'); const embed = { author: { @@ -68,20 +68,18 @@ class BugReport extends Command { }; } } - - this.bot.client.users.get(this.bot.owner) - .sendEmbed(embed) - .then(() => message.reply('Bug report sent.')) - .catch(this.logger.error); + this.messageManager.sendDirectEmbedToOwner(embed); + this.messageManager.reply(message, 'Bug report sent.', true, true); } else { - message.channel.sendEmbed({ + const embed = { author: { icon_url: message.author.avatarURL, name: `${message.author.username}#${message.author.discriminator}`, }, title: `Bug Report | ${message.author}`, - fields: [{name: '_ _', value:'Need to provide a bug report, see `/help` for syntax.'}], - }).catch(this.logger.error) + fields: [{ name: '_ _', value: 'Need to provide a bug report, see `/help` for syntax.' }], + }; + this.messageManager.embed(message, embed, true, false); } } } diff --git a/src/commands/Core/Help.js b/src/commands/Core/Help.js new file mode 100644 index 000000000..caab1442c --- /dev/null +++ b/src/commands/Core/Help.js @@ -0,0 +1,127 @@ +'use strict'; + +const Command = require('../../Command.js'); + + +/** + * Describes the Help command + */ +class Help extends Command { + /** + * Constructs a callable command + * @param {Genesis} bot The bot object + */ + constructor(bot) { + super(bot, 'core.help', 'help', 'Display this message'); + + this.helpEmbed = null; + + /** + * Help reply messsage for alerting a user to check their direct messages. + * @type {string} + * @private + */ + this.helpReplyMsg = process.env.HELP_REPLY || ' check your direct messages for help.'; + } + + /** + * Send help message + * @param {Message} message Message to reply to + */ + run(message) { + if (message.channel.type !== 'dm') { + this.messageManager.reply(message, this.helpReplyMsg, true, false); + } + this.sendCoreEmbed(message); + this.sendSettingsEmbed(message); + this.sendWarframeEmbed(message); + this.sendHelpEmbed(message); + if (message.author.id === this.bot.owner) { + this.sendOwnerOnlyEmbed(message); + } + } + + sendHelpEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel).then((prefix) => { + const commands = this.commandHandler.commands.filter(c => + !c.ownerOnly && + !/core/ig.test(c.id) && + !(/warframe/ig.test(c.id)) && + !/settings/ig.test(c.id)) + .map(c => c.usages.map(u => ({ + name: `${prefix}${c.call} ${u.parameters.map(p => `<${p}>`).join(u.separator ? u.separator : ' ')}`, + value: u.description, + inline: false, + } + ))); + this.sendEmbedForCommands(message, commands, 'Help!', 0x00ff00); + }).catch(this.logger.error); + } + + sendOwnerOnlyEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel).then((prefix) => { + const ownerCommands = this.commandHandler.commands.filter(c => c.ownerOnly) + .map(c => c.usages.map(u => ({ + name: `${prefix}${c.call} ${u.parameters.map(p => `<${p}>`).join(' ')}`, + value: u.description, + inline: false, + }))); + this.sendEmbedForCommands(message, ownerCommands, 'Owner Only', 0xff0000); + }).catch(this.logger.error); + } + + sendCoreEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel).then((prefix) => { + const commands = this.commandHandler.commands.filter(c => !c.ownerOnly && /core/ig.test(c.id)) + .map(c => c.usages.map(u => ({ + name: `${prefix}${c.call} ${u.parameters.map(p => `<${p}>`).join(' ')}`, + value: u.description, + inline: false, + }))); + this.sendEmbedForCommands(message, commands, 'Core Commands', 0x000000); + }).catch(this.logger.error); + } + + sendWarframeEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel).then((prefix) => { + const commands = this.commandHandler.commands.filter(c => !c.ownerOnly && /warframe/ig.test(c.id)) + .map(c => c.usages.map(u => ({ + name: `${prefix}${c.call} ${u.parameters.map(p => `<${p}>`).join(' ')}`, + value: u.description, + inline: false, + }))); + this.sendEmbedForCommands(message, commands, 'Warframe Commands', 0x4068BD); + }).catch(this.logger.error); + } + + sendSettingsEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel).then((prefix) => { + const ownerCommands = this.commandHandler.commands.filter(c => !c.ownerOnly && /settings/ig.test(c.id)) + .map(c => c.usages.map(u => ({ + name: `${prefix}${c.call} ${u.parameters.map(p => `<${p}>`).join(' ')}`, + value: u.description, + inline: false, + }))); + this.sendEmbedForCommands(message, ownerCommands, 'Settings Commands', 0xe5c100); + }).catch(this.logger.error); + } + + sendEmbedForCommands(message, commands, title, color) { + const embed = { + title, + fields: [].concat(...commands), + color, + }; + if (title === 'Core Commands') { + embed.type = 'rich'; + embed.thumbnail = { + url: 'https://github.com/aliasfalse/genesis/raw/master/src/resources/cephalontransparent.png', + }; + } + if (commands.length > 0) { + this.messageManager.sendDirectEmbedToAuthor(message, embed, false); + } + } +} + +module.exports = Help; diff --git a/src/commands/Ping.js b/src/commands/Core/Ping.js similarity index 96% rename from src/commands/Ping.js rename to src/commands/Core/Ping.js index 32b07ba14..a7ce52970 100644 --- a/src/commands/Ping.js +++ b/src/commands/Core/Ping.js @@ -1,7 +1,7 @@ 'use strict'; const ping = require('ping').promise; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); /** * @param {number} millis The number of milliseconds in the time delta @@ -83,7 +83,7 @@ class Ping extends Command { ], footer: { thumbnail_url: '_ _', - text: `Uptime: ${timeDeltaToString(this.bot.client.uptime)} | Hosted by JakeyPrime at imjake.me`, + text: `Uptime: ${timeDeltaToString(this.bot.client.uptime)}`, }, }, }); diff --git a/src/commands/Help.js b/src/commands/Help.js deleted file mode 100644 index 24da6ce76..000000000 --- a/src/commands/Help.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -const Command = require('../Command.js'); - -/** - * Describes the Help command - */ -class Help extends Command { - /** - * Constructs a callable command - * @param {Genesis} bot The bot object - */ - constructor(bot) { - super(bot, 'core.help', 'help', 'Display this message'); - - this.helpEmbed = null; - - /** - * Help reply messsage for alerting a user to check their direct messages. - * @type {string} - * @private - */ - this.helpReplyMsg = process.env.HELP_REPLY || ' check your direct messages for help.'; - } - - /** - * Send help message - * @param {Message} message Message to reply to - */ - run(message) { - if (!this.helpEmbed) { - this.makeHelpEmbed(); - } - if (message.channel.type !== 'dm') { - message.reply(this.helpReplyMsg) - .then((reply) => { - if (reply.deletable) { - reply.delete(10000); - } - }).catch(this.logger.error); - } - - const promises = [ - message.author.sendEmbed(this.helpEmbed).then(() => { - if (message.deletable) { - message.delete(2000); - } - }), - ]; - - if (message.author.id === this.bot.owner) { - promises.push(message.author.sendEmbed(this.makeOwnerOnlyEmbed())); - } - Promise.all(promises).catch(this.logger.error); - } - - makeHelpEmbed() { - this.helpEmbed = { - type: 'rich', - thumbnail: { - url: 'https://github.com/aliasfalse/genesis/raw/master/src/resources/cephalontransparent.png', - }, - }; - - const commands = this.commandHandler.commands.filter(c => !c.ownerOnly) - .map(c => c.usages.map(u => ({ - name: `${this.bot.prefix}${c.call} ${u.parameters.map(p => `<${p}>`).join(u.separator ? u.separator : ' ')}`, - value: u.description, - inline: false, - } - ))); - - this.helpEmbed.fields = [].concat(...commands); - } - - makeOwnerOnlyEmbed() { - const ownerCommands = this.commandHandler.commands.filter(c => c.ownerOnly) - .map(c => c.usages.map(u => ({ - name: `${this.bot.prefix}${c.call} ${u.parameters.map(p => `<${p}>`).join(' ')}`, - value: u.description, - inline: false, - }))); - const embed = { - title: 'Owner only', - fields: [].concat(...ownerCommands), - color: 0xff0000, - }; - - return embed; - } -} - -module.exports = Help; diff --git a/src/commands/Alerts.js b/src/commands/Ondemand/Alerts.js similarity index 63% rename from src/commands/Alerts.js rename to src/commands/Ondemand/Alerts.js index 0d99aa3a1..c6ce89610 100644 --- a/src/commands/Alerts.js +++ b/src/commands/Ondemand/Alerts.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const AlertEmbed = require('../embeds/AlertEmbed.js'); +const Command = require('../../Command.js'); +const AlertEmbed = require('../../embeds/AlertEmbed.js'); /** * Displays the currently active alerts @@ -12,7 +12,7 @@ class Alerts extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.alerts', 'alerts', 'Display the currently active alerts'); + super(bot, 'warframe.worldstate.alerts', 'alerts', 'Display the currently active alerts'); } /** @@ -25,12 +25,7 @@ class Alerts extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const alerts = ws.alerts.filter(a => !a.getExpired()); - return message.channel.sendEmbed(new AlertEmbed(this.bot, alerts)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, new AlertEmbed(this.bot, alerts), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Armor.js b/src/commands/Ondemand/Armor.js similarity index 89% rename from src/commands/Armor.js rename to src/commands/Ondemand/Armor.js index 36567addc..4676298fd 100644 --- a/src/commands/Armor.js +++ b/src/commands/Ondemand/Armor.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); /** * Calculates the damage reduction for a given armor value @@ -42,10 +42,8 @@ class Armor extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.armor', 'armor', 'armor'); - - this.regex = new RegExp(`^${this.bot.escapedPrefix}armor(?:\\s+([\\d+\\.?\\d*\\s]+))?`, 'i'); - + super(bot, 'warframe.calculations.armor', 'armor', 'armor'); + this.regex = new RegExp(`^${this.call}(?:\\s+([\\d+\\.?\\d*\\s]+))?`, 'i'); this.usages = [ { description: 'Display instructions for calculating armor', parameters: [] }, { @@ -105,13 +103,7 @@ class Armor extends Command { text: 'Data evaluated by Warframe Community Developers', }, }; - message.channel.sendEmbed(embed) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); - }).catch(this.logger.error); + this.messageManager.embed(message, embed, true, false); } else { this.logger.debug('Entered 0-param armor'); this.sendUsage(message); @@ -147,13 +139,7 @@ class Armor extends Command { }, }; - message.reply('', { embed }) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); - }).catch(this.logger.error); + this.messageManager.embed(message, embed, true, false); } /** diff --git a/src/commands/ConclaveChallenges.js b/src/commands/Ondemand/ConclaveChallenges.js similarity index 61% rename from src/commands/ConclaveChallenges.js rename to src/commands/Ondemand/ConclaveChallenges.js index cb2d922f2..488e75afc 100644 --- a/src/commands/ConclaveChallenges.js +++ b/src/commands/Ondemand/ConclaveChallenges.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const ConclaveChallengeEmbed = require('../embeds/ConclaveChallengeEmbed.js'); +const Command = require('../../Command.js'); +const ConclaveChallengeEmbed = require('../../embeds/ConclaveChallengeEmbed.js'); /** * Displays the currently active Invasions @@ -12,8 +12,8 @@ class ConclaveChallenges extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.conclaveChallenges', 'conclave', 'Gets the current conclave challenges for a category of challenge, or all.'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}conclave(?:\\s+([\\w+\\s]+))?`, 'i'); + super(bot, 'warframe.worldstate.conclaveChallenges', 'conclave', 'Gets the current conclave challenges for a category of challenge, or all.'); + this.regex = new RegExp('^conclave(?:\\s+([\\w+\\s]+))?', 'i'); this.usages = [ { @@ -29,18 +29,13 @@ class ConclaveChallenges extends Command { * or perform an action based on parameters. */ run(message) { - const category = message.content.match(this.regex)[1]; + const category = message.strippedContent.match(this.regex)[1]; this.bot.settings.getChannelPlatform(message.channel) .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const conclaveChallenges = ws.conclaveChallenges; const embed = new ConclaveChallengeEmbed(this.bot, conclaveChallenges, category); - return message.channel.sendEmbed(embed); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, embed, true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Damage.js b/src/commands/Ondemand/Damage.js similarity index 87% rename from src/commands/Damage.js rename to src/commands/Ondemand/Damage.js index 0ab59b54e..854e743a4 100644 --- a/src/commands/Damage.js +++ b/src/commands/Ondemand/Damage.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); /** * Displays the Damage 2.0 charts @@ -11,7 +11,7 @@ class Damage extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.damage', 'damage', 'Display Damage 2.0 chart'); + super(bot, 'warframe.misc.damage', 'damage', 'Display Damage 2.0 chart'); this.damageChart = 'http://i.imgur.com/EOzr440.png'; } diff --git a/src/commands/Darvo.js b/src/commands/Ondemand/Darvo.js similarity index 70% rename from src/commands/Darvo.js rename to src/commands/Ondemand/Darvo.js index d8db7a4ea..89ebf1c1d 100644 --- a/src/commands/Darvo.js +++ b/src/commands/Ondemand/Darvo.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const DarvoEmbed = require('../embeds/DarvoEmbed.js'); +const Command = require('../../Command.js'); +const DarvoEmbed = require('../../embeds/DarvoEmbed.js'); /** * Displays today's Darvo deal @@ -12,7 +12,7 @@ class Darvo extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.darvo', 'darvo', 'Displays today\'s Darvo deal'); + super(bot, 'warframe.worldstate.darvo', 'darvo', 'Displays today\'s Darvo deal'); } /** @@ -25,7 +25,7 @@ class Darvo extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const deal = ws.dailyDeals[0]; - return message.channel.sendEmbed(new DarvoEmbed(this.bot, deal)); + this.messageManager.embed(message, new DarvoEmbed(this.bot, deal), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/EarthCycle.js b/src/commands/Ondemand/EarthCycle.js similarity index 71% rename from src/commands/EarthCycle.js rename to src/commands/Ondemand/EarthCycle.js index f653e62c7..5f8c0c58a 100644 --- a/src/commands/EarthCycle.js +++ b/src/commands/Ondemand/EarthCycle.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const EarthCycleEmbed = require('../embeds/EarthCycleEmbed.js'); +const Command = require('../../Command.js'); +const EarthCycleEmbed = require('../../embeds/EarthCycleEmbed.js'); function getCurrentEarthCycle() { const cycleSeconds = Math.floor(Date.now() / 1000) % 28800; // One cycle = 8 hours = 28800 seconds @@ -35,7 +35,7 @@ class EarthCycle extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.cycle', 'cycle', 'Current and remaining time in cycle of Earth rotation.'); + super(bot, 'warframe.misc.cycle', 'cycle', 'Current and remaining time in cycle of Earth rotation.'); } /** @@ -45,13 +45,7 @@ class EarthCycle extends Command { */ run(message) { const state = getCurrentEarthCycle(); - message.channel.sendEmbed(new EarthCycleEmbed(this.bot, state)) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); - }).catch(this.logger.error); + this.messageManager.embed(message, new EarthCycleEmbed(this.bot, state), true, false); } } diff --git a/src/commands/Enemies.js b/src/commands/Ondemand/Enemies.js similarity index 61% rename from src/commands/Enemies.js rename to src/commands/Ondemand/Enemies.js index 7fb0088ee..326e85a63 100644 --- a/src/commands/Enemies.js +++ b/src/commands/Ondemand/Enemies.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const EnemyEmbed = require('../embeds/EnemyEmbed.js'); +const Command = require('../../Command.js'); +const EnemyEmbed = require('../../embeds/EnemyEmbed.js'); /** * Displays the currently persistent enemies @@ -12,7 +12,7 @@ class Enemies extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.acolytes', 'acolyte', 'Display any currently active acolyte-style enemies.'); + super(bot, 'warframe.worldstate.acolytes', 'acolyte', 'Display any currently active acolyte-style enemies.'); } /** @@ -25,12 +25,8 @@ class Enemies extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const persistentEnemies = ws.persistentEnemies; - return message.channel.sendEmbed(new EnemyEmbed(this.bot, persistentEnemies)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, + new EnemyEmbed(this.bot, persistentEnemies), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/FeaturedDeal.js b/src/commands/Ondemand/FeaturedDeal.js similarity index 59% rename from src/commands/FeaturedDeal.js rename to src/commands/Ondemand/FeaturedDeal.js index 5f4acc97d..9d8d70120 100644 --- a/src/commands/FeaturedDeal.js +++ b/src/commands/Ondemand/FeaturedDeal.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const SalesEmbed = require('../embeds/SalesEmbed.js'); +const Command = require('../../Command.js'); +const SalesEmbed = require('../../embeds/SalesEmbed.js'); /** * Displays current featured deals @@ -12,8 +12,8 @@ class FeaturedDeal extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.featureddeal', 'featureddeal', 'Displays current featured deals'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}featured\\s?deals?$`, 'i'); + super(bot, 'warframe.worldstate.featureddeal', 'featureddeal', 'Displays current featured deals'); + this.regex = new RegExp('^featured\\s?deals?$', 'i'); } /** @@ -26,13 +26,8 @@ class FeaturedDeal extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const sales = ws.flashSales.filter(popularItem => popularItem.isFeatured); - return message.channel.sendEmbed(new SalesEmbed(this.bot, sales)); - }) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return new Promise(); + this.messageManager.embed(message, + new SalesEmbed(this.bot, sales), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Fissures.js b/src/commands/Ondemand/Fissures.js similarity index 61% rename from src/commands/Fissures.js rename to src/commands/Ondemand/Fissures.js index ee77f4829..25ef1be01 100644 --- a/src/commands/Fissures.js +++ b/src/commands/Ondemand/Fissures.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const FissureEmbed = require('../embeds/FissureEmbed.js'); +const Command = require('../../Command.js'); +const FissureEmbed = require('../../embeds/FissureEmbed.js'); /** * Displays the currently active Invasions @@ -12,7 +12,7 @@ class Fissures extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.fissures', 'fissures', 'Get the current list of Void Fissure Missions'); + super(bot, 'warframe.worldstate.fissures', 'fissures', 'Get the current list of Void Fissure Missions'); } /** @@ -25,12 +25,8 @@ class Fissures extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const fissures = ws.fissures; - return message.channel.sendEmbed(new FissureEmbed(this.bot, fissures)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, + new FissureEmbed(this.bot, fissures), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Invasions.js b/src/commands/Ondemand/Invasions.js similarity index 62% rename from src/commands/Invasions.js rename to src/commands/Ondemand/Invasions.js index 25eb65053..b4787fc38 100644 --- a/src/commands/Invasions.js +++ b/src/commands/Ondemand/Invasions.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const InvasionEmbed = require('../embeds/InvasionEmbed.js'); +const Command = require('../../Command.js'); +const InvasionEmbed = require('../../embeds/InvasionEmbed.js'); /** * Displays the currently active Invasions @@ -12,7 +12,7 @@ class Invasions extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.invasions', 'invasion', 'Display the currently active Invasions'); + super(bot, 'warframe.worldstate.invasions', 'invasion', 'Display the currently active Invasions'); } /** @@ -25,12 +25,8 @@ class Invasions extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const invasions = ws.invasions.filter(i => !i.completed); - return message.channel.sendEmbed(new InvasionEmbed(this.bot, invasions)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, + new InvasionEmbed(this.bot, invasions), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Mod.js b/src/commands/Ondemand/Mod.js similarity index 50% rename from src/commands/Mod.js rename to src/commands/Ondemand/Mod.js index 00ddab999..0a91a639a 100644 --- a/src/commands/Mod.js +++ b/src/commands/Ondemand/Mod.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); const Wikia = require('node-wikia'); const warframe = new Wikia('warframe'); @@ -14,8 +14,9 @@ class Mod extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.mod', 'mod', 'Search the Warframe Wiki for a mod\'s image'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}mod(.+)`, 'i'); + super(bot, 'warframe.misc.mod', 'mod', 'Search the Warframe Wiki for a mod\'s image'); + this.regex = new RegExp('^mod(.+)', 'i'); + this.noResultStr = `${this.md.codeMulti}No result for search, Operator. Attempt another search query.${this.md.blockEnd}`; } /** @@ -24,9 +25,9 @@ class Mod extends Command { * or perform an action based on parameters. */ run(message) { - const query = this.regex.exec(message.cleanContent.match(this.regex)[0])[1]; + const query = this.regex.exec(message.strippedContent.match(this.regex)[0])[1]; if (!query) { - message.reply(`${this.md.codeMulti}Please specify a search term${this.md.blockEnd}`); + this.messageManager.reply(message, this.noResultStr, true, false); } else { warframe.getSearchList({ query, @@ -49,35 +50,26 @@ class Mod extends Command { list.items.forEach((item) => { if (item.id === id) { sent = true; - message.channel.sendFile(thumbUrl, 'Mod.png', message.author.toString()).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); - }).catch(this.logger.error); + const embed = { + title: query, + color: 0xC0C0C0, + description: `Mod result for ${query}`, + image: { + url: thumbUrl, + }, + }; + this.messageManager.embed(message, embed, true, false); } }); if (!sent) { - message.reply(`${this.md.codeMulti}No result for search, Operator. Attempt another search query.${this.md.blockEnd}`) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); - }).catch(this.logger.error); + this.messageManager.reply(message, this.noResultStr, true, false); } }); }); }) .catch((error) => { this.logger.error(error); - message.reply(`${this.md.codeMulti}No result for search, Operator. Attempt another search query.${this.md.blockEnd}`) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); - }).catch(this.logger.error); + this.messageManager.reply(message, this.noResultStr, true, false); }); } } diff --git a/src/commands/News.js b/src/commands/Ondemand/News.js similarity index 63% rename from src/commands/News.js rename to src/commands/Ondemand/News.js index b1d3a1838..83fa0a926 100644 --- a/src/commands/News.js +++ b/src/commands/Ondemand/News.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const NewsEmbed = require('../embeds/NewsEmbed.js'); +const Command = require('../../Command.js'); +const NewsEmbed = require('../../embeds/NewsEmbed.js'); /** * Displays the currently active warframe news @@ -12,7 +12,7 @@ class News extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.news', 'news', 'Display the currently active news'); + super(bot, 'warframe.worldstate.news', 'news', 'Display the currently active news'); } /** @@ -25,12 +25,7 @@ class News extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const news = ws.news; - return message.channel.sendEmbed(new NewsEmbed(this.bot, news)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, new NewsEmbed(this.bot, news), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/PopularSale.js b/src/commands/Ondemand/PopularSale.js similarity index 59% rename from src/commands/PopularSale.js rename to src/commands/Ondemand/PopularSale.js index c6505397c..2196127ab 100644 --- a/src/commands/PopularSale.js +++ b/src/commands/Ondemand/PopularSale.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const SalesEmbed = require('../embeds/SalesEmbed.js'); +const Command = require('../../Command.js'); +const SalesEmbed = require('../../embeds/SalesEmbed.js'); /** * Displays current popular sales @@ -12,8 +12,8 @@ class PopularSale extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.populardeals', 'populardeals', 'Displays current featured deals'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}popular\\sdeals?$`, 'i'); + super(bot, 'warframe.worldstate.populardeals', 'populardeals', 'Displays current featured deals'); + this.regex = new RegExp('^popular\\sdeals?$', 'i'); } /** @@ -26,13 +26,7 @@ class PopularSale extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const sales = ws.flashSales.filter(popularItem => popularItem.isPopular); - return message.channel.sendEmbed(new SalesEmbed(this.bot, sales)); - }) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return new Promise(); + this.messageManager.embed(message, new SalesEmbed(this.bot, sales), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Ondemand/Pricecheck.js b/src/commands/Ondemand/Pricecheck.js new file mode 100644 index 000000000..0b5914ebb --- /dev/null +++ b/src/commands/Ondemand/Pricecheck.js @@ -0,0 +1,46 @@ +'use strict'; + +const Nexus = require('warframe-nexus-query'); +const Command = require('../../Command.js'); +const PriceCheckEmbed = require('../../embeds/PriceCheckEmbed.js'); + +/** + * Looks up items from Nexus-stats.com + */ +class PriceCheck extends Command { + /** + * Constructs a callable command + * @param {Genesis} bot The bot object + */ + constructor(bot) { + super(bot, 'warframe.misc.pricecheck', 'pricecheck', 'pricecheck'); + this.regex = new RegExp('^p(?:rice)?\\s?c(?:heck)?(?:\\s+([\\w+\\s]+))?', 'i'); + + this.usages = [ + { + description: 'Display an items worth from nexus-stats.com', + parameters: ['item'], + }, + ]; + + this.nexusQuerier = new Nexus(); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const item = message.strippedContent.match(this.regex)[1]; + + this.nexusQuerier.priceCheckQueryAttachment(item) + .then((result) => { + this.messageManager.embed(message, + new PriceCheckEmbed(this.bot, result, item), true, false); + }) + .catch(this.logger.error); + } +} + +module.exports = PriceCheck; diff --git a/src/commands/PrimeAccess.js b/src/commands/Ondemand/PrimeAccess.js similarity index 57% rename from src/commands/PrimeAccess.js rename to src/commands/Ondemand/PrimeAccess.js index dbb12c742..7fe9d10ce 100644 --- a/src/commands/PrimeAccess.js +++ b/src/commands/Ondemand/PrimeAccess.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const PrimeAccessEmbed = require('../embeds/NewsEmbed.js'); +const Command = require('../../Command.js'); +const PrimeAccessEmbed = require('../../embeds/NewsEmbed.js'); /** * Displays the currently active warframe prime access news @@ -12,8 +12,8 @@ class PrimeAccess extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.primeaccess', 'primeaccess', 'Display the currently active prime access news'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}prime\\s?access$`, 'i'); + super(bot, 'warframe.worldstate.primeaccess', 'primeaccess', 'Display the currently active prime access news'); + this.regex = new RegExp('^prime\\s?access$', 'i'); } /** @@ -26,12 +26,7 @@ class PrimeAccess extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const news = ws.news.filter(n => n.isPrimeAccess()); - return message.channel.sendEmbed(new PrimeAccessEmbed(this.bot, news, 'primeaccess')); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, new PrimeAccessEmbed(this.bot, news, 'primeaccess'), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Profile.js b/src/commands/Ondemand/Profile.js similarity index 64% rename from src/commands/Profile.js rename to src/commands/Ondemand/Profile.js index b9e193a7b..b16371073 100644 --- a/src/commands/Profile.js +++ b/src/commands/Ondemand/Profile.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const profiles = require('../resources/profiles.json'); +const Command = require('../../Command.js'); +const profiles = require('../../resources/profiles.json'); /** * Displays the response time for the bot and checks Warframe's servers to see if they are up */ @@ -11,8 +11,8 @@ class FrameProfile extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.warframe.profile', 'frame profile', 'Get a Warframe\'s profile video'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}frame(?:\\s?profile)?(.+)?`, 'i'); + super(bot, 'warframe.misc.profile', 'frame profile', 'Get a Warframe\'s profile video'); + this.regex = new RegExp('^frame(?:\\s?profile)?(.+)?', 'i'); this.usages = [ { description: 'Get a Warframe\'s profile video', @@ -27,33 +27,23 @@ class FrameProfile extends Command { * or perform an action based on parameters. */ run(message) { - let frame = message.content.match(this.regex)[1]; - let promise; + let frame = message.strippedContent.match(this.regex)[1]; if (frame) { frame = frame.trim().toLowerCase(); - profiles.forEach((profile) => { if (new RegExp(profile.regex, 'ig').test(frame)) { - promise = message.reply(`Warfame Profile | ${profile.name} : ${profile.url}`); + this.messageManager.reply(message, `Warfame Profile | ${profile.name} : ${profile.url}`, true, false); } }); } else { - promise = message.channel.sendEmbed({ + this.messageManager.embed(message, { title: 'Available Profiles', fields: [{ name: '_ _', value: profiles.map(profile => profile.name).join('\n') }], footer: { icon_url: 'https://avatars1.githubusercontent.com/u/24436369', text: 'Data evaluated by Warframe Community Developers', }, - }); - } - if (promise) { - promise.then(() => { - if (message.deletable) { - message.delete(10000); - } - }) - .catch(this.logger.error); + }, true, false); } } } diff --git a/src/commands/Raid.js b/src/commands/Ondemand/Raid.js similarity index 66% rename from src/commands/Raid.js rename to src/commands/Ondemand/Raid.js index 6fda8a77c..0de57a574 100644 --- a/src/commands/Raid.js +++ b/src/commands/Ondemand/Raid.js @@ -1,8 +1,8 @@ 'use strict'; const Cache = require('json-fetch-cache'); -const RaidEmbed = require('../embeds/RaidEmbed.js'); -const Command = require('../Command.js'); +const RaidEmbed = require('../../embeds/RaidEmbed.js'); +const Command = require('../../Command.js'); /** * Returns search results from the Warframe wiki @@ -13,8 +13,8 @@ class Raid extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.raid', 'raid', 'Get the raid record for a desired user, or for the calling user'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}(?:${this.call}s?|trials?)\\s*(.+)?`, 'i'); + super(bot, 'warframe.stats.raid', 'raid', 'Get the raid record for a desired user, or for the calling user'); + this.regex = new RegExp(`^(?:${this.call}s?|trials?)\\s*(.+)?`, 'i'); this.usages = [ { description: 'Search for a users\'s raid stats', @@ -29,7 +29,7 @@ class Raid extends Command { * or perform an action based on parameters. */ run(message) { - let query = message.cleanContent.match(this.regex)[1]; + let query = message.strippedContent.match(this.regex)[1]; if (!query || typeof query === 'undefined') { query = message.member ? message.member.displayName : message.author.username; query = query.replace('*', ''); @@ -40,18 +40,10 @@ class Raid extends Command { .then((platform) => { const url = encodeURI(`https://api.trials.wf/api/player/${platform.toLowerCase()}/${query}/completed`); const raidCache = new Cache(url, 999999); - raidCache.getDataJson().then((data) => { - const embed = new RaidEmbed(this.bot, data, query); - return message.channel.sendEmbed(embed); + this.messageManager.embed(message, new RaidEmbed(this.bot, data, query), true, false); }); }) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); - }) .catch(this.logger.error); } } diff --git a/src/commands/Ondemand/Shields.js b/src/commands/Ondemand/Shields.js new file mode 100644 index 000000000..df587ae67 --- /dev/null +++ b/src/commands/Ondemand/Shields.js @@ -0,0 +1,38 @@ +'use strict'; + +const Command = require('../../Command.js'); +const ShieldEmbed = require('../../embeds/ShieldEmbed.js'); + +/** + * Performs shield calculations + */ +class Shields extends Command { + /** + * Constructs a callable command + * @param {Genesis} bot The bot object + */ + constructor(bot) { + super(bot, 'warframe.calculations.shields', 'shields', 'shields'); + this.regex = new RegExp('^shield(?: +([\\d+\\.?\\d* ]+))?', 'i'); + + this.usages = [ + { + description: 'Display an enemy\'s current shields.', + parameters: ['base shields', 'base level', 'current level'], + }, + ]; + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const pattern3Params = /(\d+\.?\d*)(?:\s+(\d+\.?\d*)\s+(\d+\.?\d*))?$/; + const params = message.strippedContent.match(pattern3Params); + this.messageManager.embed(new ShieldEmbed(this.bot, params)); + } +} + +module.exports = Shields; diff --git a/src/commands/Simaris.js b/src/commands/Ondemand/Simaris.js similarity index 62% rename from src/commands/Simaris.js rename to src/commands/Ondemand/Simaris.js index 3ec0858ba..851bbbcda 100644 --- a/src/commands/Simaris.js +++ b/src/commands/Ondemand/Simaris.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const SimarisEmbed = require('../embeds/SimarisEmbed.js'); +const Command = require('../../Command.js'); +const SimarisEmbed = require('../../embeds/SimarisEmbed.js'); /** * Displays the current simaris target @@ -12,7 +12,7 @@ class Simaris extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.simaris', 'simaris', 'Display current Sanctuary status.'); + super(bot, 'warframe.worldstate.simaris', 'simaris', 'Display current Sanctuary status.'); } /** @@ -25,12 +25,7 @@ class Simaris extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const simaris = ws.simaris; - return message.channel.sendEmbed(new SimarisEmbed(this.bot, simaris)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, new SimarisEmbed(this.bot, simaris), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Sorties.js b/src/commands/Ondemand/Sorties.js similarity index 56% rename from src/commands/Sorties.js rename to src/commands/Ondemand/Sorties.js index 353ca52b8..d42ade91f 100644 --- a/src/commands/Sorties.js +++ b/src/commands/Ondemand/Sorties.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const SortieEmbed = require('../embeds/SortieEmbed.js'); +const Command = require('../../Command.js'); +const SortieEmbed = require('../../embeds/SortieEmbed.js'); /** * Displays the currently active Invasions @@ -12,8 +12,7 @@ class Sorties extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.sorties', 'sortie', 'Display the currently active sorties'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}${this.call}s?$`, 'i'); + super(bot, 'warframe.worldstate.sorties', 'sortie', 'Display the currently active sorties'); } /** @@ -27,14 +26,9 @@ class Sorties extends Command { .then((ws) => { const sortie = ws.sortie; if (sortie.isExpired()) { - return message.channel.sendMessage('There is currently no sortie'); + this.messageManager.sendMessage(message, 'There is currently no sortie', true, true); } - return message.channel.sendEmbed(new SortieEmbed(this.bot, sortie)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, new SortieEmbed(this.bot, sortie), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Syndicates.js b/src/commands/Ondemand/Syndicates.js similarity index 57% rename from src/commands/Syndicates.js rename to src/commands/Ondemand/Syndicates.js index 9f9a925c8..21c6e77f3 100644 --- a/src/commands/Syndicates.js +++ b/src/commands/Ondemand/Syndicates.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const SyndicateEmbed = require('../embeds/SyndicateEmbed.js'); +const Command = require('../../Command.js'); +const SyndicateEmbed = require('../../embeds/SyndicateEmbed.js'); /** @@ -13,8 +13,8 @@ class Syndicates extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.syndicate', 'syndicate', 'Gets the starchat nodes for the desired syndicate, or all.'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}syndicate(?:\\s+([\\w+\\s]+))?`, 'i'); + super(bot, 'warframe.worldstate.syndicate', 'syndicate', 'Gets the starchat nodes for the desired syndicate, or all.'); + this.regex = new RegExp('^syndicate(?:\\s+([\\w+\\s]+))?', 'i'); this.usages = [ { description: 'Display syndicate nodes for a syndicate.', @@ -29,18 +29,13 @@ class Syndicates extends Command { * or perform an action based on parameters. */ run(message) { - const syndicate = message.content.match(this.regex)[1]; + const syndicate = message.strippedContent.match(this.regex)[1]; this.bot.settings.getChannelPlatform(message.channel) .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const syndicateMissions = ws.syndicateMissions; - return message.channel.sendEmbed(new SyndicateEmbed(this.bot, - syndicateMissions, syndicate)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, new SyndicateEmbed(this.bot, + syndicateMissions, syndicate), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/Tutorial.js b/src/commands/Ondemand/Tutorial.js similarity index 64% rename from src/commands/Tutorial.js rename to src/commands/Ondemand/Tutorial.js index 393bb2a9f..e9debede2 100644 --- a/src/commands/Tutorial.js +++ b/src/commands/Ondemand/Tutorial.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const tutorials = require('../resources/tutorials.json'); +const Command = require('../../Command.js'); +const tutorials = require('../../resources/tutorials.json'); /** * Displays the response time for the bot and checks Warframe's servers to see if they are up */ @@ -11,8 +11,8 @@ class FrameProfile extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.warframe.tutorial', 'tutorial', 'Get a Warframe Tutorial Video'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}tutorial(.+)?`, 'i'); + super(bot, 'warframe.misc.tutorial', 'tutorial', 'Get a Warframe Tutorial Video'); + this.regex = new RegExp('^tutorial(.+)?', 'i'); this.usages = [ { description: 'Get a Warframe Tutorial Video', @@ -27,33 +27,24 @@ class FrameProfile extends Command { * or perform an action based on parameters. */ run(message) { - let query = message.content.match(this.regex)[1]; - let promise; + let query = message.strippedContent.match(this.regex)[1]; if (query) { query = query.trim().toLowerCase(); tutorials.forEach((tutorial) => { if (new RegExp(tutorial.regex, 'ig').test(query)) { - promise = message.reply(`Warfame Tutorial | ${tutorial.name} : ${tutorial.url}`); + this.messageManager.reply(`Warfame Tutorial | ${tutorial.name} : ${tutorial.url}`); } }); } else { - promise = message.channel.sendEmbed({ + this.messageManager.embed(message, { title: 'Available Tutorials', fields: [{ name: '_ _', value: tutorials.map(tutorial => tutorial.name).join('\n') }], footer: { icon_url: 'https://avatars1.githubusercontent.com/u/24436369', text: 'Data evaluated by Warframe Community Developers', }, - }); - } - if (promise) { - promise.then(() => { - if (message.deletable) { - message.delete(10000); - } - }) - .catch(this.logger.error); + }, true, false); } } } diff --git a/src/commands/Updates.js b/src/commands/Ondemand/Updates.js similarity index 62% rename from src/commands/Updates.js rename to src/commands/Ondemand/Updates.js index fe0554426..febcbce4d 100644 --- a/src/commands/Updates.js +++ b/src/commands/Ondemand/Updates.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const UpdateEmbed = require('../embeds/NewsEmbed.js'); +const Command = require('../../Command.js'); +const UpdateEmbed = require('../../embeds/NewsEmbed.js'); /** * Displays the currently active Warframe update news @@ -12,7 +12,7 @@ class Updates extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.updates', 'updates', 'Display the currently active update news'); + super(bot, 'warframe.worldstate.updates', 'updates', 'Display the currently active update news'); } /** @@ -25,12 +25,7 @@ class Updates extends Command { .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { const news = ws.news.filter(n => n.isUpdate()); - return message.channel.sendEmbed(new UpdateEmbed(this.bot, news, 'update')); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, new UpdateEmbed(this.bot, news, 'update'), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/VoidTrader.js b/src/commands/Ondemand/VoidTrader.js similarity index 57% rename from src/commands/VoidTrader.js rename to src/commands/Ondemand/VoidTrader.js index a28f0b0b5..6e7671223 100644 --- a/src/commands/VoidTrader.js +++ b/src/commands/Ondemand/VoidTrader.js @@ -1,7 +1,7 @@ 'use strict'; -const Command = require('../Command.js'); -const VoidTraderEmbed = require('../embeds/VoidTraderEmbed.js'); +const Command = require('../../Command.js'); +const VoidTraderEmbed = require('../../embeds/VoidTraderEmbed.js'); /** * Displays the currently active Invasions @@ -12,7 +12,7 @@ class VoidTrader extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'ondemand.baro', 'baro', 'Display the current status of the Void Trader'); + super(bot, 'warframe.worldstate.baro', 'baro', 'Display the current status of the Void Trader'); } /** @@ -24,13 +24,8 @@ class VoidTrader extends Command { this.bot.settings.getChannelPlatform(message.channel) .then(platform => this.bot.worldStates[platform].getData()) .then((ws) => { - const voidTrader = ws.voidTrader; - return message.channel.sendEmbed(new VoidTraderEmbed(this.bot, voidTrader)); - }).then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); + this.messageManager.embed(message, + new VoidTraderEmbed(this.bot, ws.voidTrader), true, false); }) .catch(this.logger.error); } diff --git a/src/commands/WhereIs.js b/src/commands/Ondemand/WhereIs.js similarity index 90% rename from src/commands/WhereIs.js rename to src/commands/Ondemand/WhereIs.js index ee891118e..014859fa4 100644 --- a/src/commands/WhereIs.js +++ b/src/commands/Ondemand/WhereIs.js @@ -1,7 +1,7 @@ 'use strict'; const Query = require('warframe-location-query'); -const Command = require('../Command.js'); +const Command = require('../../Command.js'); const extraSpace = '  '; @@ -14,8 +14,8 @@ class Whereis extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.whereis', 'whereis', 'whereis'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}where(?:\\s?is)?(?:\\s+([\\w+\\s]+))?`, 'i'); + super(bot, 'warframe.misc.whereis', 'whereis', 'whereis'); + this.regex = new RegExp('^where(?:\\s?is)?(?:\\s+([\\w+\\s]+))?', 'i'); this.usages = [ { @@ -33,7 +33,7 @@ class Whereis extends Command { * or perform an action based on parameters. */ run(message) { - const item = message.content.match(this.regex)[1]; + const item = message.strippedContent.match(this.regex)[1]; this.querier.getAll(item) .then((results) => { const resultsHasResults = Object.prototype.toString.call(results) === '[object Array]' && results.length > 0; diff --git a/src/commands/Wiki.js b/src/commands/Ondemand/Wiki.js similarity index 87% rename from src/commands/Wiki.js rename to src/commands/Ondemand/Wiki.js index bcaef3914..9d25a0ee3 100644 --- a/src/commands/Wiki.js +++ b/src/commands/Ondemand/Wiki.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); const Wikia = require('node-wikia'); const warframe = new Wikia('warframe'); @@ -14,8 +14,8 @@ class Wiki extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'misc.wiki', 'wiki', 'Search the Warframe Wiki for information'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}wiki\\s*([\\w\\s-]+)?`, 'i'); + super(bot, 'warframe.misc.wiki', 'wiki', 'Search the Warframe Wiki for information'); + this.regex = new RegExp('^wiki\\s*([\\w\\s-]+)?', 'i'); this.usages = [ { description: 'Search the Warframe wiki for a specific topic', @@ -30,7 +30,7 @@ class Wiki extends Command { * or perform an action based on parameters. */ run(message) { - const query = message.cleanContent.match(this.regex)[1]; + const query = message.strippedContent.match(this.regex)[1]; if (!query) { message.reply(`${this.md.codeMulti}Please specify a search term${this.md.blockEnd}`); } else { diff --git a/src/commands/Avatar.js b/src/commands/Owner/Avatar.js similarity index 80% rename from src/commands/Avatar.js rename to src/commands/Owner/Avatar.js index e364d0b0b..612308af2 100644 --- a/src/commands/Avatar.js +++ b/src/commands/Owner/Avatar.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); /** * Sets the avatar for the bot @@ -13,7 +13,7 @@ class Avatar extends Command { constructor(bot) { super(bot, 'core.avatar', 'avatar', 'Set Bot avatar'); this.ownerOnly = true; - this.regex = new RegExp(`^${this.bot.escapedPrefix}avatar\\s*(.*)?`, 'i'); + this.regex = new RegExp(`^${this.call}\\s*(.*)?`, 'i'); this.usages = [ { description: 'Set the bot\'s avatar url', @@ -28,7 +28,7 @@ class Avatar extends Command { * or perform an action based on parameters. */ run(message) { - const url = message.cleanContent.match(this.regex)[1]; + const url = message.strippedContent.match(this.regex)[1]; this.bot.client.user.setAvatar(url) .then(() => message.reply('New avatar set!')) .catch(this.logger.error); diff --git a/src/commands/LeaveServer.js b/src/commands/Owner/LeaveServer.js similarity index 83% rename from src/commands/LeaveServer.js rename to src/commands/Owner/LeaveServer.js index c280b7f1f..450cb0c2a 100644 --- a/src/commands/LeaveServer.js +++ b/src/commands/Owner/LeaveServer.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); /** * Leaves a server. @@ -13,7 +13,7 @@ class LeaveServer extends Command { constructor(bot) { super(bot, 'core.leaveserver', 'leaveserver', 'Leave a specified server'); this.ownerOnly = true; - this.regex = new RegExp(`^${this.bot.escapedPrefix}${this.call}\\s*(.*)?`, 'i'); + this.regex = new RegExp(`^${this.call}\\s*(.*)?`, 'i'); this.usages = [ { description: 'Tell the bot to leave a server, if it\'s cached', @@ -28,7 +28,7 @@ class LeaveServer extends Command { * or perform an action based on parameters. */ run(message) { - const serverid = message.cleanContent.match(this.regex)[1]; + const serverid = message.strippedContent.match(this.regex)[1]; if (this.bot.client.guilds.has(serverid)) { this.bot.client.guilds.get(serverid).leave() .then(guild => message.reply(`Left ${guild.name}`)) diff --git a/src/commands/Reload.js b/src/commands/Owner/Reload.js similarity index 54% rename from src/commands/Reload.js rename to src/commands/Owner/Reload.js index 887338c8b..601aadbec 100644 --- a/src/commands/Reload.js +++ b/src/commands/Owner/Reload.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); /** * Reloads the script containing the commands @@ -26,12 +26,15 @@ class Reload extends Command { this.commandHandler.loadCommands(); const commandsAfter = this.commandHandler.commands.map(c => c.id); - message.reply(`${this.zSWC}${this.md.codeMulti}Commands reloaded!${this.md.blockEnd}` + - `${this.md.lineEnd}\`\`\`diff${this.md.lineEnd}-${commandsBefore.sort().join(' ')}` + - `${this.md.lineEnd}+${commandsAfter.sort().join(' ')}\`\`\``); - if (message.deletable) { - message.delete(5000); - } + const commandsAdded = commandsAfter.filter(command => !commandsBefore.includes(command)); + const commandsRemoved = commandsBefore.filter(command => !commandsAfter.includes(command)); + + const commandsAddedString = commandsAdded.length > 0 ? commandsAdded.sort().join(' ') : ' No Commands Added'; + const commandsRemovedString = commandsRemoved.length > 0 ? commandsRemoved.sort().join(' ') : ' No Commands Removed'; + + this.messageManager.sendMessage(message, `${this.md.codeMulti}Commands reloaded!${this.md.blockEnd}` + + `${this.md.lineEnd}\`\`\`diff${this.md.lineEnd}-${commandsRemovedString}\`\`\`\n` + + `\`\`\`diff${this.md.lineEnd}+${commandsAddedString}\`\`\``, true, true); } } diff --git a/src/commands/Servers.js b/src/commands/Owner/Servers.js similarity index 94% rename from src/commands/Servers.js rename to src/commands/Owner/Servers.js index 45475cffa..573e56e45 100644 --- a/src/commands/Servers.js +++ b/src/commands/Owner/Servers.js @@ -1,6 +1,6 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); /** * Get a list of all servers diff --git a/src/commands/Pricecheck.js b/src/commands/Pricecheck.js deleted file mode 100644 index c0e956b92..000000000 --- a/src/commands/Pricecheck.js +++ /dev/null @@ -1,85 +0,0 @@ -'use strict'; - -const Nexus = require('warframe-nexus-query'); -const Command = require('../Command.js'); - -/** - * Looks up items from Nexus-stats.com - */ -class PriceCheck extends Command { - /** - * Constructs a callable command - * @param {Genesis} bot The bot object - */ - constructor(bot) { - super(bot, 'misc.pricecheck', 'pricecheck', 'pricecheck'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}p(?:rice)?\\s?c(?:heck)?(?:\\s+([\\w+\\s]+))?`, 'i'); - - this.usages = [ - { - description: 'Display an items worth from nexus-stats.com', - parameters: ['item'], - }, - ]; - - this.nexusQuerier = new Nexus(); - } - - /** - * Run the command - * @param {Message} message Message with a command to handle, reply to, - * or perform an action based on parameters. - */ - run(message) { - const item = message.content.match(this.regex)[1]; - - this.nexusQuerier.priceCheckQueryAttachment(item) - .then((result) => { - let embed = {}; - if (typeof result[0] === 'string') { - embed = { - color: 0xff0000, - title: 'Warframe - Pricecheck', - url: 'http://nexus-stats.com', - description: `Pricecheck for: ${item}`, - thumbnail: { - url: 'https://cdn.discordapp.com/icons/195582152849620992/4c1fbd47b3e6c8d49b6d2362c79a537b.jpg', - }, - fields: [ - { - name: '_ _', - value: result[0], - inline: true, - }, - ], - footer: { - icon_url: 'https://cdn.discordapp.com/icons/195582152849620992/4c1fbd47b3e6c8d49b6d2362c79a537b.jpg', - text: 'Pricechecks provided by Nexus Stats - https://nexus-stats.com', - }, - }; - } else { - const attachment = result[0]; - embed = { - description: `Price query for ${item}`, - color: parseInt(attachment.color, 16), - type: attachment.type, - title: attachment.title, - url: attachment.url, - fields: attachment.fields, - thumbnail: attachment.thumbnail, - footer: attachment.footer, - }; - } - return message.channel.sendEmbed(embed); - }) - .then(() => { - if (message.deletable) { - return message.delete(2000); - } - return Promise.resolve(); - }) - .catch(this.logger.error); - } -} - -module.exports = PriceCheck; diff --git a/src/commands/Settings/Disable.js b/src/commands/Settings/Disable.js new file mode 100644 index 000000000..5f66c4235 --- /dev/null +++ b/src/commands/Settings/Disable.js @@ -0,0 +1,149 @@ +'use strict'; + +const Command = require('../../Command.js'); +const EnableUsageEmbed = require('../../embeds/EnableUsageEmbed.js'); +const EnableInfoEmbed = require('../../embeds/EnableInfoEmbed.js'); + +class Disable extends Command { + constructor(bot) { + super(bot, 'settings.disable', 'disable', 'Disable a command.'); + this.usages = [ + { description: 'Disable a command for a role in a channel or channels', parameters: ['command id> in for )?|here|\\*)(?:\\s+for\\s((?:\\<\\#)?\\d+(?:\\>)?|\\*))?)?)?`, + 'i'); + this.blacklistable = false; + this.requiresAuth = true; + } + + run(message) { + const params = message.strippedContent.match(this.regex); + if (!params[1]) { + message.channel.sendEmbed(new EnableUsageEmbed(this.bot, null, 0)); + } else { + params.splice(0, 1); + const commands = this.getCommandsToEnable(params[0]); + let channels = []; + + if (params[1]) { + channels = this.getChannels(message.mentions.channels.length > 0 + ? message.mentions.channels : params[1], message); + } else { + channels = [message.channel]; + } + + let target = {}; + if (params[2] || + message.mentions.roles.array().length > 0 || message.mentions.users.array().length > 0) { + target = this.getTarget(params[2], message.mentions ? message.mentions.roles : [], + message.mentions ? message.mentions.users : [], message); + } else { + target = message.guild.roles.find('name', '@everyone'); + } + const infoEmbed = new EnableInfoEmbed(this.bot, 0, [commands, channels, target.toString()]); + const promises = []; + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + if (respondToSettings) { + promises.push(message.channel.sendEmbed(infoEmbed)); + } + }); + commands.forEach((command) => { + channels.forEach((channel) => { + if (target.type === 'Role') { + promises.push(this.bot.settings + .setChannelPermissionForRole(channel, target, command, 0)); + } else { + promises.push(this.bot.settings + .setChannelPermissionForMember(channel, target, command, 0)); + } + }); + }); + promises.forEach((promise) => { + promise.then((msg) => { + if (msg.deletable) { + msg.delete(50000).catch(this.logger.error); + } + }).catch(this.logger.error); + }); + } + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + /** + * Get the list of commands based on input + * @param {string} commandIdParam parameter for determining commands + * @returns {Array} command ids to enable + */ + getCommandsToEnable(commandIdParam) { + const commandsToEnable = []; + const commandRegex = new RegExp(commandIdParam.replace('.', '\\.').replace('*', '.*'), 'ig'); + this.bot.commandHandler.commands.forEach((command) => { + if (commandRegex.test(command.id) && command.blacklistable) { + commandsToEnable.push(command.id); + } + }); + return commandsToEnable; + } + + /** + * Get the list of channels to enable commands in based on the parameters + * @param {string|Array} channelsParam parameter for determining channels + * @param {Message} message Discord message to get information on channels + * @returns {Array} channel ids to enable commands in + */ + getChannels(channelsParam, message) { + let channels = []; + if (typeof channelsParam === 'string') { + // handle it for strings + if (channelsParam !== '*' && channelsParam !== 'here') { + channels.push(this.bot.client.channels.get(channelsParam.trim())); + } else if (channelsParam === '*') { + channels = channels.concat(message.guild.channels.array().filter(channel => channel.type === 'text')); + } else if (channelsParam === 'here') { + channels.push(message.channel); + } + } else { + channels.concat(channelsParam); + } + return channels; + } + + /** + * Get the target role or user from the parameter string + * or role mentions or user mentions, preferring the latter 2. + * @param {string} targetParam string from the command to determine the user or role + * @param {Array} roleMentions role mentions from the command + * @param {Array} userMentions user mentions from the command + * @param {Message} message message to get information on users and roles + * @returns {Role|User} target or user to disable commands for + */ + getTarget(targetParam, roleMentions, userMentions, message) { + let target = ''; + if (roleMentions.array().length > 0) { + target = roleMentions.array()[0]; + target.type = 'Role'; + } else if (userMentions.array().length > 0) { + target = userMentions.array()[0]; + target.type = 'User'; + } else { + const userTarget = this.bot.client.users.get(targetParam); + const roleTarget = message.guild.roles.get(targetParam); + if (targetParam === '*') { + target = message.guild.roles.find('name', '@everyone'); + target.type = 'Role'; + } else if (roleTarget) { + target = roleTarget; + target.type = 'Role'; + } else if (userTarget) { + target = userTarget; + target.type = 'User'; + } + } + return target; + } +} + +module.exports = Disable; diff --git a/src/commands/Settings/DisablePingEvent.js b/src/commands/Settings/DisablePingEvent.js new file mode 100644 index 000000000..8f2700333 --- /dev/null +++ b/src/commands/Settings/DisablePingEvent.js @@ -0,0 +1,89 @@ +'use strict'; + +const Command = require('../../Command.js'); +const eventTypes = require('../../resources/trackables.json').eventTypes; + +/** + * Sets the current guild's custom prefix + */ +class EnablePingEvent extends Command { + constructor(bot) { + super(bot, 'settings.ping.event.disable', 'ping off event'); + this.usages = [ + { description: 'Show command for pinging for items', parameters: [] }, + { description: 'Disable pinging for an event or events', parameters: ['event(s) to disable ping for'] }, + ]; + this.regex = new RegExp(`^${this.call}s?(?:\\s+(${eventTypes.join('|')}|all))?`, 'i'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const unsplitItems = message.strippedContent.match(this.regex)[1]; + if (!unsplitItems) { + this.sendInstructionEmbed(message); + return; + } + + const items = unsplitItems.split(' '); + let itemsToPing = []; + if (items[0] === 'all') { + itemsToPing = itemsToPing.concat(eventTypes); + } else { + items.forEach((item) => { + if (eventTypes.includes(item.trim())) { + itemsToPing.push(item.trim()); + } else { + this.sendInstructionEmbed(message); + } + }); + } + + const promises = []; + itemsToPing.forEach(item => promises.push(this.bot.settings + .setEventTypePing(message.channel, item, false))); + + promises.forEach(promise => promise.catch(this.logger.error)); + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }).catch(this.logger.error); + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + sendInstructionEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel) + .then(prefix => message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${prefix}${this.call} `, + value: 'Disable pinging for an event', + }, + { + name: 'Possible values:', + value: `\n${eventTypes.join('\n')}`, + }, + ], + })) + .catch(this.logger.error); + } +} + +module.exports = EnablePingEvent; diff --git a/src/commands/Settings/DisablePingItem.js b/src/commands/Settings/DisablePingItem.js new file mode 100644 index 000000000..2d93ec6bb --- /dev/null +++ b/src/commands/Settings/DisablePingItem.js @@ -0,0 +1,89 @@ +'use strict'; + +const Command = require('../../Command.js'); +const rewardTypes = require('../../resources/trackables.json').rewardTypes; + +/** + * Sets the current guild's custom prefix + */ +class DisablePingEvent extends Command { + constructor(bot) { + super(bot, 'settings.ping.item.disable', 'ping off item'); + this.usages = [ + { description: 'Show command for pinging for items', parameters: [] }, + { description: 'Disable pinging for an item or items', parameters: ['item(s) to disable ping for'] }, + ]; + this.regex = new RegExp(`^${this.call}s?(?:\\s+(${rewardTypes.join('|')}|all))?`, 'i'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const unsplitItems = message.strippedContent.match(this.regex)[1]; + if (!unsplitItems) { + this.sendInstructionEmbed(message); + return; + } + + const items = unsplitItems.split(' '); + let itemsToPing = []; + if (items[0] === 'all') { + itemsToPing = itemsToPing.concat(rewardTypes); + } else { + items.forEach((item) => { + if (rewardTypes.includes(item.trim())) { + itemsToPing.push(item.trim()); + } else { + this.sendInstructionEmbed(message); + } + }); + } + + const promises = []; + itemsToPing.forEach(item => promises.push(this.bot.settings + .setItemPing(message.channel, item, false))); + + promises.forEach(promise => promise.catch(this.logger.error)); + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }).catch(this.logger.error); + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + sendInstructionEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel) + .then(prefix => message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${prefix}${this.call} `, + value: 'Disable pinging for an item', + }, + { + name: 'Possible values:', + value: `\n${rewardTypes.join('\n')}`, + }, + ], + })) + .catch(this.logger.error); + } +} + +module.exports = DisablePingEvent; diff --git a/src/commands/Settings/Enable.js b/src/commands/Settings/Enable.js new file mode 100644 index 000000000..65c0658d5 --- /dev/null +++ b/src/commands/Settings/Enable.js @@ -0,0 +1,142 @@ +'use strict'; + +const Command = require('../../Command.js'); +const EnableUsageEmbed = require('../../embeds/EnableUsageEmbed.js'); +const EnableInfoEmbed = require('../../embeds/EnableInfoEmbed.js'); + +class Enable extends Command { + constructor(bot) { + super(bot, 'settings.enable', 'enable', 'Enable a command.'); + this.usages = [ + { description: 'Enable a command for a role in a channel or channels', parameters: ['command id> in for )?|\\*|here)(?:\\s+for\\s((?:\\<\\#)?\\d+(?:\\>)?|\\*))?)?)?`, + 'i'); + this.requiresAuth = true; + this.blacklistable = false; + } + + run(message) { + const params = message.strippedContent.match(this.regex); + if (!params[1]) { + message.channel.sendEmbed(new EnableUsageEmbed(this.bot)); + } else { + params.splice(0, 1); + const commands = this.getCommandsToEnable(params[0]); + let channels = []; + + if (params[1]) { + channels = this.getChannels(message.mentions.channels.length > 0 + ? message.mentions.channels : params[1], message); + } else { + channels = [message.channel]; + } + + let target = {}; + if (params[2]) { + target = this.getTarget(params[2], message.mentions.roles, + message.mentions.users, message); + } else { + target = message.guild.roles.find('name', '@everyone'); + } + const infoEmbed = new EnableInfoEmbed(this.bot, 1, [commands, channels, target.toString()]); + const promises = []; + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + if (respondToSettings) { + promises.push(message.channel.sendEmbed(infoEmbed)); + } + }); + commands.forEach((command) => { + channels.forEach((channel) => { + if (target.type === 'Role') { + promises.push(this.bot.settings + .setChannelPermissionForRole(channel, target, command, 1)); + } else { + promises.push(this.bot.settings + .setChannelPermissionForMember(channel, target, command, 1)); + } + }); + }); + promises.forEach(promise => promise.catch(this.logger.error)); + } + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + /** + * Get the list of commands based on input + * @param {string} commandIdParam parameter for determining commands + * @returns {Array} command ids to enable + */ + getCommandsToEnable(commandIdParam) { + const commandsToEnable = []; + const commandRegex = new RegExp(commandIdParam.replace('.', '\\.').replace('*', '.*'), 'ig'); + this.bot.commandHandler.commands.forEach((command) => { + if (commandRegex.test(command.id) && command.blacklistable) { + commandsToEnable.push(command.id); + } + }); + return commandsToEnable; + } + + /** + * Get the list of channels to enable commands in based on the parameters + * @param {string|Array} channelsParam parameter for determining channels + * @param {Message} message Discord message to get information on channels + * @returns {Array} channel ids to enable commands in + */ + getChannels(channelsParam, message) { + let channels = []; + if (typeof channelsParam === 'string') { + // handle it for strings + if (channelsParam !== '*' && channelsParam !== 'here') { + channels.push(this.bot.client.channels.get(channelsParam.trim())); + } else if (channelsParam === '*') { + channels = channels.concat(message.guild.channels.array().filter(channel => channel.type === 'text')); + } else if (channelsParam === 'here') { + channels.push(message.channel); + } + } else { + channels.concat(channelsParam); + } + return channels; + } + + /** + * Get the target role or user from the parameter string + * or role mentions or user mentions, preferring the latter 2. + * @param {string} targetParam string from the command to determine the user or role + * @param {Array} roleMentions role mentions from the command + * @param {Array} userMentions user mentions from the command + * @param {Message} message message to get information on users and roles + * @returns {Role|User} target or user to enable commands for + */ + getTarget(targetParam, roleMentions, userMentions, message) { + let target = ''; + if (roleMentions.length > 0) { + target = roleMentions[0]; + target.type = 'Role'; + } else if (userMentions.length > 0) { + target = userMentions[0]; + target.type = 'User'; + } else { + const userTarget = this.bot.client.users.get(targetParam); + const roleTarget = message.guild.roles.get(targetParam); + if (targetParam) { + target = message.guild.roles.find('name', '@everyone'); + target.type = 'Role'; + } else if (roleTarget) { + target = roleTarget; + target.type = 'Role'; + } else if (userTarget) { + target = userTarget; + target.type = 'User'; + } + } + return target; + } +} + +module.exports = Enable; diff --git a/src/commands/Settings/EnablePingEvent.js b/src/commands/Settings/EnablePingEvent.js new file mode 100644 index 000000000..46d095123 --- /dev/null +++ b/src/commands/Settings/EnablePingEvent.js @@ -0,0 +1,89 @@ +'use strict'; + +const Command = require('../../Command.js'); +const eventTypes = require('../../resources/trackables.json').eventTypes; + +/** + * Sets the current guild's custom prefix + */ +class EnablePingEvent extends Command { + constructor(bot) { + super(bot, 'settings.ping.event.enable', 'ping on event'); + this.usages = [ + { description: 'Show command for pinging for items', parameters: [] }, + { description: 'Enable pinging for an event or events', parameters: ['event(s) to enable ping for'] }, + ]; + this.regex = new RegExp(`^${this.call}s?(?:\\s+(${eventTypes.join('|')}|all))?`, 'i'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const unsplitItems = message.strippedContent.match(this.regex)[1]; + if (!unsplitItems) { + this.sendInstructionEmbed(message); + return; + } + + const items = unsplitItems.split(' '); + let itemsToPing = []; + if (items[0] === 'all') { + itemsToPing = itemsToPing.concat(eventTypes); + } else { + items.forEach((item) => { + if (eventTypes.includes(item.trim())) { + itemsToPing.push(item.trim()); + } else { + this.sendInstructionEmbed(message); + } + }); + } + + const promises = []; + itemsToPing.forEach(item => promises.push(this.bot.settings + .setEventTypePing(message.channel, item, true))); + + promises.forEach(promise => promise.catch(this.logger.error)); + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }).catch(this.logger.error); + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + sendInstructionEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel) + .then(prefix => message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${prefix}${this.call} `, + value: 'Enable pinging for an event', + }, + { + name: 'Possible values:', + value: `\n${eventTypes.join('\n')}`, + }, + ], + })) + .catch(this.logger.error); + } +} + +module.exports = EnablePingEvent; diff --git a/src/commands/Settings/EnablePingItem.js b/src/commands/Settings/EnablePingItem.js new file mode 100644 index 000000000..c978535ca --- /dev/null +++ b/src/commands/Settings/EnablePingItem.js @@ -0,0 +1,89 @@ +'use strict'; + +const Command = require('../../Command.js'); +const rewardTypes = require('../../resources/trackables.json').rewardTypes; + +/** + * Sets the current guild's custom prefix + */ +class EnablePingItem extends Command { + constructor(bot) { + super(bot, 'settings.ping.item.enable', 'ping on item'); + this.usages = [ + { description: 'Show command for pinging for items', parameters: [] }, + { description: 'Enable pinging for an item or items', parameters: ['item(s) to enable ping for'] }, + ]; + this.regex = new RegExp(`^${this.call}s?(?:\\s+(${rewardTypes.join('|')}|all))?`, 'i'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const unsplitItems = message.strippedContent.match(this.regex)[1]; + if (!unsplitItems) { + this.sendInstructionEmbed(message); + return; + } + + const items = unsplitItems.split(' '); + let itemsToPing = []; + if (items[0] === 'all') { + itemsToPing = itemsToPing.concat(rewardTypes); + } else { + items.forEach((item) => { + if (rewardTypes.includes(item.trim())) { + itemsToPing.push(item.trim()); + } else { + this.sendInstructionEmbed(message); + } + }); + } + + const promises = []; + itemsToPing.forEach(item => promises.push(this.bot.settings + .setItemPing(message.channel, item, true))); + + promises.forEach(promise => promise.catch(this.logger.error)); + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }).catch(this.logger.error); + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + sendInstructionEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel) + .then(prefix => message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${prefix}${this.call} `, + value: 'Enable pinging for an item', + }, + { + name: 'Possible values:', + value: `\n${rewardTypes.join('\n')}`, + }, + ], + })) + .catch(this.logger.error); + } +} + +module.exports = EnablePingItem; diff --git a/src/commands/Settings/GetCommandIds.js b/src/commands/Settings/GetCommandIds.js new file mode 100644 index 000000000..6f157d686 --- /dev/null +++ b/src/commands/Settings/GetCommandIds.js @@ -0,0 +1,46 @@ +'use strict'; + +const Command = require('../../Command.js'); +const CommandIdEmbed = require('../../embeds/CommandIdEmbed.js'); + +/** + * Get a list of all servers + */ +class GetCommandIds extends Command { + /** + * Constructs a callable command + * @param {Bot} bot The bot object + */ + constructor(bot) { + super(bot, 'settings.getcommandids', 'getcommandids', 'Get list of bot command ids available for you to view'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const commands = this.commandHandler.commands.filter(command => + !command.ownerOnly || (message.author.id === this.bot.owner && command.ownerOnly)); + const embed = new CommandIdEmbed(this.bot, commands); + if (message.channel.type !== 'dm') { + message.reply('Check your direct messages for more information.') + .then((reply) => { + if (reply.deletable) { + reply.delete(10000); + } + }).catch(this.logger.error); + } + const promises = [ + message.author.sendEmbed(embed).then(() => { + if (message.deletable) { + message.delete(2000); + } + }), + ]; + Promise.all(promises).catch(this.logger.error); + } +} + +module.exports = GetCommandIds; diff --git a/src/commands/Settings/Language.js b/src/commands/Settings/Language.js new file mode 100644 index 000000000..2c2995ce7 --- /dev/null +++ b/src/commands/Settings/Language.js @@ -0,0 +1,47 @@ +'use strict'; + +const Command = require('../../Command.js'); + +class Language extends Command { + constructor(bot) { + super(bot, 'settings.language', 'language'); + this.usages = [ + { description: 'Change this channel\'s language', parameters: ['language'] }, + ]; + this.regex = new RegExp(`^${this.call}\\s?(.+)?$`, 'i'); + } + + run(message) { + const language = message.strippedContent.match(this.regex)[1]; + if (!language || !this.bot.languages.includes(language.toLowerCase())) { + message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${this.bot.prefix}${this.call} `, + value: `Language is one of ${this.bot.languages.join(', ')}`, + }, + ], + }); + } else { + this.bot.settings.setChannelLanguage(message.channel, language.toLowerCase()).then(() => { + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated'); + } + return retPromise; + }); + }).catch(this.logger.error); + } + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } +} + +module.exports = Language; diff --git a/src/commands/Platform.js b/src/commands/Settings/Platform.js similarity index 71% rename from src/commands/Platform.js rename to src/commands/Settings/Platform.js index c40a039ac..82ee1e404 100644 --- a/src/commands/Platform.js +++ b/src/commands/Settings/Platform.js @@ -1,19 +1,18 @@ 'use strict'; -const Command = require('../Command.js'); +const Command = require('../../Command.js'); class Platform extends Command { constructor(bot) { - super(bot, 'settings.platform', 'platform'); + super(bot, 'settings.platform', 'platform', 'Change a channel\'s platform'); this.usages = [ { description: 'Change this channel\'s platform', parameters: ['platform'] }, ]; - this.regex = new RegExp(`^${this.bot.escapedPrefix}${this.call}(?:\\s+([pcsxb14]{2,3}))?`, - 'i'); + this.regex = new RegExp(`${this.call}(?:\\s+([pcsxb14]{2,3}))?`, 'i'); } run(message) { - const platform = message.cleanContent.match(this.regex)[1]; + const platform = message.strippedContent.match(this.regex)[1]; if (!platform || !this.bot.platforms.includes(platform.toLowerCase())) { message.channel.sendEmbed({ title: 'Usage', @@ -28,8 +27,7 @@ class Platform extends Command { }); } else { this.bot.settings.setChannelPlatform(message.channel, platform.toLowerCase()).then(() => { - message.react('\u2705'); - return message.reply('Settings updated'); + this.messageManager.notifySettingsChange(message, true, true); }).catch(this.logger.error); } if (message.deletable) { diff --git a/src/commands/Settings/Prefix.js b/src/commands/Settings/Prefix.js new file mode 100644 index 000000000..621b85f72 --- /dev/null +++ b/src/commands/Settings/Prefix.js @@ -0,0 +1,85 @@ +'use strict'; + +const Command = require('../../Command.js'); + +/** + * Sets the current guild's custom prefix + */ +class Prefix extends Command { + constructor(bot) { + super(bot, 'settings.prefix', 'prefix'); + this.usages = [ + { description: 'Change this channel\'s platform', parameters: ['prefix (up to 3 characters)'] }, + ]; + this.regex = new RegExp(`^${this.call}(?:\\s+(.+))?`, + 'i'); + this.requiresAuth = true; + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const prefix = message.strippedContent.match(this.regex)[1]; + if (!prefix) { + message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${this.bot.prefix}${this.call} `, + value: 'Set the channel\'s custom prefix', + }, + ], + }); + } else if (prefix === 'reset') { + let promise = null; + if (message.channel.type === 'text') { + promise = this.bot.settings.resetGuildPrefix(message.channel.guild); + } else { + promise = this.bot.settings.resetChannelPrefix(message.channel); + } + promise.then(() => { + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated'); + } + return retPromise; + }); + }).catch(this.logger.error); + } else { + let promise = null; + if (message.channel.type === 'text') { + promise = this.bot.settings.setGuildPrefix(message.channel.guild, prefix); + } else { + promise = this.bot.settings.setChannelPrefix(message.channel, prefix); + } + promise.then(() => { + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }); + }).catch(this.logger.error); + } + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } +} + +module.exports = Prefix; diff --git a/src/commands/Settings/RespondToSettings.js b/src/commands/Settings/RespondToSettings.js new file mode 100644 index 000000000..2f81a5968 --- /dev/null +++ b/src/commands/Settings/RespondToSettings.js @@ -0,0 +1,41 @@ +'use strict'; + +const Command = require('../../Command.js'); + +class RespondToSettings extends Command { + constructor(bot) { + super(bot, 'settings.respondSettings', 'Set whether or not to respond to settings'); + this.usages = [ + { description: 'Change if this channel has settings changes resonded in it', parameters: ['response enabled'] }, + ]; + this.regex = new RegExp('^respond?\\s?settings\\s?(.+)?$', 'i'); + } + + run(message) { + const enable = message.strippedContent.match(this.regex)[1]; + if (!enable) { + const embed = { + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${this.bot.prefix}${this.call} `, + value: '_ _', + }, + ], + }; + this.messageManager.embed(message, embed, true, true); + } else { + let enableResponse = false; + if (enable === 'enable' || enable === 'enable' || enable === '1' || enable === 'true') { + enableResponse = true; + } + this.bot.settings.setChannelResponseToSettings(message.channel, enableResponse) + .then(() => this.messageManager.notifySettingsChange(message, true, true)) + .catch(this.logger.error); + } + } +} + +module.exports = RespondToSettings; diff --git a/src/commands/Settings/Settings.js b/src/commands/Settings/Settings.js new file mode 100644 index 000000000..fee88b72b --- /dev/null +++ b/src/commands/Settings/Settings.js @@ -0,0 +1,60 @@ +'use strict'; + +const Command = require('../../Command.js'); +const SettingsEmbed = require('../../embeds/SettingsEmbed.js'); + +class Settings extends Command { + constructor(bot) { + super(bot, 'settings.settings', 'settings', 'Get settings'); + this.regex = new RegExp(`^${this.call}$`, 'i'); + } + + run(message) { + const settings = []; + this.bot.settings.getChannelLanguage(message.channel) + .then((language) => { + settings.push({ name: 'Language', value: language }); + return this.bot.settings.getChannelPlatform(message.channel); + }) + .then((platform) => { + settings.push({ name: 'Platform', value: platform }); + return this.bot.settings.getChannelResponseToSettings(message.channel); + }) + .then((respond) => { + settings.push({ name: 'Respond to Settings', value: respond ? 'yes' : 'no' }); + return this.bot.settings.getChannelPrefix(message.channel); + }) + .then((prefix) => { + settings.push({ name: 'Command Prefix', value: prefix }); + return this.bot.settings.getTrackedItems(message.channel); + }) + .then((items) => { + settings.push({ + name: 'Tracked Items', + value: items.length > 0 ? `\n${items.join('\n')}` : 'No Tracked Items', + inline: true, + }); + return this.bot.settings.getTrackedEventTypes(message.channel); + }) + .then((types) => { + settings.push({ + name: 'Tracked Events', + value: types.length > 0 ? `\n${types.join('\n')}` : 'No Tracked Event Types', + inline: true, + }); + const embed = new SettingsEmbed(this.bot, message.channel, settings); + message.channel.sendEmbed(embed).then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + }) + .catch(this.logger.error); + + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } +} + +module.exports = Settings; diff --git a/src/commands/Settings/TrackEvent.js b/src/commands/Settings/TrackEvent.js new file mode 100644 index 000000000..24eeb1d3d --- /dev/null +++ b/src/commands/Settings/TrackEvent.js @@ -0,0 +1,89 @@ +'use strict'; + +const Command = require('../../Command.js'); +const eventTypes = require('../../resources/trackables.json').eventTypes; + +/** + * Sets the current guild's custom prefix + */ +class TrackEvent extends Command { + constructor(bot) { + super(bot, 'settings.track.event', 'track event'); + this.usages = [ + { description: 'Show tracking command for tracking events', parameters: [] }, + { description: 'Track an event or events', parameters: ['event(s) to track'] }, + ]; + this.regex = new RegExp(`^${this.call}s?(?:\\s+(${eventTypes.join('|')}|all))?`, 'i'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const unsplitItems = message.strippedContent.match(this.regex)[1]; + if (!unsplitItems) { + this.sendInstructionEmbed(message); + return; + } + + const items = unsplitItems.split(' '); + let itemsToTrack = []; + if (items[0] === 'all') { + itemsToTrack = itemsToTrack.concat(eventTypes); + } else { + items.forEach((item) => { + if (eventTypes.includes(item.trim())) { + itemsToTrack.push(item.trim()); + } else { + this.sendInstructionEmbed(message); + } + }); + } + + const promises = []; + itemsToTrack.forEach(item => promises.push(this.bot.settings + .trackEventType(message.channel, item))); + + promises.forEach(promise => promise.catch(this.logger.error)); + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }).catch(this.logger.error); + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + sendInstructionEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel) + .then(prefix => message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${prefix}${this.call} `, + value: 'Track events to be alerted in this channel.', + }, + { + name: 'Possible values:', + value: `\n${eventTypes.join('\n')}`, + }, + ], + })) + .catch(this.logger.error); + } +} + +module.exports = TrackEvent; diff --git a/src/commands/Settings/TrackItem.js b/src/commands/Settings/TrackItem.js new file mode 100644 index 000000000..2c141c361 --- /dev/null +++ b/src/commands/Settings/TrackItem.js @@ -0,0 +1,93 @@ +'use strict'; + +const Command = require('../../Command.js'); +const rewardTypes = require('../../resources/trackables.json').rewardTypes; + +/** + * Sets the current guild's custom prefix + */ +class TrackItem extends Command { + constructor(bot) { + super(bot, 'settings.track.item', 'track item'); + this.usages = [ + { description: 'Show tracking command for tracking items', parameters: [] }, + { description: 'Track an item or items', parameters: ['item(s) to track'] }, + ]; + this.regex = new RegExp(`^${this.call}s?(?:\\s?(${rewardTypes.join('|')}|all))?`, 'i'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const unsplitItems = message.strippedContent.match(this.regex)[1]; + if (!unsplitItems) { + this.sendInstructionEmbed(message); + return; + } + + const items = unsplitItems.split(' '); + let itemsToTrack = []; + if (items[0] === 'all') { + itemsToTrack = itemsToTrack.concat(rewardTypes); + } else { + const invalidItems = []; + items.forEach((item) => { + if (rewardTypes.includes(item.trim())) { + itemsToTrack.push(item.trim()); + } else { + invalidItems.push(item.trim()); + } + if (invalidItems.length > 0) { + this.sendInstructionEmbed(message, invalidItems); + } + }); + } + + const promises = []; + itemsToTrack.forEach(item => promises.push(this.bot.settings + .trackItem(message.channel, item))); + + promises.forEach(promise => promise.catch(this.logger.error)); + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }).catch(this.logger.error); + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + sendInstructionEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel) + .then(prefix => message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${prefix}${this.call} `, + value: 'Track items to be alerted in this channel.', + }, + { + name: 'Possible values:', + value: `\n${rewardTypes.join('\n')}`, + }, + ], + })) + .catch(this.logger.error); + } +} + +module.exports = TrackItem; diff --git a/src/commands/Settings/UntrackEvent.js b/src/commands/Settings/UntrackEvent.js new file mode 100644 index 000000000..8d43d795d --- /dev/null +++ b/src/commands/Settings/UntrackEvent.js @@ -0,0 +1,93 @@ +'use strict'; + +const Command = require('../../Command.js'); +const eventTypes = require('../../resources/trackables.json').eventTypes; + +/** + * Sets the current guild's custom prefix + */ +class UntrackItem extends Command { + constructor(bot) { + super(bot, 'settings.untrack.event', 'untrack event'); + this.usages = [ + { description: 'Show tracking command for untracking events', parameters: [] }, + { description: 'Untrack an event or events', parameters: ['event(s) to untrack'] }, + ]; + this.regex = new RegExp(`^${this.call}s?(?:\\s?(${eventTypes.join('|')}|all))?`, 'i'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const unsplitItems = message.strippedContent.match(this.regex)[1]; + if (!unsplitItems) { + this.sendInstructionEmbed(message); + return; + } + + const items = unsplitItems.split(' '); + let itemsToTrack = []; + if (items[0] === 'all') { + itemsToTrack = itemsToTrack.concat(eventTypes); + } else { + const invalidItems = []; + items.forEach((item) => { + if (eventTypes.includes(item.trim())) { + itemsToTrack.push(item.trim()); + } else { + invalidItems.push(item.trim()); + } + if (invalidItems.length > 0) { + this.sendInstructionEmbed(message, invalidItems); + } + }); + } + + const promises = []; + itemsToTrack.forEach(item => promises.push(this.bot.settings + .untrackEventType(message.channel, item))); + + promises.forEach(promise => promise.catch(this.logger.error)); + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }).catch(this.logger.error); + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + sendInstructionEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel) + .then(prefix => message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${prefix}${this.call} `, + value: 'Untrack events to be alerted in this channel.', + }, + { + name: 'Possible values:', + value: `\n${eventTypes.join('\n')}`, + }, + ], + })) + .catch(this.logger.error); + } +} + +module.exports = UntrackItem; diff --git a/src/commands/Settings/UntrackItem.js b/src/commands/Settings/UntrackItem.js new file mode 100644 index 000000000..27ac682d8 --- /dev/null +++ b/src/commands/Settings/UntrackItem.js @@ -0,0 +1,92 @@ +'use strict'; + +const Command = require('../../Command.js'); +const rewardTypes = require('../../resources/trackables.json').rewardTypes; + +/** + * Sets the current guild's custom prefix + */ +class Prefix extends Command { + constructor(bot) { + super(bot, 'settings.untrack.item', 'untrack item'); + this.usages = [ + { description: 'Unrack an item or items', parameters: ['item to untrack'] }, + ]; + this.regex = new RegExp(`^${this.call}s?(?:\\s?(${rewardTypes.join('|')}|all))?`, 'i'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + const unsplitItems = message.strippedContent.match(this.regex)[1]; + if (!unsplitItems) { + this.sendInstructionEmbed(message); + return; + } + + const items = unsplitItems.split(' '); + let itemsToTrack = []; + if (items[0] === 'all') { + itemsToTrack = itemsToTrack.concat(rewardTypes); + } else { + const invalidItems = []; + items.forEach((item) => { + if (rewardTypes.includes(item.trim())) { + itemsToTrack.push(item.trim()); + } else { + invalidItems.push(item.trim()); + } + if (invalidItems.length > 0) { + this.sendInstructionEmbed(message, invalidItems); + } + }); + } + + const promises = []; + itemsToTrack.forEach(item => promises.push(this.bot.settings + .untrackItem(message.channel, item))); + + promises.forEach(promise => promise.catch(this.logger.error)); + message.react('\u2705'); + this.bot.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + let retPromise = null; + if (respondToSettings) { + retPromise = message.reply('Settings updated').then((settingsMsg) => { + if (settingsMsg.deletable) { + settingsMsg.delete(50000).catch(this.logger.error); + } + }); + } + return retPromise; + }).catch(this.logger.error); + if (message.deletable) { + message.delete(5000).catch(this.logger.error); + } + } + + sendInstructionEmbed(message) { + this.bot.settings.getChannelPrefix(message.channel) + .then(prefix => message.channel.sendEmbed({ + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${prefix}${this.call} `, + value: 'Untrack items to be alerted in this channel.', + }, + { + name: 'Possible values:', + value: `\n${rewardTypes.join('\n')}`, + }, + ], + })) + .catch(this.logger.error); + } +} + +module.exports = Prefix; diff --git a/src/commands/Shields.js b/src/commands/Shields.js deleted file mode 100644 index 3ec9db2ce..000000000 --- a/src/commands/Shields.js +++ /dev/null @@ -1,85 +0,0 @@ -'use strict'; - -const Command = require('../Command.js'); - -function shieldCalc(baseShields, baseLevel, currentLevel) { - return (parseFloat(baseShields) + - (((parseFloat(currentLevel) - parseFloat(baseLevel)) ** 2) - * 0.0075 * parseFloat(baseShields))).toFixed(2); -} - -function shieldString(shields, level) { - return `At level ${parseFloat(level).toFixed(0)}, your enemy would have ${shields} Shields.`; -} - -/** - * Performs shield calculations - */ -class Shields extends Command { - /** - * Constructs a callable command - * @param {Genesis} bot The bot object - */ - constructor(bot) { - super(bot, 'misc.shields', 'shields', 'shields'); - this.regex = new RegExp(`^${this.bot.escapedPrefix}shield(?: +([\\d+\\.?\\d* ]+))?`, 'i'); - - this.usages = [ - { - description: 'Display an enemy\'s current shields.', - parameters: ['base shields', 'base level', 'current level'], - }, - ]; - } - - /** - * Run the command - * @param {Message} message Message with a command to handle, reply to, - * or perform an action based on parameters. - */ - run(message) { - const pattern3Params = /(\d+\.?\d*)(?:\s+(\d+\.?\d*)\s+(\d+\.?\d*))?$/; - const params = message.content.match(pattern3Params); - const color = params && params.length > 3 ? 0x00ff00 : 0xff0000; - const embed = { - color, - author: { - name: this.bot.client.user.clientID, - icon_url: this.bot.client.user.avatarURL, - }, - title: 'Warframe - Shields', - url: 'https://warframe.com', - thumbnail: { - url: 'http://i.imgur.com/BVUXIjA.png', - }, - fields: [ - { - name: '_ _', - value: '', - }, - ], - footer: { - icon_url: 'https://avatars1.githubusercontent.com/u/24436369', - text: 'Data evaluated by Warframe Community Developers', - }, - }; - - if (params && params.length > 3) { - const shields = params[1]; - const baseLevel = params[2]; - const currentLevel = params[3]; - this.logger.debug('Entered 3-param shield'); - const calc = shieldCalc(shields, baseLevel, currentLevel); - embed.fields[0].name = 'Shield calculation'; - embed.fields[0].value = shieldString(calc, currentLevel); - } else { - this.logger.debug('Entered 0-param shield'); - embed.fields[0].value = `${this.bot.prefix}shields (Base Shelds) (Base Level) (Current Level) - calculate shields and stats.`; - embed.fields[0].name = 'Possible uses include:'; - } - - message.channel.sendEmbed(embed); - } -} - -module.exports = Shields; diff --git a/src/embeds/BaseEmbed.js b/src/embeds/BaseEmbed.js index fb6b5aec2..f160cfb16 100644 --- a/src/embeds/BaseEmbed.js +++ b/src/embeds/BaseEmbed.js @@ -12,7 +12,7 @@ class BaseEmbed { this.footer = { icon_url: 'https://avatars1.githubusercontent.com/u/24436369', - text: 'Data evaluated by warframe-worldstate-parser, Warframe Community Developers', + text: 'Data evaluated by warframe-worldstate-parser | Warframe Community Developers', }; } } diff --git a/src/embeds/CommandIdEmbed.js b/src/embeds/CommandIdEmbed.js new file mode 100644 index 000000000..7221c74a2 --- /dev/null +++ b/src/embeds/CommandIdEmbed.js @@ -0,0 +1,26 @@ +'use strict'; + +const BaseEmbed = require('./BaseEmbed.js'); + +/** + * Utility class for making rich embeds + */ +class CommandIdEmbed extends BaseEmbed { + /** + * @param {Genesis} bot - An instance of Genesis + * @param {Array} commandIds - a list of commands for ids to send + */ + constructor(bot, commandIds) { + super(); + this.url = 'https://discord.io/cephalon-sanctuary'; + + this.footer = { + icon_url: 'https://avatars1.githubusercontent.com/u/24436369', + text: 'Data provided by Warframe Community Developers', + }; + this.fields = commandIds.map(command => + ({ name: command.call, value: command.id, inline: false })); + } +} + +module.exports = CommandIdEmbed; diff --git a/src/embeds/EnableInfoEmbed.js b/src/embeds/EnableInfoEmbed.js new file mode 100644 index 000000000..aa9bd9253 --- /dev/null +++ b/src/embeds/EnableInfoEmbed.js @@ -0,0 +1,37 @@ +'use strict'; + +const BaseEmbed = require('./BaseEmbed.js'); + +/** + * Utility class for making rich embeds + */ +class EnableInfoEmbed extends BaseEmbed { + /** + * @param {Genesis} bot - An instance of Genesis + * @param {number} enable - 1 if enabling command, 0 if disabling + * @param {Array} params - list of params + */ + constructor(bot, enable, params) { + super(); + this.title = 'Settings to Change'; + this.type = 'rich'; + this.color = 0x0000ff; + this.fields = [ + { + name: 'Command Ids', + value: params[0].join('; '), + inline: true, + }, + ]; + if (params[1]) { + this.fields.push({ name: 'Channels', value: params[1].length > 0 ? params[1].join('; ') : 'No channels' }); + } + if (params[2]) { + this.fields.push({ name: 'User or Role', value: params[2] ? params[2] : 'No user or role' }); + } + this.fields.push({ name: 'Enable', value: enable === 1 ? 'Yes' : 'No' }); + this.footer.text = 'Data provided by Warframe Community Developers'; + } +} + +module.exports = EnableInfoEmbed; diff --git a/src/embeds/EnableUsageEmbed.js b/src/embeds/EnableUsageEmbed.js new file mode 100644 index 000000000..7ea324177 --- /dev/null +++ b/src/embeds/EnableUsageEmbed.js @@ -0,0 +1,43 @@ +'use strict'; + +const BaseEmbed = require('./BaseEmbed.js'); + +/** + * Utility class for making rich embeds + */ +class EnableUsageEmbed extends BaseEmbed { + /** + * @param {Genesis} bot - An instance of Genesis + * @param {Array} params - list of params + * @param {number} enable 1 if enable, 0 if disable + */ + constructor(bot, params, enable) { + super(); + this.title = 'Usage'; + this.type = 'rich'; + this.color = 0x0000ff; + this.description = `${bot.prefix}${enable === 1 ? 'enable' : 'disable'} in for `; + this.fields = [ + { + name: '', + value: 'The command or commands to disable.\nSee `/getcommandids` for more information.\nOther accepted replacements: `*` for enabling all.', + }, + { + name: '', + value: `Channel to disable a command for.\nOther accepted replacements: \`*\` for ${enable === 1 ? 'enabling' : 'disabling'} in all channels.`, + }, + { + name: '', + value: `Id of user or role to ${enable === 1 ? 'enable' : 'disable'} commands for. Will accept mentions in the future.\n` + + 'Other accepted replacements: `*` for enabling for all users.', + }, + ]; + + if (params) { + this.fields.push({ name: 'Provided parameters', value: params.join(' | ') }); + } + this.footer.text = 'Data provided by Warframe Community Developers'; + } +} + +module.exports = EnableUsageEmbed; diff --git a/src/embeds/EnemyEmbed.js b/src/embeds/EnemyEmbed.js index bfcc1edf4..8d165666d 100644 --- a/src/embeds/EnemyEmbed.js +++ b/src/embeds/EnemyEmbed.js @@ -22,16 +22,16 @@ class EnemyEmbed extends BaseEmbed { this.color = enemies.length > 2 ? 0x00ff00 : 0xff0000; this.fields = enemies.map(e => ({ name: e.agentType, - value: `Last discovered at ${e.lastDiscoveredAt}.\nIt has ${(100*Number(e.healthPercent)).toFixed(2)}% health remaining and is currently ${e.isDiscovered ? 'discovered' : 'not discovered'}`, + value: `Last discovered at ${e.lastDiscoveredAt}.\nIt has ${(100 * Number(e.healthPercent)).toFixed(2)}% health remaining and is currently ${e.isDiscovered ? 'discovered' : 'not discovered'}`, })); } else if (enemies.length === 1) { const e = enemies[0]; this.title = e.agentType; this.description = `Enemy ${e.discovered ? 'Discovered' : 'Hiding'}!`; this.color = 0xaf5b4b; - this.fields = [{ name: '_ _', value: `**${e.discovered? '' : 'Last '}Discovered At:** ${e.lastDiscoveredAt}` }, - { name: '_ _', value: `**Health Remaining:** ${(100*Number(e.healthPercent)).toFixed(2)}%` }, - { name: '_ _', value: `Will flee after ${e.fleeDamage} damage.\nGet after the Acolyte, Tenno!`}]; + this.fields = [{ name: '_ _', value: `**${e.discovered ? '' : 'Last '}Discovered At:** ${e.lastDiscoveredAt}` }, + { name: '_ _', value: `**Health Remaining:** ${(100 * Number(e.healthPercent)).toFixed(2)}%` }, + { name: '_ _', value: `Will flee after ${e.fleeDamage} damage.\nGet after the Acolyte, Tenno!` }]; } else { this.color = 0xaf5b4b; this.fields = [{ name: 'There are currently no enemies to combat', value: '_ _' }]; diff --git a/src/embeds/PriceCheckEmbed.js b/src/embeds/PriceCheckEmbed.js new file mode 100644 index 000000000..5a6913385 --- /dev/null +++ b/src/embeds/PriceCheckEmbed.js @@ -0,0 +1,48 @@ +'use strict'; + +const BaseEmbed = require('./BaseEmbed.js'); + +/** + * Generates enemy embeds + */ +class PriceCheckEmbed extends BaseEmbed { + /** + * @param {Genesis} bot - An instance of Genesis + * @param {Array.} result - array of string results or attachments + * @param {string} query - query that this is a result for + */ + constructor(bot, result, query) { + super(); + this.description = `Price query for ${query}`; + if (typeof result[0] === 'string') { + this.color = 0xff0000; + this.title = 'Warframe - Pricecheck'; + this.url = 'http://nexus-stats.com'; + this.thumbnail = { + url: 'https://cdn.discordapp.com/icons/195582152849620992/4c1fbd47b3e6c8d49b6d2362c79a537b.jpg', + }; + this.fields = [ + { + name: '_ _', + value: result[0], + inline: true, + }, + ]; + this.footer = { + icon_url: 'https://cdn.discordapp.com/icons/195582152849620992/4c1fbd47b3e6c8d49b6d2362c79a537b.jpg', + text: 'Pricechecks provided by Nexus Stats - https://nexus-stats.com', + }; + } else { + const attachment = result[0]; + this.color = parseInt(attachment.color, 16); + this.type = attachment.type; + this.title = attachment.title; + this.url = attachment.url; + this.fields = attachment.fields; + this.thumbnail = attachment.thumbnail; + this.footer = attachment.footer; + } + } +} + +module.exports = PriceCheckEmbed; diff --git a/src/embeds/SettingsEmbed.js b/src/embeds/SettingsEmbed.js new file mode 100644 index 000000000..27383bdb3 --- /dev/null +++ b/src/embeds/SettingsEmbed.js @@ -0,0 +1,32 @@ +'use strict'; + +const BaseEmbed = require('./BaseEmbed.js'); + +/** + * Generates settings embeds + */ +class SettingsEmbed extends BaseEmbed { + /** + * @param {Genesis} bot - An instance of Genesis + * @param {Channel} channel - The channel for which to send settings + * @param {Settings} settings - The settngs to to display + */ + constructor(bot, channel, settings) { + super(); + + this.color = 0x00ff00; + if (channel.type === 'text') { + this.title = `Settings for ${channel.name}`; + } else { + this.title = `Settings for DM with ${channel.recipient.username}`; + } + + this.fields = [{ name: '_ _', value: '' }]; + settings.forEach((setting) => { + this.fields[0].value += `\n**${setting.name}:** ${setting.value}`; + }); + this.footer.text = 'Settings data provided by Cephalon Genesis | Warframe Community Developers'; + } +} + +module.exports = SettingsEmbed; diff --git a/src/embeds/ShieldEmbed.js b/src/embeds/ShieldEmbed.js new file mode 100644 index 000000000..fbf1af308 --- /dev/null +++ b/src/embeds/ShieldEmbed.js @@ -0,0 +1,54 @@ +'use strict'; + +const BaseEmbed = require('./BaseEmbed.js'); + +function shieldCalc(baseShields, baseLevel, currentLevel) { + return (parseFloat(baseShields) + + (((parseFloat(currentLevel) - parseFloat(baseLevel)) ** 2) + * 0.0075 * parseFloat(baseShields))).toFixed(2); +} + +function shieldString(shields, level) { + return `At level ${parseFloat(level).toFixed(0)}, your enemy would have ${shields} Shields.`; +} + +/** + * Generates enemy embeds + */ +class ShieldEmbed extends BaseEmbed { + /** + * @param {Genesis} bot - An instance of Genesis + * @param {Array} params - array of string parameters + */ + constructor(bot, params) { + super(); + this.color = params && params.length > 3 ? 0x00ff00 : 0xff0000; + this.title = 'Warframe - Shields'; + this.url = 'https://warframe.com'; + this.thumbnail = { + url: 'http://i.imgur.com/BVUXIjA.png', + }; + this.fields = [ + { + name: '_ _', + value: '', + }, + ]; + + if (params && params.length > 3) { + const shields = params[1]; + const baseLevel = params[2]; + const currentLevel = params[3]; + this.logger.debug('Entered 3-param shield'); + const calc = shieldCalc(shields, baseLevel, currentLevel); + this.fields[0].name = 'Shield calculation'; + this.fields[0].value = shieldString(calc, currentLevel); + } else { + this.logger.debug('Entered 0-param shield'); + this.fields[0].value = `${this.bot.prefix}shields (Base Shelds) (Base Level) (Current Level) - calculate shields and stats.`; + this.fields[0].name = 'Possible uses include:'; + } + } +} + +module.exports = ShieldEmbed; diff --git a/src/resources/strings.json b/src/resources/strings.json index 8f03471e0..28304ee0e 100644 --- a/src/resources/strings.json +++ b/src/resources/strings.json @@ -1,6 +1,21 @@ { - "languages" : { - "english": { + "languages": { + "en-US": { + "damage_reply": "Operator $author, the damage flowchart, at your request.", + "override_enabled": "Operator, the override is now enabled.", + "override_disabled": "Operator, the override is now disabled.", + "override_toggle_error": "An error occurred toggling `override`.", + "command_not_blacklistable": "`$command` is not able to be blacklisted.", + "cannot_reply": "Cannot respond to command, `$command`.", + "command_added_blacklist": "`$command` added to the blacklist.", + "all_command_added_blacklist": "All commands added to the blacklist", + "command_removed_blacklist": "`$command` removed from the blacklist.", + "all_command_removed_blacklist": "All commands removed from the blacklist", + "response_enabled": "Operator, responding to settings changes is now enabled.", + "response_disabled": "Operator, responding to settings changes is now disabled.", + "response_toggle_error": "An error occurred toggling `response`.", + "language_set": "Lanuage set to `$language`.", + "language_not_set": "Language not set to `$language`. Provided language was either invalid or already set." } } } diff --git a/src/resources/trackables.json b/src/resources/trackables.json new file mode 100644 index 000000000..2099ab576 --- /dev/null +++ b/src/resources/trackables.json @@ -0,0 +1,205 @@ +{ + "rewardTypes" :[ + "vauban", + "skin", + "helmet", + "nitain", + "mutalist", + "weapon", + "clantech", + "aura", + "resource", + "nightmare", + "endo", + "potato", + "forma", + "exilus", + "other" + ], + "eventTypes" : [ + "alerts", + "invasions", + "news", + "sorties", + "fissures", + "baro", + "darvo", + "enemies", + "conclave.weeklies", + "conclave.dailies", + "syndicate.arbiters", + "syndicate.suda", + "syndicate.loka", + "syndicate.perrin", + "syndicate.veil", + "syndicate.meridian" + ], + "objs": [ + { + "name": "vauban", + "description": "Vauban parts", + "test": ["^vauban" , "i"], + "thumbnail": "https://raw.githubusercontent.com/Warframe-Community-Developers/warframe-worldstate-parser/master/resources/vauban_thumb.png", + "color": "0x5C5A53" + }, + { + "name": "skin", + "description": "Weapon skins", + "test": ["skin", "i"], + "thumbnail": "https://raw.githubusercontent.com/Warframe-Community-Developers/warframe-worldstate-parser/master/resources/weapon_skin_thumb.png", + "color": "0x4F4C33" + }, + { + "name": "helmet", + "description": "Alternative helmets", + "test": ["helmet", "i"], + "thumbnail": "https://raw.githubusercontent.com/Warframe-Community-Developers/warframe-worldstate-parser/master/resources/alt_helmet_thumb.png", + "color": "0x567677" + }, + { + "name": "nitain", + "description": "Nitain extract", + "test": ["nitain", "i"], + "thumbnail": "https://raw.githubusercontent.com/Warframe-Community-Developers/warframe-worldstate-parser/master/resources/nitain_thumb.png", + "color": "0xAEADA4" + }, + { + "name": "mutalistCoordinate", + "description": "Mutalist Alad V coordinates", + "test":["mutalist", "i"], + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/mutalist_thumb.png", + "color": "0x26B37" + }, + { + "name": "weapon", + "description": "Weapons", + "test": ["dagger|sword|glaive", "i"], + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/glaive_thumb.png", + "color": "0xA3A097" + }, + { + "name": "clantech", + "description": "Clantech resources", + "test": ["fieldron|detonite|mutagen", "i"], + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/clantech_thmb.png", + "color": "0x4D5556" + }, + { + "name": "aura", + "description": "Auras", + "test": "", + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/aura_thumb.png", + "color": "0xC8F8FF" + }, + { + "name": "resource", + "description": "Resources", + "test": "", + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/resource_thumb.png", + "color": "0xFFEE9C" + }, + { + "name": "nightmare", + "description": "Nightmare mods", + "test": "", + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/nightmare_thumb.png", + "color": "0xB22E2C" + }, + { + "name": "endo", + "description": "Endo", + "test": ["\\d+\\sendo", "i"], + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/endo_thumb.png", + "color": "0xC2A24C" + }, + { + "name": "potato", + "description": "Orokin Catalysts/Reactors", + "test": ["catalyst|reactor", "i"], + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/potato_thumb.png", + "color": "0x689ADD" + }, + { + "name": "forma", + "description": "Forma", + "test": ["forma", "i"], + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/forma_thumb.png", + "color": "0xF9E592" + }, + { + "name": "exilus", + "description": "Exilus", + "test": ["exilus","i"], + "thumbnail": "https://github.com/Warframe-Community-Developers/warframe-worldstate-parser/raw/master/resources/exilus_thumb.png", + "color": "0x722824" + }, + { + "name": "other", + "description": "Other", + "test": ".*", + "thumbnail": "", + "color": "0x4F545C" + } +], +"nightmare" : [ + "Accelerated Blast", + "Animal Instinct", + "Armored Agility", + "Blaze", + "Constitution", + "Focus Energy", + "Fortitude", + "Hammer Shot", + "Ice Storm", + "Lethal Torrent", + "Rending Strike", + "Stunning Speed", + "Wildfire", + "Seeking Fury", + "Shred", + "Vigor" +], +"auras" : [ + "Corrosive Projection", + "Dead Eye", + "EMP Aura", + "Enemy Radar", + "Energy Siphon", + "Infested Impedance", + "Loot Detector", + "Physique", + "Pistol Scavenger", + "Rejuvenation", + "Rifle Amp", + "Rifle Scavenger", + "Shield Disruption", + "Shotgun Scavenger", + "Sniper Scavenger", + "Speed Holster", + "Sprint Boost", + "Stand United", + "Steel Charge" +], +"resources" : [ + "Neural Sensors", + "Orokin Cell", + "Neurodes", + "Alloy Plate", + "Circuits", + "Control Module", + "Ferrite", + "Gallium", + "Morphics", + "Nano Spores", + "Oxium", + "Rubedo", + "Salvage", + "Plastids", + "Polymer Bundle", + "Argon Crystal", + "Cryotic", + "Oxium", + "Tellurium", + "Javlock Capacitor" +] +} diff --git a/src/settings/Database.js b/src/settings/Database.js index f7dbe3a67..20d38cfb5 100644 --- a/src/settings/Database.js +++ b/src/settings/Database.js @@ -32,14 +32,34 @@ class Database { Object.assign(opts, dbOptions); this.db = mysql.createPool(opts); this.bot = bot; + + this.defaults = { + prefix: '/', + respond_to_settings: true, + platform: 'pc', + language: 'en-us', + }; } /** * Creates the required tables in the database - * @returns {Promise} + * @returns {Array.} */ createSchema() { - return Promise.mapSeries(schema, q => this.db.query(q)); + const promises = Promise.mapSeries(schema, q => this.db.query(q)); + return promises; + } + + /** + * Initialize data for guilds in channels for existing guilds + * @param {Client} client for pulling guild information + */ + ensureData(client) { + const promises = []; + client.guilds.array().forEach((guild) => { + promises.push(this.addGuild(guild).then(this.bot.logger.debug)); + }); + promises.forEach(this.bot.logger.error); } /** @@ -64,7 +84,6 @@ class Database { */ deleteGuild(guild) { const query = SQL`DELETE FROM channels WHERE guild_id = ${guild.id};`; - return this.db.query(query); } @@ -105,8 +124,7 @@ class Database { * @returns {Promise} */ setChannelLanguage(channel, language) { - const query = SQL`UPDATE channels SET language = ${language} WHERE id = ${channel.id};`; - return this.db.query(query); + return this.setChannelSetting(channel, 'language', language); } /** @@ -116,8 +134,7 @@ class Database { * @returns {Promise} */ setChannelPlatform(channel, platform) { - const query = SQL`UPDATE channels SET platform = ${platform} WHERE id = ${channel.id};`; - return this.db.query(query); + return this.setChannelSetting(channel, 'platform', platform.toLowerCase()); } /** @@ -127,8 +144,46 @@ class Database { * @returns {Promise} */ setChannelResponseToSettings(channel, respond) { - const query = SQL`UPDATE channels SET respond_to_settings = ${respond} WHERE id = ${channel.id};`; - return this.db.query(query); + return this.setChannelSetting(channel, 'respond_to_settings', respond); + } + + /** + * Sets the custom prefix for this guild + * @param {Guild} guild The Discord guild for which to set the response setting + * @param {string} prefix The prefix for this guild + * @returns {Promise} + */ + setGuildPrefix(guild, prefix) { + return this.setGuildSetting(guild, 'prefix', prefix); + } + + /** + * Resets the custom prefix for this guild to the bot's globally configured prefix + * @param {Guild} guild The Discord guild for which to set the response setting + * @returns {Promise} + */ + resetGuildPrefix(guild) { + return this.setGuildSetting(guild, 'prefix', this.bot.prefix); + } + + /** + * Sets the custom prefix for this channel + * @param {Channel} channel The Discord channel for which to set the response setting + * @param {string} prefix The prefix for this channel + * @returns {Promise} + */ + setChannelPrefix(channel, prefix) { + return this.setChannelSetting(channel, 'prefix', prefix); + } + + /** + * Resets the custom prefix for this guild to the bot's globally configured prefix + * @param {Channel} channel The Discord guild for which to set the response setting + * @param {string} prefix The prefix for this channel + * @returns {Promise} + */ + resetChannelPrefix(channel) { + return this.setChannelSetting(channel, 'prefix', this.bot.prefix); } /** @@ -137,17 +192,7 @@ class Database { * @returns {Promise.} */ getChannelLanguage(channel) { - const query = SQL`SELECT language FROM channels WHERE id = ${channel.id};`; - return this.db.query(query) - .then((res) => { - if (res[0].length === 0) { - if (channel.type === 'text') { - return this.addGuildTextChannel(channel).then(() => 'en-US'); - } - return this.addDMChannel(channel).then(() => 'en-US'); - } - return res[0][0].language; - }); + return this.getChannelSetting(channel, 'language'); } /** @@ -156,17 +201,7 @@ class Database { * @returns {Promise.} */ getChannelPlatform(channel) { - const query = SQL`SELECT platform FROM channels WHERE id = ${channel.id};`; - return this.db.query(query) - .then((res) => { - if (res[0].length === 0) { - if (channel.type === 'text') { - return this.addGuildTextChannel(channel).then(() => 'pc'); - } - return this.addDMChannel(channel).then(() => 'pc'); - } - return res[0][0].platform; - }); + return this.getChannelSetting(channel, 'platform'); } /** @@ -174,15 +209,62 @@ class Database { * @param {Channel} channel The channel * @returns {Promise.} */ - getChannelRespondToSettings(channel) { - const query = SQL`SELECT platform FROM channels WHERE id = ${channel.id};`; + getChannelResponseToSettings(channel) { + return this.getChannelSetting(channel, 'respond_to_settings'); + } + + /** + * Returns the prefix setting for a guild + * @param {Channel} channel The guild + * @returns {Promis.} the previs setting for the guild + */ + getChannelPrefix(channel) { + return this.getChannelSetting(channel, 'prefix'); + } + + /** + * Get a setting for a particular channel + * @param {Channel} channel channel to get the setting for + * @param {string} setting name of the setting to get + * @returns {Promise} setting + */ + getChannelSetting(channel, setting) { + const query = SQL`SELECT val FROM settings WHERE channel_id=${channel.id} and setting=${setting};`; return this.db.query(query) - .then((res) => { - if (res.rows.length === 0) { - throw new Error(`The channel with ID ${channel.id} was not found in the database`); + .then((res) => { + if (res[0].length === 0) { + if (channel.type === 'text') { + return this.addGuildTextChannel(channel).then(() => this.defaults[`${setting}`]); } - return res.rows[0].respond_to_settings; - }); + return this.addDMChannel(channel).then(() => this.defaults[`${setting}`]); + } + return res[0][0].val; + }); + } + + /** + * Get a setting for a particular channel + * @param {Channel} channel channel to get the setting for + * @param {string} setting name of the setting to set + * @param {string|boolean} value value of the setting to be set + * @returns {Promise} setting + */ + setChannelSetting(channel, setting, value) { + const query = SQL`INSERT IGNORE INTO settings (channel_id, setting, val) VALUE (${channel.id},${setting},${value}) ON DUPLICATE KEY UPDATE val=${value};`; + return this.db.query(query); + } + + /** + * Resets the custom prefix for this guild to the bot's globally configured prefix + * @param {Guild} guild The Discord guild for which to set the response setting + * @param {string} setting Name of the setting to set + * @param {string|boolean} val value of the setting to be set + * @returns {Promise} + */ + setGuildSetting(guild, setting, val) { + const value = guild.channels.array().map(channel => `(${channel.id}, ${setting}, ${val})`).join(','); + const query = SQL`INSERT IGNORE INTO settings (channel_id, setting, val) VALUES ${value} ON DUPLICATE KEY UPDATE val=${val};`; + return this.db.query(query); } /** @@ -313,7 +395,7 @@ class Database { getTrackedItems(channel) { const query = SQL`SELECT item FROM item_notifications WHERE channel_id = ${channel.id};`; return this.db.query(query) - .then(res => res.map(r => r.item)); + .then(res => res[0].map(r => r.item)); } /** @@ -324,7 +406,7 @@ class Database { getTrackedEventTypes(channel) { const query = SQL`SELECT type FROM type_notifications WHERE channel_id = ${channel.id};`; return this.db.query(query) - .then(res => res.map(r => r.type)); + .then(res => res[0].map(r => r.type)); } /** @@ -431,11 +513,10 @@ class Database { AND is_user = false AND target_id = ${role.id}`; return this.db.query(query) .then((res) => { - if (res.rows.length === 0) { - throw new Error(`The channel permissions for the channel ${channel.id} - for role ${role.id} was not found in the database`); + if (res[0].length === 0) { + return true; } - return res.rows[0].allowed; + return res.rows[0].allowed === 1; }); } @@ -470,12 +551,10 @@ class Database { AND guild_permissions.target_id IN (${userRoleIds});`; return this.db.query(query) .then((res) => { - if (res.rows.length === 0) { - throw new Error(`The channel permissions for the channel ${channel.id} - for roles: ${userRoles.array().map(role => role.name).join(', ')} were not found in the database`); + if (res[0].length === 0) { + return true; } - - return res.rows[0].allowed; + return res[0][0].allowed; }); } diff --git a/src/settings/MessageManager.js b/src/settings/MessageManager.js new file mode 100644 index 000000000..8acea47be --- /dev/null +++ b/src/settings/MessageManager.js @@ -0,0 +1,188 @@ +'use strict'; + +/** + * MessageManager for + */ +class MessaageManager { + + /** + * Construct a message manager for sending and managing messages + * @param {Genesis} bot bot containing necessary settings + */ + constructor(bot) { + this.client = bot.client; + this.logger = bot.logger; + this.settings = bot.settings; + this.owner = bot.owner; + + /** + * Zero space whitespace character to prepend to any messages sent + * to prevent a command from inadvertantly being triggered. + * @type {string} + */ + this.zSWC = '\u200B'; + } + + /** + * Send a message, with options to delete messages after calling + * @param {Message} message original message being responded to + * @param {string} content String to send to a channel + * @param {boolean} deleteOriginal True to delete the original message + * @param {boolean} deleteResponse True to delete the sent message after time + */ + sendMessage(message, content, deleteOriginal, deleteResponse) { + const promises = []; + if ((message.channel.type === 'text' && + message.channel.permissionsFor(this.client.user.id).hasPermission('SEND_MESSAGES')) + || message.channel.type === 'dm') { + promises.push(message.channel.sendMessage(`${this.zSWC}${content}`).then((msg) => { + if (deleteOriginal && message.deletable) { + promises.push(message.delete(10000)); + } + if (deleteResponse && msg.deletable) { + promises.push(msg.delete(10000)); + } + })); + } + + promises.forEach(promise => promise.catch(this.logger.error)); + } + + /** + * Send a message, with options to delete messages after calling + * @param {Message} message original message being responded to + * @param {string} content String to send to a channel + * @param {boolean} deleteOriginal True to delete the original message + * @param {boolean} deleteResponse True to delete the sent message after time + * @returns {null|Promise} + */ + replyMessageRetPromise(message, content, deleteOriginal, deleteResponse) { + if ((message.channel.type === 'text' && + message.channel.permissionsFor(this.client.user.id).hasPermission('SEND_MESSAGES')) + || message.channel.type === 'dm') { + return message.channel.sendMessage(`${this.zSWC}${content}`).then((msg) => { + if (deleteOriginal && message.deletable) { + message.delete(10000).catch(this.logger.error); + } + if (deleteResponse && msg.deletable) { + msg.delete(10000).catch(this.logger.error); + } + }); + } + return null; + } + + /** + * Send a message, with options to delete messages after calling + * @param {Message} message original message being responded to + * @param {string} content String to send to a channel + * @param {boolean} deleteOriginal True to delete the original message + * @param {boolean} deleteResponse True to delete the sent message after time + */ + reply(message, content, deleteOriginal, deleteResponse) { + const promises = []; + if ((message.channel.type === 'text' && + message.channel.permissionsFor(this.client.user.id).hasPermission('SEND_MESSAGES')) + || message.channel.type === 'dm') { + promises.push(message.reply(`${this.zSWC}${content}`).then((msg) => { + if (deleteOriginal && message.deletable) { + promises.push(message.delete(10000)); + } + if (deleteResponse && msg.deletable) { + promises.push(msg.delete(10000)); + } + })); + } + + promises.forEach(promise => promise.catch(this.logger.error)); + } + + /** + * Send a message, with options to delete messages after calling + * @param {Message} message original message being responded to + * @param {Object} embed Embed object to send + * @param {boolean} deleteOriginal True to delete the original message + * @param {boolean} deleteResponse True to delete the sent message after time + */ + embed(message, embed, deleteOriginal, deleteResponse) { + const promises = []; + if ((message.channel.type === 'text' && + message.channel.permissionsFor(this.client.user.id).hasPermissions(['SEND_MESSAGES', 'EMBED_LINKS'])) + || message.channel.type === 'dm') { + promises.push(message.channel.sendEmbed(embed).then((msg) => { + if (deleteOriginal && message && message.deletable) { + promises.push(message.delete(10000)); + } + if (deleteResponse && msg && msg.deletable) { + promises.push(msg.delete(10000)); + } + })); + } + promises.forEach(promise => promise.catch(this.logger.error)); + } + + /** + * Send a message, with options to delete messages after calling + * @param {Message} message original message being responded to + * @param {string} content String to send to a channel + * @param {boolean} deleteResponse True to delete the sent message after time + */ + sendDirectMessageToAuthor(message, content, deleteResponse) { + const promises = []; + promises.push(message.author.sendMessage(content).then((msg) => { + if (deleteResponse && msg.deletable) { + promises.push(msg.delete(10000)); + } + })); + + promises.forEach(promise => promise.catch(this.logger.error)); + } + + /** + * Send a message, with options to delete messages after calling + * @param {Message} message original message being responded to + * @param {Object} embed Embed object to send + * @param {boolean} deleteResponse True to delete the sent message after time + */ + sendDirectEmbedToAuthor(message, embed, deleteResponse) { + const promises = []; + promises.push(message.author.sendEmbed(embed).then((msg) => { + if (deleteResponse && msg && msg.deletable) { + promises.push(msg.delete(10000)); + } + })); + promises.forEach(promise => promise.catch(this.logger.error)); + } + + sendDirectEmbedToOwner(embed) { + this.client.get(this.owner).sendEmbed(embed).catch(this.logger.error); + } + + /** + * Notify channel of settings change if enabled + * @param {Message} message Message to reply to and fetch channel settings from + * @param {boolean} deleteOriginal whether or not to delete the original message + * @param {boolean} deleteResponse whether or not to delete the response message + */ + notifySettingsChange(message, deleteOriginal, deleteResponse) { + const promises = []; + message.react('\u2705'); + this.settings.getChannelResponseToSettings(message.channel) + .then((respondToSettings) => { + if (respondToSettings) { + promises.push(message.reply('Settings updated') + .then((msg) => { + if (deleteResponse && msg.deletable) { + promises.push(msg.delete(5000)); + } + })); + } + if (deleteOriginal && message.deletable) { + promises.push(message.delete(5000)); + } + }) + .catch(this.logger.error); + } +} + +module.exports = MessaageManager; diff --git a/src/settings/StringManager.js b/src/settings/StringManager.js new file mode 100644 index 000000000..19bca53ce --- /dev/null +++ b/src/settings/StringManager.js @@ -0,0 +1,54 @@ +'use strict'; + +const strings = require('../resources/strings.json'); + +class StringManager { + /** + * Construct a string manager for internationalizing strings + * String template: + * * `$author` - Replaced by the message author + * * `$message` - Replaced by the message content + * * `$channel` - Replaced by the message channel name + * * `$ch_mntn` - Replaced by the message channel mention + * + * @param {Settings} settings Settings for this string manager + * to fetch the language for a channel with + */ + constructor(settings) { + this.settings = settings; + } + + /** + * Get the localized string for a particular stringId + * @param {string} stringId String id of the internationalized string to fetch + * @param {Message} message Message to derive template replacement data from + * as well as for fetching settings + * @returns {Promise} String promise with the corresponding string + */ + getString(stringId, message, { command = '' } = {}) { + return new Promise((resolve, reject) => { + this.settings.getChannelLanguage(message.channel.id) + .then((language) => { + const lang = language !== null ? language : 'english'; + let resStr = strings.languages[`${lang}`][`${stringId}`]; + if (typeof resStr !== 'undefined') { + if (message !== null) { + resStr = resStr.replace(/\$author/i, message.author.toString()) + .replace(/\$message/i, message.cleanContent) + .replace(/\$channel/i, message.channel.name) + .replace(/\$ch_mntn/i, message.channel.toString()); + } + if (command !== '') { + resStr = resStr.replace(/\$command/i, command); + } + resolve(resStr); + } else { + reject(`Couldn't find string ${stringId}`); + } + }) + .catch(err => reject(err)); + }); + } +} + +module.exports = StringManager; diff --git a/src/settings/schema.js b/src/settings/schema.js index e494690cc..fc0a2e38d 100644 --- a/src/settings/schema.js +++ b/src/settings/schema.js @@ -7,7 +7,8 @@ module.exports = [ language VARCHAR(5) NOT NULL DEFAULT 'en-US', platform VARCHAR(3) NOT NULL DEFAULT 'pc', webhook TEXT, - respond_to_settings BOOLEAN NOT NULL DEFAULT TRUE + respond_to_settings BOOLEAN NOT NULL DEFAULT TRUE, + prefix VARCHAR(3) NOT NULL DEFAULT '/' );`, `CREATE TABLE IF NOT EXISTS type_notifications ( channel_id BIGINT UNSIGNED NOT NULL, @@ -46,4 +47,11 @@ module.exports = [ text TEXT NOT NULL, PRIMARY KEY (guild_id, item_or_type) );`, + `CREATE TABLE IF NOT EXISTS settings ( + channel_id BIGINT UNSIGNED NOT NULL, + setting VARCHAR(20) NOT NULL, + value VARCHAR(255) NOT NULL, + PRIMARY KEY (channel_id, setting), + FOREIGN KEY (channel_id) REFERENCES channels(id) + );`, ]; From 0250c50f7ac8be452c95cc775d00794716e36c79 Mon Sep 17 00:00:00 2001 From: Matej Voboril Date: Sat, 25 Feb 2017 23:56:26 -0600 Subject: [PATCH 2/7] Add invite command, new settings, message manager consumption --- pm2.json | 3 +- src/commands/Core/Invite.js | 27 ++++++++++ src/commands/Ondemand/Wiki.js | 22 ++------ src/commands/Owner/Avatar.js | 2 +- src/commands/Owner/LeaveServer.js | 2 +- src/commands/Settings/Disable.js | 11 +--- src/commands/Settings/DisablePingEvent.js | 23 ++------- src/commands/Settings/DisablePingItem.js | 21 ++------ src/commands/Settings/Enable.js | 4 +- src/commands/Settings/EnablePingEvent.js | 21 ++------ src/commands/Settings/EnablePingItem.js | 21 ++------ src/commands/Settings/GetCommandIds.js | 16 +----- src/commands/Settings/Language.js | 13 +---- src/commands/Settings/Platform.js | 6 +-- src/commands/Settings/Prefix.js | 60 ++++++++-------------- src/commands/Settings/RespondToSettings.js | 11 ++-- src/commands/Settings/Settings.js | 12 +---- src/commands/Settings/TrackEvent.js | 22 ++------ src/commands/Settings/TrackItem.js | 22 ++------ src/commands/Settings/UntrackEvent.js | 18 +------ src/commands/Settings/UntrackItem.js | 18 +------ src/embeds/WikiEmbed.js | 28 ++++++++++ src/settings/Database.js | 30 +++++++---- src/settings/MessageManager.js | 2 +- 24 files changed, 143 insertions(+), 272 deletions(-) create mode 100644 src/commands/Core/Invite.js create mode 100644 src/embeds/WikiEmbed.js diff --git a/pm2.json b/pm2.json index 70133c2b4..178eb7671 100644 --- a/pm2.json +++ b/pm2.json @@ -36,7 +36,8 @@ "MYSQL_PASSWORD":"password", "MYSQL_DB":"genesis", "LOG_LEVEL": "ERROR", - "WORLDSTATE_TIMEOUT": 60000 + "WORLDSTATE_TIMEOUT": 60000, + "INVITE_URL" : "https://github.com/Warframe-Community-Developers/genesis" } } ] diff --git a/src/commands/Core/Invite.js b/src/commands/Core/Invite.js new file mode 100644 index 000000000..0fe251fff --- /dev/null +++ b/src/commands/Core/Invite.js @@ -0,0 +1,27 @@ +'use strict'; + +const Command = require('../../Command.js'); + +/** + * Displays the response time for the bot and checks Warframe's servers to see if they are up + */ +class Invite extends Command { + /** + * Constructs a callable command + * @param {Genesis} bot The bot object + */ + constructor(bot) { + super(bot, 'core.invite', 'invite', 'Ping Genesis to test connectivity'); + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + this.messageManager.reply(message, process.env.INVITE_URL || 'No Invite Set', true, false); + } +} + +module.exports = Invite; diff --git a/src/commands/Ondemand/Wiki.js b/src/commands/Ondemand/Wiki.js index 9d25a0ee3..880cc5ec5 100644 --- a/src/commands/Ondemand/Wiki.js +++ b/src/commands/Ondemand/Wiki.js @@ -1,6 +1,7 @@ 'use strict'; const Command = require('../../Command.js'); +const WikiEmbed = require('../../embeds/WikiEmbed.js'); const Wikia = require('node-wikia'); const warframe = new Wikia('warframe'); @@ -22,6 +23,7 @@ class Wiki extends Command { parameters: ['topic'], }, ]; + this.noResult = `${this.md.codeMulti}No result for search, Operator. Attempt another search query.${this.md.blockEnd}`; } /** @@ -32,34 +34,20 @@ class Wiki extends Command { run(message) { const query = message.strippedContent.match(this.regex)[1]; if (!query) { - message.reply(`${this.md.codeMulti}Please specify a search term${this.md.blockEnd}`); + this.MessageManager.reply(message, this.noResult, true, true); } else { this.logger.debug(`Searched for query: ${query}`); - warframe.getSearchList({ query, limit: 1, }).then(articles => warframe.getArticleDetails({ ids: articles.items.map(i => i.id), })).then((details) => { - const item = Object.values(details.items)[0]; - return message.channel.sendEmbed({ - title: item.title, - type: 'rich', - url: details.basepath + item.url, - image: { - url: item.thumbnail.replace(/\/revision\/.*/, ''), - width: item.original_dimensions.width, - height: item.original_dimensions.height, - }, - description: item.abstract, - }); + this.messageManager.embed(message, new WikiEmbed(this.bot, details), true, false); }) .catch((err) => { if (err.exception && err.exception.code === 404) { - message.reply(`${this.md.codeMulti}No result for search, Operator. Attempt another search query.${this.md.blockEnd}`) - .then(msg => msg.delete(100000)) - .catch(this.logger.error); + this.MessageManager.reply(message, this.noResult, true, true); } else { this.logger.error(err); } diff --git a/src/commands/Owner/Avatar.js b/src/commands/Owner/Avatar.js index 612308af2..11ae1cdbc 100644 --- a/src/commands/Owner/Avatar.js +++ b/src/commands/Owner/Avatar.js @@ -30,7 +30,7 @@ class Avatar extends Command { run(message) { const url = message.strippedContent.match(this.regex)[1]; this.bot.client.user.setAvatar(url) - .then(() => message.reply('New avatar set!')) + .then(() => this.messageManager.reply(message, 'New avatar set!', true, true)) .catch(this.logger.error); } } diff --git a/src/commands/Owner/LeaveServer.js b/src/commands/Owner/LeaveServer.js index 450cb0c2a..ae09c1831 100644 --- a/src/commands/Owner/LeaveServer.js +++ b/src/commands/Owner/LeaveServer.js @@ -31,7 +31,7 @@ class LeaveServer extends Command { const serverid = message.strippedContent.match(this.regex)[1]; if (this.bot.client.guilds.has(serverid)) { this.bot.client.guilds.get(serverid).leave() - .then(guild => message.reply(`Left ${guild.name}`)) + .then(guild => this.messageManager.reply(message, `Left ${guild.name}`, true, true)) .catch(this.logger.error); } else { message.reply('No such guild cached'); diff --git a/src/commands/Settings/Disable.js b/src/commands/Settings/Disable.js index 5f66c4235..02f8a28f9 100644 --- a/src/commands/Settings/Disable.js +++ b/src/commands/Settings/Disable.js @@ -45,7 +45,7 @@ class Disable extends Command { this.bot.settings.getChannelResponseToSettings(message.channel) .then((respondToSettings) => { if (respondToSettings) { - promises.push(message.channel.sendEmbed(infoEmbed)); + this.messageManager.sendEmbed(message, infoEmbed, true, false); } }); commands.forEach((command) => { @@ -60,16 +60,9 @@ class Disable extends Command { }); }); promises.forEach((promise) => { - promise.then((msg) => { - if (msg.deletable) { - msg.delete(50000).catch(this.logger.error); - } - }).catch(this.logger.error); + promise.catch(this.logger.error); }); } - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } } /** diff --git a/src/commands/Settings/DisablePingEvent.js b/src/commands/Settings/DisablePingEvent.js index 8f2700333..8e6eebdce 100644 --- a/src/commands/Settings/DisablePingEvent.js +++ b/src/commands/Settings/DisablePingEvent.js @@ -45,29 +45,13 @@ class EnablePingEvent extends Command { const promises = []; itemsToPing.forEach(item => promises.push(this.bot.settings .setEventTypePing(message.channel, item, false))); - promises.forEach(promise => promise.catch(this.logger.error)); - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }).catch(this.logger.error); - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } + this.messageManager.notifySettingsChange(message, true, true); } sendInstructionEmbed(message) { this.bot.settings.getChannelPrefix(message.channel) - .then(prefix => message.channel.sendEmbed({ + .then(prefix => this.messageManager.embed(message, { title: 'Usage', type: 'rich', color: 0x0000ff, @@ -81,8 +65,7 @@ class EnablePingEvent extends Command { value: `\n${eventTypes.join('\n')}`, }, ], - })) - .catch(this.logger.error); + }, true, false)); } } diff --git a/src/commands/Settings/DisablePingItem.js b/src/commands/Settings/DisablePingItem.js index 2d93ec6bb..24c2d4a83 100644 --- a/src/commands/Settings/DisablePingItem.js +++ b/src/commands/Settings/DisablePingItem.js @@ -47,27 +47,12 @@ class DisablePingEvent extends Command { .setItemPing(message.channel, item, false))); promises.forEach(promise => promise.catch(this.logger.error)); - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }).catch(this.logger.error); - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } + this.messageManager.notifySettingsChange(message, true, false); } sendInstructionEmbed(message) { this.bot.settings.getChannelPrefix(message.channel) - .then(prefix => message.channel.sendEmbed({ + .then(prefix => this.messageManager.embed(message, { title: 'Usage', type: 'rich', color: 0x0000ff, @@ -81,7 +66,7 @@ class DisablePingEvent extends Command { value: `\n${rewardTypes.join('\n')}`, }, ], - })) + }, true, false)) .catch(this.logger.error); } } diff --git a/src/commands/Settings/Enable.js b/src/commands/Settings/Enable.js index 65c0658d5..0f5290f7a 100644 --- a/src/commands/Settings/Enable.js +++ b/src/commands/Settings/Enable.js @@ -19,7 +19,7 @@ class Enable extends Command { run(message) { const params = message.strippedContent.match(this.regex); if (!params[1]) { - message.channel.sendEmbed(new EnableUsageEmbed(this.bot)); + this.messageManager.embed(message, new EnableUsageEmbed(this.bot), true, false); } else { params.splice(0, 1); const commands = this.getCommandsToEnable(params[0]); @@ -44,7 +44,7 @@ class Enable extends Command { this.bot.settings.getChannelResponseToSettings(message.channel) .then((respondToSettings) => { if (respondToSettings) { - promises.push(message.channel.sendEmbed(infoEmbed)); + this.messageManager.embed(message, infoEmbed, true, false); } }); commands.forEach((command) => { diff --git a/src/commands/Settings/EnablePingEvent.js b/src/commands/Settings/EnablePingEvent.js index 46d095123..daacb43ff 100644 --- a/src/commands/Settings/EnablePingEvent.js +++ b/src/commands/Settings/EnablePingEvent.js @@ -47,27 +47,12 @@ class EnablePingEvent extends Command { .setEventTypePing(message.channel, item, true))); promises.forEach(promise => promise.catch(this.logger.error)); - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }).catch(this.logger.error); - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } + this.messageManager.notifySettingsChange(message, true, true); } sendInstructionEmbed(message) { this.bot.settings.getChannelPrefix(message.channel) - .then(prefix => message.channel.sendEmbed({ + .then(prefix => this.messageManager.embed(message, { title: 'Usage', type: 'rich', color: 0x0000ff, @@ -81,7 +66,7 @@ class EnablePingEvent extends Command { value: `\n${eventTypes.join('\n')}`, }, ], - })) + }, true, false)) .catch(this.logger.error); } } diff --git a/src/commands/Settings/EnablePingItem.js b/src/commands/Settings/EnablePingItem.js index c978535ca..b8d0680ce 100644 --- a/src/commands/Settings/EnablePingItem.js +++ b/src/commands/Settings/EnablePingItem.js @@ -47,27 +47,12 @@ class EnablePingItem extends Command { .setItemPing(message.channel, item, true))); promises.forEach(promise => promise.catch(this.logger.error)); - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }).catch(this.logger.error); - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } + this.messageManager.notifySettingsChange(message, true, true); } sendInstructionEmbed(message) { this.bot.settings.getChannelPrefix(message.channel) - .then(prefix => message.channel.sendEmbed({ + .then(prefix => this.messageManager.embed(message, { title: 'Usage', type: 'rich', color: 0x0000ff, @@ -81,7 +66,7 @@ class EnablePingItem extends Command { value: `\n${rewardTypes.join('\n')}`, }, ], - })) + }, true, false)) .catch(this.logger.error); } } diff --git a/src/commands/Settings/GetCommandIds.js b/src/commands/Settings/GetCommandIds.js index 6f157d686..8ce657349 100644 --- a/src/commands/Settings/GetCommandIds.js +++ b/src/commands/Settings/GetCommandIds.js @@ -25,21 +25,9 @@ class GetCommandIds extends Command { !command.ownerOnly || (message.author.id === this.bot.owner && command.ownerOnly)); const embed = new CommandIdEmbed(this.bot, commands); if (message.channel.type !== 'dm') { - message.reply('Check your direct messages for more information.') - .then((reply) => { - if (reply.deletable) { - reply.delete(10000); - } - }).catch(this.logger.error); + this.messageManager.reply(message, 'Check your direct messages for more information.', true, true); } - const promises = [ - message.author.sendEmbed(embed).then(() => { - if (message.deletable) { - message.delete(2000); - } - }), - ]; - Promise.all(promises).catch(this.logger.error); + this.messageManager.sendDirectEmbedToAuthor(message, embed, false); } } diff --git a/src/commands/Settings/Language.js b/src/commands/Settings/Language.js index 2c2995ce7..93b76abfe 100644 --- a/src/commands/Settings/Language.js +++ b/src/commands/Settings/Language.js @@ -27,20 +27,9 @@ class Language extends Command { }); } else { this.bot.settings.setChannelLanguage(message.channel, language.toLowerCase()).then(() => { - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated'); - } - return retPromise; - }); + this.messageManager.notifySettingsChange(message, true, true); }).catch(this.logger.error); } - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } } } diff --git a/src/commands/Settings/Platform.js b/src/commands/Settings/Platform.js index 82ee1e404..94f3e33e8 100644 --- a/src/commands/Settings/Platform.js +++ b/src/commands/Settings/Platform.js @@ -26,9 +26,9 @@ class Platform extends Command { ], }); } else { - this.bot.settings.setChannelPlatform(message.channel, platform.toLowerCase()).then(() => { - this.messageManager.notifySettingsChange(message, true, true); - }).catch(this.logger.error); + this.bot.settings.setChannelPlatform(message.channel, platform.toLowerCase()) + .then(() => this.messageManager.notifySettingsChange(message, true, true)) + .catch(this.logger.error); } if (message.deletable) { message.delete(5000).catch(this.logger.error); diff --git a/src/commands/Settings/Prefix.js b/src/commands/Settings/Prefix.js index 621b85f72..9e1a253c2 100644 --- a/src/commands/Settings/Prefix.js +++ b/src/commands/Settings/Prefix.js @@ -24,60 +24,42 @@ class Prefix extends Command { run(message) { const prefix = message.strippedContent.match(this.regex)[1]; if (!prefix) { - message.channel.sendEmbed({ - title: 'Usage', - type: 'rich', - color: 0x0000ff, - fields: [ - { - name: `${this.bot.prefix}${this.call} `, - value: 'Set the channel\'s custom prefix', - }, - ], + this.settings.getChannelPrefix(message.channel) + .then((configuredPrefix) => { + this.messageManager.embed(message, { + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${configuredPrefix}${this.call} `, + value: 'Set the channel\'s custom prefix', + }, + ], + }, true, false); }); } else if (prefix === 'reset') { let promise = null; if (message.channel.type === 'text') { - promise = this.bot.settings.resetGuildPrefix(message.channel.guild); + this.bot.settings.resetGuildPrefix(message.channel.guild); } else { promise = this.bot.settings.resetChannelPrefix(message.channel); } promise.then(() => { - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated'); - } - return retPromise; - }); + this.messageManager.notifySettingsChange(message, true, true); }).catch(this.logger.error); } else { let promise = null; if (message.channel.type === 'text') { - promise = this.bot.settings.setGuildPrefix(message.channel.guild, prefix); + this.bot.settings.setGuildPrefix(message.channel.guild, prefix); } else { promise = this.bot.settings.setChannelPrefix(message.channel, prefix); } - promise.then(() => { - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }); - }).catch(this.logger.error); - } - if (message.deletable) { - message.delete(5000).catch(this.logger.error); + if (promise) { + promise.then(() => { + this.messageManager.notifySettingsChange(message, true, true); + }).catch(this.logger.error); + } } } } diff --git a/src/commands/Settings/RespondToSettings.js b/src/commands/Settings/RespondToSettings.js index 2f81a5968..46a9acc85 100644 --- a/src/commands/Settings/RespondToSettings.js +++ b/src/commands/Settings/RespondToSettings.js @@ -8,11 +8,11 @@ class RespondToSettings extends Command { this.usages = [ { description: 'Change if this channel has settings changes resonded in it', parameters: ['response enabled'] }, ]; - this.regex = new RegExp('^respond?\\s?settings\\s?(.+)?$', 'i'); + this.regex = new RegExp('^respond(?:\\sto)?\\s?settings\\s?(.+)?$', 'i'); } run(message) { - const enable = message.strippedContent.match(this.regex)[1]; + let enable = message.strippedContent.match(this.regex)[1]; if (!enable) { const embed = { title: 'Usage', @@ -27,13 +27,14 @@ class RespondToSettings extends Command { }; this.messageManager.embed(message, embed, true, true); } else { + enable = enable.trim(); let enableResponse = false; - if (enable === 'enable' || enable === 'enable' || enable === '1' || enable === 'true') { + if (enable === 'enable' || enable === 'enable' || enable === '1' || enable === 'true' || enable === 1) { enableResponse = true; } this.bot.settings.setChannelResponseToSettings(message.channel, enableResponse) - .then(() => this.messageManager.notifySettingsChange(message, true, true)) - .catch(this.logger.error); + .then(() => this.messageManager.notifySettingsChange(message, true, true)) + .catch(this.logger.error); } } } diff --git a/src/commands/Settings/Settings.js b/src/commands/Settings/Settings.js index fee88b72b..289e4410f 100644 --- a/src/commands/Settings/Settings.js +++ b/src/commands/Settings/Settings.js @@ -21,7 +21,7 @@ class Settings extends Command { return this.bot.settings.getChannelResponseToSettings(message.channel); }) .then((respond) => { - settings.push({ name: 'Respond to Settings', value: respond ? 'yes' : 'no' }); + settings.push({ name: 'Respond to Settings', value: respond === '1' ? 'yes' : 'no' }); return this.bot.settings.getChannelPrefix(message.channel); }) .then((prefix) => { @@ -43,17 +43,9 @@ class Settings extends Command { inline: true, }); const embed = new SettingsEmbed(this.bot, message.channel, settings); - message.channel.sendEmbed(embed).then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); + this.messageManager.embed(message, embed, true, true); }) .catch(this.logger.error); - - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } } } diff --git a/src/commands/Settings/TrackEvent.js b/src/commands/Settings/TrackEvent.js index 24eeb1d3d..c9ab4802e 100644 --- a/src/commands/Settings/TrackEvent.js +++ b/src/commands/Settings/TrackEvent.js @@ -47,27 +47,12 @@ class TrackEvent extends Command { .trackEventType(message.channel, item))); promises.forEach(promise => promise.catch(this.logger.error)); - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }).catch(this.logger.error); - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } + this.messageManager.notifySettingsChange(message, true, true); } sendInstructionEmbed(message) { this.bot.settings.getChannelPrefix(message.channel) - .then(prefix => message.channel.sendEmbed({ + .then(prefix => this.messageManager.embed(message, { title: 'Usage', type: 'rich', color: 0x0000ff, @@ -81,8 +66,7 @@ class TrackEvent extends Command { value: `\n${eventTypes.join('\n')}`, }, ], - })) - .catch(this.logger.error); + }, true, false)); } } diff --git a/src/commands/Settings/TrackItem.js b/src/commands/Settings/TrackItem.js index 2c141c361..7e11899b2 100644 --- a/src/commands/Settings/TrackItem.js +++ b/src/commands/Settings/TrackItem.js @@ -49,29 +49,13 @@ class TrackItem extends Command { const promises = []; itemsToTrack.forEach(item => promises.push(this.bot.settings .trackItem(message.channel, item))); - promises.forEach(promise => promise.catch(this.logger.error)); - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }).catch(this.logger.error); - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } + this.messageManager.notifySettingsChange(message, true, true); } sendInstructionEmbed(message) { this.bot.settings.getChannelPrefix(message.channel) - .then(prefix => message.channel.sendEmbed({ + .then(prefix => this.messageManager.embed(message, { title: 'Usage', type: 'rich', color: 0x0000ff, @@ -85,7 +69,7 @@ class TrackItem extends Command { value: `\n${rewardTypes.join('\n')}`, }, ], - })) + }, true, false)) .catch(this.logger.error); } } diff --git a/src/commands/Settings/UntrackEvent.js b/src/commands/Settings/UntrackEvent.js index 8d43d795d..045a95574 100644 --- a/src/commands/Settings/UntrackEvent.js +++ b/src/commands/Settings/UntrackEvent.js @@ -49,24 +49,8 @@ class UntrackItem extends Command { const promises = []; itemsToTrack.forEach(item => promises.push(this.bot.settings .untrackEventType(message.channel, item))); - promises.forEach(promise => promise.catch(this.logger.error)); - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }).catch(this.logger.error); - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } + this.messageManager.notifySettingsChange(message, true, true); } sendInstructionEmbed(message) { diff --git a/src/commands/Settings/UntrackItem.js b/src/commands/Settings/UntrackItem.js index 27ac682d8..34e67215f 100644 --- a/src/commands/Settings/UntrackItem.js +++ b/src/commands/Settings/UntrackItem.js @@ -48,24 +48,8 @@ class Prefix extends Command { const promises = []; itemsToTrack.forEach(item => promises.push(this.bot.settings .untrackItem(message.channel, item))); - promises.forEach(promise => promise.catch(this.logger.error)); - message.react('\u2705'); - this.bot.settings.getChannelResponseToSettings(message.channel) - .then((respondToSettings) => { - let retPromise = null; - if (respondToSettings) { - retPromise = message.reply('Settings updated').then((settingsMsg) => { - if (settingsMsg.deletable) { - settingsMsg.delete(50000).catch(this.logger.error); - } - }); - } - return retPromise; - }).catch(this.logger.error); - if (message.deletable) { - message.delete(5000).catch(this.logger.error); - } + this.messageManager.notifySettingsChange(message, true, true); } sendInstructionEmbed(message) { diff --git a/src/embeds/WikiEmbed.js b/src/embeds/WikiEmbed.js new file mode 100644 index 000000000..cec122f40 --- /dev/null +++ b/src/embeds/WikiEmbed.js @@ -0,0 +1,28 @@ +'use strict'; + +const BaseEmbed = require('./BaseEmbed.js'); + +/** + * Generates enemy embeds + */ +class WikiEmbed extends BaseEmbed { + /** + * @param {Genesis} bot - An instance of Genesis + * @param {Array.} details details to derive data from + */ + constructor(bot, details) { + super(); + const item = Object.values(details.items)[0]; + this.title = item.title; + this.type = 'rich'; + this.url = details.basepath + item.url; + this.image = { + url: item.thumbnail.replace(/\/revision\/.*/, ''), + width: item.original_dimensions.width, + height: item.original_dimensions.height, + }; + this.description = item.abstract; + } +} + +module.exports = WikiEmbed; diff --git a/src/settings/Database.js b/src/settings/Database.js index 20d38cfb5..e7aeb4bf1 100644 --- a/src/settings/Database.js +++ b/src/settings/Database.js @@ -43,11 +43,10 @@ class Database { /** * Creates the required tables in the database - * @returns {Array.} + * @returns {Promise} */ createSchema() { - const promises = Promise.mapSeries(schema, q => this.db.query(q)); - return promises; + return Promise.mapSeries(schema, q => this.db.query(q)); } /** @@ -57,9 +56,16 @@ class Database { ensureData(client) { const promises = []; client.guilds.array().forEach((guild) => { - promises.push(this.addGuild(guild).then(this.bot.logger.debug)); + promises.push(this.addGuild(guild)); }); - promises.forEach(this.bot.logger.error); + Promise.all(promises.map(x => x.reflect())) + .then((results) => { + results.forEach((result) => { + if (!result.isFulfilled()) { + this.bot.logger.error(result.reason()); + } + }); + }); } /** @@ -201,7 +207,7 @@ class Database { * @returns {Promise.} */ getChannelPlatform(channel) { - return this.getChannelSetting(channel, 'platform'); + return this.getChannelSetting(channel, 'platform').then(prefix => unescape(prefix)); } /** @@ -262,9 +268,11 @@ class Database { * @returns {Promise} */ setGuildSetting(guild, setting, val) { - const value = guild.channels.array().map(channel => `(${channel.id}, ${setting}, ${val})`).join(','); - const query = SQL`INSERT IGNORE INTO settings (channel_id, setting, val) VALUES ${value} ON DUPLICATE KEY UPDATE val=${val};`; - return this.db.query(query); + const promises = []; + guild.channels.array().forEach((channel) => { + promises.push(this.setChannelSetting(channel, setting, val)); + }); + return null; } /** @@ -274,7 +282,7 @@ class Database { * @returns {Promise} */ trackItem(channel, item) { - const query = SQL`INSERT IGNORE INTO item_notifications (channel_id, item) VALUES (${channel.id}, ${item});`; + const query = SQL`INSERT IGNORE INTO item_notifications (channel_id, item) VALUES (${channel.id},${item});`; return this.db.query(query); } @@ -296,7 +304,7 @@ class Database { * @returns {Promise} */ trackEventType(channel, type) { - const query = SQL`INSERT IGNORE INTO type_notifications (channel_id, type) VALUES (${channel.id}, ${type});`; + const query = SQL`INSERT IGNORE INTO type_notifications (channel_id, type) VALUES (${channel.id},${type});`; return this.db.query(query); } diff --git a/src/settings/MessageManager.js b/src/settings/MessageManager.js index 8acea47be..b6666a176 100644 --- a/src/settings/MessageManager.js +++ b/src/settings/MessageManager.js @@ -169,7 +169,7 @@ class MessaageManager { message.react('\u2705'); this.settings.getChannelResponseToSettings(message.channel) .then((respondToSettings) => { - if (respondToSettings) { + if (respondToSettings === '1') { promises.push(message.reply('Settings updated') .then((msg) => { if (deleteResponse && msg.deletable) { From f18ad5daadaa278d6ddd46252a90b51d2dc316d1 Mon Sep 17 00:00:00 2001 From: Matej Voboril Date: Sun, 26 Feb 2017 00:17:47 -0600 Subject: [PATCH 3/7] added delete after response setting --- src/commands/Core/Invite.js | 2 +- src/commands/Settings/DeleteAfterRespond.js | 42 ++++++++++++++++ src/commands/Settings/RespondToSettings.js | 2 +- src/commands/Settings/Settings.js | 4 ++ src/settings/Database.js | 21 ++++++++ src/settings/MessageManager.js | 55 +++++++++------------ 6 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 src/commands/Settings/DeleteAfterRespond.js diff --git a/src/commands/Core/Invite.js b/src/commands/Core/Invite.js index 0fe251fff..7055a9125 100644 --- a/src/commands/Core/Invite.js +++ b/src/commands/Core/Invite.js @@ -11,7 +11,7 @@ class Invite extends Command { * @param {Genesis} bot The bot object */ constructor(bot) { - super(bot, 'core.invite', 'invite', 'Ping Genesis to test connectivity'); + super(bot, 'core.invite', 'invite', 'Send Invitation Link to Authorize Bot to Join a Server'); } /** diff --git a/src/commands/Settings/DeleteAfterRespond.js b/src/commands/Settings/DeleteAfterRespond.js new file mode 100644 index 000000000..bb85b5166 --- /dev/null +++ b/src/commands/Settings/DeleteAfterRespond.js @@ -0,0 +1,42 @@ +'use strict'; + +const Command = require('../../Command.js'); + +class RespondToSettings extends Command { + constructor(bot) { + super(bot, 'settings.deleteafterrespond', 'delete after respond', 'Set whether or not to allow the bot to delete commands and/or responses after responding.'); + this.usages = [ + { description: 'Change if the bot to delete commands and/or responses after responding in this channel', parameters: ['deleting enabled'] }, + ]; + this.regex = new RegExp('^delete\\s?after\\s?respond\\s?(.+)?$', 'i'); + } + + run(message) { + let enable = message.strippedContent.match(this.regex)[1]; + if (!enable) { + const embed = { + title: 'Usage', + type: 'rich', + color: 0x0000ff, + fields: [ + { + name: `${this.bot.prefix}${this.call} `, + value: '_ _', + }, + ], + }; + this.messageManager.embed(message, embed, true, true); + } else { + enable = enable.trim(); + let enableResponse = false; + if (enable === 'enable' || enable === 'enable' || enable === '1' || enable === 'true' || enable === 1) { + enableResponse = true; + } + this.bot.settings.setChannelResponseToSettings(message.channel, enableResponse) + .then(() => this.messageManager.notifySettingsChange(message, true, true)) + .catch(this.logger.error); + } + } +} + +module.exports = RespondToSettings; diff --git a/src/commands/Settings/RespondToSettings.js b/src/commands/Settings/RespondToSettings.js index 46a9acc85..57969418b 100644 --- a/src/commands/Settings/RespondToSettings.js +++ b/src/commands/Settings/RespondToSettings.js @@ -4,7 +4,7 @@ const Command = require('../../Command.js'); class RespondToSettings extends Command { constructor(bot) { - super(bot, 'settings.respondSettings', 'Set whether or not to respond to settings'); + super(bot, 'settings.respondSettings', 'respond yo settings', 'Set whether or not to respond to settings'); this.usages = [ { description: 'Change if this channel has settings changes resonded in it', parameters: ['response enabled'] }, ]; diff --git a/src/commands/Settings/Settings.js b/src/commands/Settings/Settings.js index 289e4410f..b6a93dee3 100644 --- a/src/commands/Settings/Settings.js +++ b/src/commands/Settings/Settings.js @@ -22,6 +22,10 @@ class Settings extends Command { }) .then((respond) => { settings.push({ name: 'Respond to Settings', value: respond === '1' ? 'yes' : 'no' }); + return this.bot.settings.getChannelDeleteAfterResponse(message.channel); + }) + .then((deleteAfterRespond) => { + settings.push({ name: 'Delete Message After Responding', value: deleteAfterRespond === '1' ? 'yes' : 'no' }); return this.bot.settings.getChannelPrefix(message.channel); }) .then((prefix) => { diff --git a/src/settings/Database.js b/src/settings/Database.js index e7aeb4bf1..b16e9ce16 100644 --- a/src/settings/Database.js +++ b/src/settings/Database.js @@ -38,6 +38,7 @@ class Database { respond_to_settings: true, platform: 'pc', language: 'en-us', + delete_after_respond: true, }; } @@ -153,6 +154,17 @@ class Database { return this.setChannelSetting(channel, 'respond_to_settings', respond); } + /** + * Sets whether or not to delete messages and responses after responding + * @param {Channel} channel The Discord channel for which to set the response setting + * @param {boolean} deleteAfterRespond Whether or not to delete messages + * and responses after responding + * @returns {Promise} + */ + setChannelDeleteAfterResponse(channel, deleteAfterRespond) { + return this.setChannelSetting(channel, 'delete_after_respond', deleteAfterRespond); + } + /** * Sets the custom prefix for this guild * @param {Guild} guild The Discord guild for which to set the response setting @@ -219,6 +231,15 @@ class Database { return this.getChannelSetting(channel, 'respond_to_settings'); } + /** + * Returns the delete_after_respond setting for a channel + * @param {Channel} channel The channel + * @returns {Promise.} + */ + getChannelDeleteAfterResponse(channel) { + return this.getChannelSetting(channel, 'delete_after_respond'); + } + /** * Returns the prefix setting for a guild * @param {Channel} channel The guild diff --git a/src/settings/MessageManager.js b/src/settings/MessageManager.js index b6666a176..ef47fde8d 100644 --- a/src/settings/MessageManager.js +++ b/src/settings/MessageManager.js @@ -36,12 +36,7 @@ class MessaageManager { message.channel.permissionsFor(this.client.user.id).hasPermission('SEND_MESSAGES')) || message.channel.type === 'dm') { promises.push(message.channel.sendMessage(`${this.zSWC}${content}`).then((msg) => { - if (deleteOriginal && message.deletable) { - promises.push(message.delete(10000)); - } - if (deleteResponse && msg.deletable) { - promises.push(msg.delete(10000)); - } + this.deleteCallAndResponse(message, msg, deleteOriginal, deleteResponse); })); } @@ -61,12 +56,7 @@ class MessaageManager { message.channel.permissionsFor(this.client.user.id).hasPermission('SEND_MESSAGES')) || message.channel.type === 'dm') { return message.channel.sendMessage(`${this.zSWC}${content}`).then((msg) => { - if (deleteOriginal && message.deletable) { - message.delete(10000).catch(this.logger.error); - } - if (deleteResponse && msg.deletable) { - msg.delete(10000).catch(this.logger.error); - } + this.deleteCallAndResponse(message, msg, deleteOriginal, deleteResponse); }); } return null; @@ -85,15 +75,9 @@ class MessaageManager { message.channel.permissionsFor(this.client.user.id).hasPermission('SEND_MESSAGES')) || message.channel.type === 'dm') { promises.push(message.reply(`${this.zSWC}${content}`).then((msg) => { - if (deleteOriginal && message.deletable) { - promises.push(message.delete(10000)); - } - if (deleteResponse && msg.deletable) { - promises.push(msg.delete(10000)); - } + this.deleteCallAndResponse(message, msg, deleteOriginal, deleteResponse); })); } - promises.forEach(promise => promise.catch(this.logger.error)); } @@ -110,12 +94,7 @@ class MessaageManager { message.channel.permissionsFor(this.client.user.id).hasPermissions(['SEND_MESSAGES', 'EMBED_LINKS'])) || message.channel.type === 'dm') { promises.push(message.channel.sendEmbed(embed).then((msg) => { - if (deleteOriginal && message && message.deletable) { - promises.push(message.delete(10000)); - } - if (deleteResponse && msg && msg.deletable) { - promises.push(msg.delete(10000)); - } + this.deleteCallAndResponse(message, msg, deleteOriginal, deleteResponse); })); } promises.forEach(promise => promise.catch(this.logger.error)); @@ -130,9 +109,7 @@ class MessaageManager { sendDirectMessageToAuthor(message, content, deleteResponse) { const promises = []; promises.push(message.author.sendMessage(content).then((msg) => { - if (deleteResponse && msg.deletable) { - promises.push(msg.delete(10000)); - } + this.deleteCallAndResponse(message, msg, false, deleteResponse); })); promises.forEach(promise => promise.catch(this.logger.error)); @@ -147,9 +124,7 @@ class MessaageManager { sendDirectEmbedToAuthor(message, embed, deleteResponse) { const promises = []; promises.push(message.author.sendEmbed(embed).then((msg) => { - if (deleteResponse && msg && msg.deletable) { - promises.push(msg.delete(10000)); - } + this.deleteCallAndResponse(message, msg, false, deleteResponse); })); promises.forEach(promise => promise.catch(this.logger.error)); } @@ -182,6 +157,24 @@ class MessaageManager { } }) .catch(this.logger.error); + promises.forEach(promise => promise.catch(this.logger.error)); + } + + deleteCallAndResponse(call, response, deleteCall, deleteResponse) { + const promises = []; + this.settings.getChannelDeleteAfterResponse(call.channel) + .then((deleteAfterRespond) => { + if (deleteAfterRespond === '1') { + if (deleteCall && call.deletable) { + promises.push(call.delete(10000)); + } + if (deleteResponse && response.deletable) { + promises.push(response.delete(10000)); + } + } + }) + .catch(this.logger.error); + promises.forEach(promise => promise.catch(this.logger.error)); } } From 1fcdc57697cc2c5d80c10759af386fedfefd8670 Mon Sep 17 00:00:00 2001 From: nspacestd Date: Sun, 26 Feb 2017 21:06:26 +0100 Subject: [PATCH 4/7] Indentation fix in safeNumber --- src/resources/RaidStat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resources/RaidStat.js b/src/resources/RaidStat.js index a2fcbdbdf..6c5143a21 100644 --- a/src/resources/RaidStat.js +++ b/src/resources/RaidStat.js @@ -22,7 +22,7 @@ function timeToSeconds(time) { * @returns {number|?} Either the passed value or 0 */ function safeNumber(value) { - return isNaN(value) ? 0 : value; + return isNaN(value) ? 0 : value; } /** From b1205af4469478c38f1e61d2989fac12fd817240 Mon Sep 17 00:00:00 2001 From: nspacestd Date: Sun, 26 Feb 2017 21:18:50 +0100 Subject: [PATCH 5/7] Move default to a separate else block --- src/commands/Settings/Disable.js | 4 +++- src/commands/Settings/Enable.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/commands/Settings/Disable.js b/src/commands/Settings/Disable.js index 02f8a28f9..e36127532 100644 --- a/src/commands/Settings/Disable.js +++ b/src/commands/Settings/Disable.js @@ -114,7 +114,7 @@ class Disable extends Command { * @returns {Role|User} target or user to disable commands for */ getTarget(targetParam, roleMentions, userMentions, message) { - let target = ''; + let target; if (roleMentions.array().length > 0) { target = roleMentions.array()[0]; target.type = 'Role'; @@ -133,6 +133,8 @@ class Disable extends Command { } else if (userTarget) { target = userTarget; target.type = 'User'; + } else { + target = ''; } } return target; diff --git a/src/commands/Settings/Enable.js b/src/commands/Settings/Enable.js index 0f5290f7a..9ca834757 100644 --- a/src/commands/Settings/Enable.js +++ b/src/commands/Settings/Enable.js @@ -114,7 +114,7 @@ class Enable extends Command { * @returns {Role|User} target or user to enable commands for */ getTarget(targetParam, roleMentions, userMentions, message) { - let target = ''; + let target; if (roleMentions.length > 0) { target = roleMentions[0]; target.type = 'Role'; @@ -133,6 +133,8 @@ class Enable extends Command { } else if (userTarget) { target = userTarget; target.type = 'User'; + } else { + target = ''; } } return target; From 0c1b252d453b39fdebd1740fa69b8426da70eb35 Mon Sep 17 00:00:00 2001 From: nspacestd Date: Sun, 26 Feb 2017 21:19:14 +0100 Subject: [PATCH 6/7] Remove useless assignment --- src/embeds/NewsEmbed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embeds/NewsEmbed.js b/src/embeds/NewsEmbed.js index 07e83cc8c..f26a045f2 100644 --- a/src/embeds/NewsEmbed.js +++ b/src/embeds/NewsEmbed.js @@ -38,7 +38,7 @@ class NewsEmbed extends BaseEmbed { } } else { name = 'Current news:'; - value = value = value.length > 0 ? value : 'No News Currently'; + value = value.length > 0 ? value : 'No News Currently'; title = 'Worldstate - News'; } From d4ab9022c76efde6e4c7ede8ae6c65573aeea321 Mon Sep 17 00:00:00 2001 From: Matej Voboril Date: Sun, 5 Mar 2017 23:47:56 -0600 Subject: [PATCH 7/7] New chart command --- src/commands/Ondemand/Progression.js | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/commands/Ondemand/Progression.js diff --git a/src/commands/Ondemand/Progression.js b/src/commands/Ondemand/Progression.js new file mode 100644 index 000000000..a4ccfc109 --- /dev/null +++ b/src/commands/Ondemand/Progression.js @@ -0,0 +1,35 @@ +'use strict'; + +const Command = require('../../Command.js'); + +/** + * Displays the Warframe Progression Chart + */ +class Progression extends Command { + /** + * Constructs a callable command + * @param {Genesis} bot The bot object + */ + constructor(bot) { + super(bot, 'warframe.misc.progress', 'progress', 'Display Warframe Progression Chart'); + this.progressionChart = 'http://i.imgur.com/0uutM7a.png'; + } + + /** + * Run the command + * @param {Message} message Message with a command to handle, reply to, + * or perform an action based on parameters. + */ + run(message) { + message.channel.sendFile(this.progressionChart, 'progression.png', + `Operator ${message.author.toString()}, the progression flowchart, at your request.`) + .then(() => { + if (message.deletable) { + return message.delete(2000); + } + return Promise.resolve(); + }).catch(this.logger.error); + } +} + +module.exports = Progression;