From 7fa653bf5b06e12e5cc450e0e1589a5958550d58 Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 5 Jul 2021 00:34:45 +0200 Subject: [PATCH 1/2] layout --- src/AutoResponse.js | 104 +++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/src/AutoResponse.js b/src/AutoResponse.js index 2ebdb2ac3..155a3f0de 100644 --- a/src/AutoResponse.js +++ b/src/AutoResponse.js @@ -6,61 +6,67 @@ const Discord = require('discord.js'); */ class AutoResponse extends ChatTriggeredFeature { - static tableName = 'responses'; + static tableName = 'responses'; - static columns = ['guildid', 'trigger', 'response', 'global', 'channels']; + static columns = ['guildid', 'trigger', 'response', 'global', 'channels']; - /** - * constructor - create an auto response - * @param {module:"discord.js".Snowflake} gid guild ID - * @param {Object} json options - * @param {Trigger} json.trigger filter that triggers the response - * @param {String} json.response message to send to the channel - * @param {Boolean} json.global does this apply to all channels in this guild - * @param {module:"discord.js".Snowflake[]} [json.channels] channels that this applies to - * @param {Number} [id] id in DB - * @return {AutoResponse} the auto response - */ - constructor(gid, json, id) { - super(id, json.trigger); - this.gid = gid; + /** + * constructor - create an auto response + * @param {module:"discord.js".Snowflake} gid guild ID + * @param {Object} json options + * @param {Trigger} json.trigger filter that triggers the response + * @param {String} json.response message to send to the channel + * @param {Boolean} json.global does this apply to all channels in this guild + * @param {module:"discord.js".Snowflake[]} [json.channels] channels that this applies to + * @param {Number} [id] id in DB + * @return {AutoResponse} the auto response + */ + constructor(gid, json, id) { + super(id, json.trigger); + this.gid = gid; - if (json) { - this.response = json.response; - this.global = json.global; - this.channels = json.channels; - } + if (json) { + this.response = json.response; + this.global = json.global; + this.channels = json.channels; + } - if (!this.channels) { - this.channels = []; - } - } + if (!this.channels) { + this.channels = []; + } + } - /** - * serialize the response - * @returns {(*|string)[]} - */ - serialize() { - return [this.gid, JSON.stringify(this.trigger), this.response, this.global, this.channels.join(',')]; - } + /** + * serialize the response + * @returns {(*|string)[]} + */ + serialize() { + return [this.gid, JSON.stringify(this.trigger), this.response, this.global, this.channels.join(',')]; + } - /** - * generate an Embed displaying the info of this response - * @param {String} title - * @param {Number} color - * @returns {module:"discord.js".MessageEmbed} - */ - embed(title, color) { - return new Discord.MessageEmbed() - .setTitle(title + ` [${this.id}]`) - .setColor(color) - .addFields( - /** @type {any} */[ - {name: 'Trigger', value: `${this.trigger.type}: \`${this.trigger.type === 'regex' ? '/' + this.trigger.content + '/' + this.trigger.flags : this.trigger.content}\``.substring(0, 1000)}, - {name: 'Response', value: this.response.substring(0,1000)}, - {name: 'Channels', value: this.global ? 'global' : this.channels.map(c => `<#${c}>`).join(', ').substring(0, 1000)} - ]); - } + /** + * generate an Embed displaying the info of this response + * @param {String} title + * @param {Number} color + * @returns {module:"discord.js".MessageEmbed} + */ + embed(title, color) { + return new Discord.MessageEmbed() + .setTitle(title + ` [${this.id}]`) + .setColor(color) + .addFields( + /** @type {any} */[ + { + name: 'Trigger', + value: `${this.trigger.type}: \`${this.trigger.type === 'regex' ? '/' + this.trigger.content + '/' + this.trigger.flags : this.trigger.content}\``.substring(0, 1000) + }, + {name: 'Response', value: this.response.substring(0, 1000)}, + { + name: 'Channels', + value: this.global ? 'global' : this.channels.map(c => `<#${c}>`).join(', ').substring(0, 1000) + } + ]); + } } From 1a7e3bf758d256f55e5df46ab9fa3666bad25527 Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 5 Jul 2021 00:55:36 +0200 Subject: [PATCH 2/2] refactor auto response command --- src/AutoResponse.js | 71 ++++++++ src/BadWord.js | 2 +- src/commands/legacy/autoresponse.js | 52 ------ src/commands/legacy/autoresponse/add.js | 89 ---------- src/commands/legacy/autoresponse/info.js | 22 --- src/commands/legacy/autoresponse/list.js | 21 --- src/commands/legacy/autoresponse/remove.js | 45 ----- src/commands/settings/AutoResponseCommand.js | 167 +++++++++++++++++++ 8 files changed, 239 insertions(+), 230 deletions(-) delete mode 100644 src/commands/legacy/autoresponse.js delete mode 100644 src/commands/legacy/autoresponse/add.js delete mode 100644 src/commands/legacy/autoresponse/info.js delete mode 100644 src/commands/legacy/autoresponse/list.js delete mode 100644 src/commands/legacy/autoresponse/remove.js create mode 100644 src/commands/settings/AutoResponseCommand.js diff --git a/src/AutoResponse.js b/src/AutoResponse.js index 155a3f0de..963868f00 100644 --- a/src/AutoResponse.js +++ b/src/AutoResponse.js @@ -1,5 +1,6 @@ const ChatTriggeredFeature = require('./ChatTriggeredFeature'); const Discord = require('discord.js'); +const util = require('./util'); /** * Class representing an auto response @@ -68,6 +69,76 @@ class AutoResponse extends ChatTriggeredFeature { ]); } + /** + * create a new response + * @param {Snowflake} guildID + * @param {boolean} global + * @param {Snowflake[]|null} channels + * @param {String} triggerType + * @param {String} triggerContent + * @param {String} responseText + * @returns {Promise<{success:boolean, response: AutoResponse, message: String}>} + */ + static async new(guildID, global, channels, triggerType, triggerContent, responseText) { + let trigger = this.getTrigger(triggerType, triggerContent); + if (!trigger.success) return trigger; + + const response = new AutoResponse(guildID, { + trigger: trigger.trigger, + global, + channels, + response: responseText + }); + await response.save(); + return {success: true, response: response}; + } + + /** + * edit this auto-response + * @param {String} option option to change + * @param {String[]} args + * @param {module:"discord.js".Guild} guild + * @returns {Promise} response message + */ + async edit(option, args, guild) { + switch (option) { + case 'trigger': { + let trigger = this.constructor.getTrigger(args.shift(), args.join(' ')); + if (!trigger.success) return trigger.message; + this.trigger = trigger.trigger; + await this.save(); + return 'Successfully changed trigger'; + } + + case 'response': { + let response = args.join(' '); + if (!response) response = 'disabled'; + + this.response = response; + await this.save(); + return `Successfully ${response === 'disabled' ? 'disabled' : 'changed'} response`; + } + + case 'channels': { + if (args[0].toLowerCase() === 'global') { + this.global = true; + this.channels = []; + } + else { + let channels = await util.channelMentions(guild, args); + if (!channels) return 'No valid channels specified'; + this.global = false; + this.channels = channels; + } + await this.save(); + return global ? 'Successfully made this auto-response global' : 'Successfully changed channels'; + } + + default: { + return 'Unknown option'; + } + } + } } module.exports = AutoResponse; diff --git a/src/BadWord.js b/src/BadWord.js index 174dbc270..8eda75d1b 100644 --- a/src/BadWord.js +++ b/src/BadWord.js @@ -175,7 +175,7 @@ class BadWord extends ChatTriggeredFeature { this.channels = []; } else { - let channels = util.channelMentions(guild, args); + let channels = await util.channelMentions(guild, args); if (!channels) return 'No valid channels specified'; this.global = false; this.channels = channels; diff --git a/src/commands/legacy/autoresponse.js b/src/commands/legacy/autoresponse.js deleted file mode 100644 index 382e55618..000000000 --- a/src/commands/legacy/autoresponse.js +++ /dev/null @@ -1,52 +0,0 @@ -const util = require('../../util.js'); -const AutoResponse = require('../../AutoResponse'); - -const list = require('./autoresponse/list'); -const add = require('./autoresponse/add'); -const remove = require('./autoresponse/remove'); -const info = require('./autoresponse/info'); - -const command = {}; - -command.description = 'Adds, removes and lists auto responses'; - -command.usage = ' '; - -command.names = ['autoresponse','response','responses','autoresponses']; - -command.execute = async (message, args, database, bot) => { - //Permission check - if (!message.member.hasPermission('MANAGE_GUILD')) { - await message.channel.send('You need the "Manage Server" permission to use this command.'); - return; - } - if (!args.length) { - return await message.channel.send(await util.usage(message,command.names[0])); - } - - let responses = await AutoResponse.getAll(message.guild.id); - - switch (args.shift().toLowerCase()) { - case 'list': - await list(responses,message); - break; - - case 'add': - await add(message); - break; - - case 'delete': - case 'remove': - await remove(responses, message, args); - break; - - case 'info': - await info(responses, message, args); - break; - - default: - return await message.channel.send(await util.usage(message,command.names[0])); - } -}; - -module.exports = command; diff --git a/src/commands/legacy/autoresponse/add.js b/src/commands/legacy/autoresponse/add.js deleted file mode 100644 index f7d3aca43..000000000 --- a/src/commands/legacy/autoresponse/add.js +++ /dev/null @@ -1,89 +0,0 @@ -const AutoResponse = require('../../../AutoResponse'); -const util = require('../../../util.js'); - -/** - * add an autoresponse - * @param {module:"discord.js".Message} message - * @returns {Promise} - */ -module.exports = async (message) => { - await message.channel.send("Please enter your trigger type (\`regex\`, \`include\` or \`match\`)!"); - let type = await util.getResponse(message.channel,message.author.id); - - if (type === null) { - return; - } - - type = type.toLowerCase(); - - if (!AutoResponse.triggerTypes.includes(type)) { - return await message.channel.send("Not a valid trigger type!"); - } - - await message.channel.send(`Please enter your trigger (${ type === 'regex' ? '`/regex/flags`' :'`example trigger`'})!`); - let content = await util.getResponse(message.channel,message.author.id); - - if (content === null) { - return; - } - - content = content.replace(/^`(.*)`$/,(a,b) => b); - - let flags; - if (type === 'regex') { - let regex = content.split(/(?} - */ -module.exports = async (responses, message, args) => { - if (!args.length) { - await message.channel.send("Provide the id of the autoresponse you want to view"); - return; - } - let response = responses.get(parseInt(args.shift())); - if (!response) { - await message.channel.send("Invalid id!"); - return; - } - - await message.channel.send(response.embed("Autoresponse",util.color.green)); -}; diff --git a/src/commands/legacy/autoresponse/list.js b/src/commands/legacy/autoresponse/list.js deleted file mode 100644 index 1783977ca..000000000 --- a/src/commands/legacy/autoresponse/list.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * list auto responses - * @param {module:"discord.js".Collection} responses - * @param {module:"discord.js".Message} message - * @returns {Promise} - */ -module.exports = async (responses, message) => { - if (!responses.size) { - return await message.channel.send("No autoresponses!"); - } - - let text = ''; - for (const [id, response] of responses) { - if(text.length > 1500){ - await message.channel.send(text.substring(0, 2000)); - text = ''; - } - text += `[${id}] ${response.global ? "global" : response.channels.map(c => `<#${c}>`).join(', ')} (${response.trigger.type}): \`${response.trigger.type === 'regex' ? '/' + response.trigger.content + '/' + response.trigger.flags : response.trigger.content}\` \n`; - } - await message.channel.send(text.substring(0, 2000)); -}; diff --git a/src/commands/legacy/autoresponse/remove.js b/src/commands/legacy/autoresponse/remove.js deleted file mode 100644 index 5b35d45d4..000000000 --- a/src/commands/legacy/autoresponse/remove.js +++ /dev/null @@ -1,45 +0,0 @@ -const util = require('../../../util.js'); -const icons = require('../../../icons'); - -/** - * remove an auto-response - * @param {module:"discord.js".Collection} responses - * @param {module:"discord.js".Message} message - * @param {String[]} args - * @returns {Promise} - */ -module.exports = async (responses, message, args) => { - if (!args.length) { - await message.channel.send("Provide the id of the autoresponse you want to remove"); - return; - } - let response = responses.get(parseInt(args.shift())); - if (!response) { - await message.channel.send("Invalid id!"); - return; - } - - let confirmation = await message.channel.send("Do you really want to delete this autoresponse?", response.embed("Remove autoresponse", util.color.red)); - { - let yes = confirmation.react(icons.yes); - let no = confirmation.react(icons.no); - await Promise.all([yes,no]); - } - - let confirmed; - try { - confirmed = (await confirmation.awaitReactions((reaction, user) => { - return user.id === message.author.id && (reaction.emoji.name === icons.yes || reaction.emoji.name === icons.no); - }, { max: 1, time: 15000, errors: ['time'] })).first().emoji.name === icons.yes; - } - catch { - return await message.channel.send("You took to long to react!"); - } - if (!confirmed) { - return await message.channel.send("Canceled!"); - } - - await response.remove(); - - await message.channel.send(`Removed the autoresponse with the id ${response.id}!`); -}; diff --git a/src/commands/settings/AutoResponseCommand.js b/src/commands/settings/AutoResponseCommand.js new file mode 100644 index 000000000..deebc0583 --- /dev/null +++ b/src/commands/settings/AutoResponseCommand.js @@ -0,0 +1,167 @@ +const Command = require('../../Command'); +const Discord = require('discord.js'); +const util = require('../../util'); +const AutoResponse = require('../../AutoResponse'); + +class AutoResponseCommand extends Command { + + static description = 'Configure auto-responses'; + + static usage = 'list|add|remove|show|edit'; + + static subCommands = { + list: { + usage:'', + description: 'List all auto-responses' + }, + add: { + usage: 'global| regex|include|match ', + description: 'Add an auto-response' + }, + remove: { + usage: '', + description: 'Remove an auto-response' + }, + show: { + usage: '', + description: 'Display an auto-response' + }, + edit: { + usage: ' trigger|response|channels ', + description: 'change options of an auto-response' + } + } + + static names = ['autoresponse','response','responses','autoresponses']; + + static userPerms = ['MANAGE_GUILD']; + + async execute() { + if (this.args.length === 0) { + await this.sendUsage(); + return; + } + + /** @type {module:"discord.js".Collection} */ + const responses = await AutoResponse.getAll(/** @type {Snowflake} */ this.message.guild.id); + + switch (this.args.shift().toLowerCase()) { + case 'list': { + if (!responses.size) return this.message.channel.send('No auto-responses!'); + + let text = ''; + for (const [id, response] of responses) { + const info = `[${id}] ${response.global ? 'global' : response.channels.map(c => `\`${c}\``).join(', ')} ` + + '`' + response.trigger.asString() + '`\n'; + + if (text.length + info.length < 2000) { + text += info; + } else { + await this.message.channel.send(text); + text = info; + } + } + if (text.length) await this.message.channel.send(text); + break; + } + + case 'add': { + if (this.args.length < 2) return this.sendSubCommandUsage('add'); + + const global = this.args[0].toLowerCase() === 'global'; + + let channels; + if (!global) channels = await util.channelMentions(this.message.guild, this.args); + else this.args.shift(); + + if (!global && !channels.length) return this.sendUsage(); + + const type = this.args.shift().toLowerCase(); + const content = this.args.join(' '); + + await this.message.channel.send('Please enter your response:'); + const responseText = await util.getResponse(this.message.channel, this.message.author.id); + if (!responseText) return; + + let response = await AutoResponse.new(this.message.guild.id, global, channels, type, content, responseText); + if (!response.success) return this.message.channel.send(response.message); + + await this.message.channel.send(response.response.embed('Added new auto-response', util.color.green)); + break; + } + + case 'remove': { + const response = await this.getAutoResponse(this.args.shift(), 'remove'); + if (!response) return; + await response.remove(); + await this.message.channel.send(response.embed(`Removed auto-response ${response.id}`, util.color.red)); + break; + } + + case 'show': { + const response = await this.getAutoResponse(this.args.shift(), 'remove'); + if (!response) return; + await this.message.channel.send(response.embed(`Auto-response ${response.id}`, util.color.green)); + break; + } + + case 'edit': { + if (this.args.length < 3) return this.sendSubCommandUsage('edit'); + const response = await this.getAutoResponse(this.args.shift(), 'remove'); + if (!response) return; + + await this.message.channel.send(response.embed(await response.edit(this.args.shift(), this.args, this.message.guild), util.color.green)); + break; + } + + default: + await this.sendUsage(); + } + + } + + /** + * get a single auto-response + * @param {String|Number} id + * @param {String} subCommand + * @returns {Promise} + */ + async getAutoResponse(id, subCommand) { + if (!id || !parseInt(id)) { + await this.sendSubCommandUsage(subCommand); + return null; + } + const result = await AutoResponse.getByID(id); + if (!result) { + await this.sendSubCommandUsage(subCommand); + return null; + } + return result; + } + + /** + * send usage for a subcommand + * @param {String} commandName sub command name + * @returns {Promise} + */ + async sendSubCommandUsage(commandName) { + commandName = commandName.toLowerCase(); + let subCommand = this.constructor.subCommands[commandName]; + if (!subCommand) throw 'Unknown subcommand'; + + return this.message.channel.send(new Discord.MessageEmbed() + .setAuthor(`Help for ${this.name} ${commandName} | Prefix: ${this.prefix}`) + .setFooter(`Command executed by ${util.escapeFormatting(this.message.author.tag)}`) + .addFields( + /** @type {any} */ + { name: 'Usage', value: `\`${this.prefix}${this.name} ${commandName} ${subCommand.usage}\``, inline: true}, + /** @type {any} */ { name: 'Description', value: subCommand.description, inline: true}, + /** @type {any} */ { name: 'Required Permissions', value: this.constructor.userPerms.map(p => `\`${p}\``).join(',') || 'none' } + ) + .setColor(util.color.green) + .setTimestamp() + ); + } +} + +module.exports = AutoResponseCommand;