From 2e9217f30dc6f2627f74099f9ab6ea6fbe61a17e Mon Sep 17 00:00:00 2001 From: Isaac Date: Thu, 1 Apr 2021 19:33:53 +0100 Subject: [PATCH] Fix and improve broken and bad code. Improve command handler, fixed message logging, fixes potential prefix problem, other small changes --- src/commands/new.js | 3 ++- src/database/index.js | 2 +- src/listeners/message.js | 23 +++++++++--------- src/listeners/messageDelete.js | 2 +- src/listeners/messageUpdate.js | 41 +++++++++++++++----------------- src/locales/en-GB.json | 16 +++++++------ src/logger.js | 2 +- src/modules/commands/command.js | 9 +++++-- src/modules/commands/manager.js | 42 +++++++++++++++++---------------- user/example.config.js | 14 ++++------- 10 files changed, 78 insertions(+), 76 deletions(-) diff --git a/src/commands/new.js b/src/commands/new.js index 31ff2ad..72efd93 100644 --- a/src/commands/new.js +++ b/src/commands/new.js @@ -17,7 +17,8 @@ module.exports = class NewCommand extends Command { { name: i18n('commands.new.args.topic.name'), description: i18n('commands.new.args.topic.description'), - required: false, + example: i18n('commands.new.args.topic.example'), + required: true, } ] }); diff --git a/src/database/index.js b/src/database/index.js index b23dee8..8d26de0 100644 --- a/src/database/index.js +++ b/src/database/index.js @@ -199,7 +199,7 @@ module.exports = async (log) => { type: DataTypes.BOOLEAN, defaultValue: false, }, - updates: { + data: { type: DataTypes.JSON }, }, { diff --git a/src/listeners/message.js b/src/listeners/message.js index e1fbb11..cb0630e 100644 --- a/src/listeners/message.js +++ b/src/listeners/message.js @@ -4,29 +4,30 @@ module.exports = { let settings = await message.guild?.settings; - // message collection for ticket archiving + // message collection for t_row archiving if (settings?.log_messages) { if (message.system) return; - let ticket = await client.db.models.Ticket.findOne({ + let t_row = await client.db.models.Ticket.findOne({ where: { id: message.channel.id } }); - if (ticket) { + if (t_row) { + let embeds = []; + for (let embed in message.embeds) embeds.push({ ...message.embeds[embed] }); + await client.db.models.Message.create({ id: message.id, - ticket: ticket.id, + ticket: t_row.id, author: message.author.id, - updates: [{ + data: { content: message.content, - time: message.createdTimestamp, - embeds: message.embeds.map(embed => { - return { ...message.embeds[embed] }; - }), - attachments: [ ...message.attachments.values() ] - }] + // time: message.createdTimestamp, + embeds, + attachments: [...message.attachments.values()] + } }); } } diff --git a/src/listeners/messageDelete.js b/src/listeners/messageDelete.js index 421d51f..4302acc 100644 --- a/src/listeners/messageDelete.js +++ b/src/listeners/messageDelete.js @@ -9,7 +9,7 @@ module.exports = { let msg = await client.db.models.Message.findOne({ where: { - id: message.channel.id + id: message.id } }); diff --git a/src/listeners/messageUpdate.js b/src/listeners/messageUpdate.js index d6e8f0f..b81d768 100644 --- a/src/listeners/messageUpdate.js +++ b/src/listeners/messageUpdate.js @@ -1,5 +1,5 @@ module.exports = { - event: 'msgUpdate', + event: 'messageUpdate', execute: async (client, oldm, newm) => { if (newm.partial) { @@ -12,34 +12,31 @@ module.exports = { let settings = await newm.guild?.settings; - if (settings?.messages) { + if (settings?.log_messages) { if (newm.system) return; - let msg = await client.db.models.msg.findOne({ + let m_row = await client.db.models.Message.findOne({ where: { - id: newm.channel.id + id: newm.id } }); - if (msg) { - let embeds = msg.embeds.map(embed => { - return { ...msg.embeds[embed] }; - }); - - if (msg.editedTimestamp) { // message has been edited - msg.updates.unshift({ - content: msg.content, - time: msg.editedTimestamp, - embeds, - attachments: [ ...msg.attachments.values() ] - }); - msg.edited = true; - } - else { // probably just a link embed loading - msg.updates[0] = Object.assign(msg.updates[0], embeds); - } + if (m_row) { + let embeds = []; + for (let embed in newm.embeds) embeds.push({ ...newm.embeds[embed] }); - await msg.save(); // save changes to msg row + m_row.data = { + content: newm.content, + // time: newm.editedTimestamp, + embeds: newm.embeds.map(embed => { + return { ...newm.embeds[embed] }; + }), + attachments: [...newm.attachments.values()] + }; + + if (newm.editedTimestamp) m_row.edited = true; + + await m_row.save(); // save changes } } } diff --git a/src/locales/en-GB.json b/src/locales/en-GB.json index 098d98c..c6647d0 100644 --- a/src/locales/en-GB.json +++ b/src/locales/en-GB.json @@ -3,12 +3,13 @@ "version": "[Discord Tickets](%s) v%s by [eartharoid](%s)" }, "cmd_usage": { - "title": "`%s` command usage", - "description": "**Usage:** %s" - }, - "cmd_usage_named_args": { - "title": "`%s` command usage", - "description": "This command uses named arguments:\n`%s argName: value anotherArg: \"A string value\";`\n\n**Required arguments are prefixed with `❗`.**" + "args": { + "description": "**Description:**", + "example": "**Example:**" + }, + "description": "**Usage:**\n`%s`\n\n**Example:**\n`%s`\n\nRequired arguments are prefixed with `❗`.", + "named_args_description": "This command uses named arguments.\n\n", + "title": "`%s` command usage" }, "commands": { "new": { @@ -23,7 +24,8 @@ }, "topic": { "name": "topic", - "description": "The topic of the ticket" + "description": "The topic of the ticket", + "example": "Problem with billing" } }, "description": "Create a new ticket", diff --git a/src/logger.js b/src/logger.js index efd05da..be31221 100644 --- a/src/logger.js +++ b/src/logger.js @@ -5,7 +5,7 @@ module.exports = new Logger({ name: 'Discord Tickets by eartharoid', debug: config.debug, logToFile: config.logs.enabled, - splitFile: true, + splitFile: config.logs.split, directory: path('./logs/'), keepFor: config.logs.keep_for, timestamp: 'YYYY-MM-DD HH:mm:ss', diff --git a/src/modules/commands/command.js b/src/modules/commands/command.js index 25e259d..a5001df 100644 --- a/src/modules/commands/command.js +++ b/src/modules/commands/command.js @@ -71,11 +71,16 @@ module.exports = class Command { */ this.args = data.args; + for (let arg in this.args) { + if (!this.args[arg].example) + throw new Error(`The "${this.name}" command's "${this.args[arg].name}" argument does not have an example!`); + } + /** * True if command is internal, false if it is from a plugin * @type {boolean} */ - this.internal = data.internal; + this.internal = data.internal === true ? true : false; if (!this.internal) { /** @@ -98,7 +103,7 @@ module.exports = class Command { * The code to be executed when a command is invoked * @abstract * @param {Message} message - The message that invoked this command - * @param {(object|string)?} args - Named command arguments, or the message content with the prefix and command removed + * @param {(object|string)} [args] - Named command arguments, or the message content with the prefix and command removed */ async execute(message, args) { } // eslint-disable-line no-unused-vars diff --git a/src/modules/commands/manager.js b/src/modules/commands/manager.js index 48d2084..12aa220 100644 --- a/src/modules/commands/manager.js +++ b/src/modules/commands/manager.js @@ -72,31 +72,35 @@ module.exports = class CommandManager { const prefix = settings.command_prefix; const i18n = this.client.i18n.get(settings.locale); - let cmd_name = message.content.match(new RegExp(`^${prefix}(\\S+)`, 'mi')); + let cmd_name = message.content.match(new RegExp(`^${prefix.replace(/(?=\W)/g, '\\')}(\\S+)`, 'mi')); if (!cmd_name) return; - let raw_args = message.content.replace(cmd_name[0], '').trim(); - cmd_name = cmd_name[1]; + let raw_args = message.content.replace(cmd_name[0], '').trim(); // remove the prefix and command + cmd_name = cmd_name[1]; // set cmd_name to the actual string const cmd = this.commands.find(cmd => cmd.aliases.includes(cmd_name)); - if (!cmd); + if (!cmd) return; let args = raw_args; + const addArgs = (embed, arg) => { + let required = arg.required ? '`❗` ' : ''; + embed.addField(required + arg.name, `» ${i18n('cmd_usage.args.description')} ${arg.description}\n» ${i18n('cmd_usage.args.example')} \`${arg.example}\``); + }; + if (cmd.process_args) { args = {}; - let data = [ ...raw_args.matchAll(/(\w+)\??\s?:\s?(["`'](.*)["`'];|[\w<>@!#]+)/gmi) ]; - data.forEach(arg => args[arg[1]] = arg[3] || arg[2]); + let data = [...raw_args.matchAll(/(?\w+)\??\s?:\s?(?([^;]|;{2})*);/gmi)]; + data.forEach(arg => args[arg.groups.key] = arg.groups.value.replace(/;{2}/gm, ';')); for (let arg of cmd.args) { - if (!args[arg]) { + if (arg.required && !args[arg]) { + let usage = `${prefix + cmd_name} ${cmd.args.map(arg => arg.required ? `<${arg.name};>` : `[${arg.name};]`).join(' ')}`; + let example = `${prefix + cmd_name} ${cmd.args.map(arg => `${arg.name}: ${arg.example};`).join(' ')}`; let embed = new MessageEmbed() .setColor(settings.error_colour) - .setTitle(i18n('cmd_usage_named_args.title', cmd_name)) - .setDescription(i18n('cmd_usage_named_args.description', settings.command_prefix + cmd_name)); - cmd.args.forEach(a => { - let required = a.required ? '`❗` ' : ''; - embed.addField(required + a.name, a.description); - }); + .setTitle(i18n('cmd_usage.title', cmd_name)) + .setDescription(i18n('cmd_usage.named_args_description') + i18n('cmd_usage.description', usage, example)); + cmd.args.forEach(a => addArgs(embed, a)); return message.channel.send(embed); } } @@ -104,15 +108,13 @@ module.exports = class CommandManager { const args_num = raw_args.split(' ').filter(arg => arg.length !== 0).length; const required_args = cmd.args.reduce((acc, arg) => arg.required ? acc + 1 : acc, 0); if (args_num < required_args) { - let usage = cmd.args.map(arg => arg.required ? `<${arg.name}>` : `[${arg.name}]`).join(' '); + let usage = `${prefix + cmd_name} ${cmd.args.map(arg => arg.required ? `<${arg.name}>` : `[${arg.name}]`).join(' ')}`; + let example = `${prefix + cmd_name} ${cmd.args.map(arg => `${arg.example}`).join(' ')}`; let embed = new MessageEmbed() .setColor(settings.error_colour) .setTitle(i18n('cmd_usage.title', cmd_name)) - .setDescription(i18n('cmd_usage.description', `\`${settings.command_prefix + cmd_name} ${usage}\``)); - cmd.args.forEach(a => { - let required = a.required ? '`❗` ' : ''; - embed.addField(required + a.name, a.description); - }); + .setDescription(i18n('cmd_usage.description', usage, example)); + cmd.args.forEach(a => addArgs(embed, a)); return message.channel.send(embed); } } @@ -152,7 +154,7 @@ module.exports = class CommandManager { try { this.client.log.commands(`Executing "${cmd.name}" command (invoked by ${message.author.tag})`); - await cmd.execute(message, args, raw_args); // execute the command + await cmd.execute(message, args); // execute the command } catch (e) { this.client.log.warn(`An error occurred whilst executing the ${cmd.name} command`); this.client.log.error(e); diff --git a/user/example.config.js b/user/example.config.js index 1f04493..57a0d66 100644 --- a/user/example.config.js +++ b/user/example.config.js @@ -7,17 +7,11 @@ * |____/ |_| |___/ \___| \___/ |_| \__,_| |_| |_| \___| |_|\_\ \___| \__| |___/ * * --------------------- - * Quick Start - * --------------------- - * - * > For detailed instructions, visit the documentation: https://discordtickets.app - * - * --------------------- * Support * --------------------- * - * > Discord support server: https://go.eartharoid.me/discord * > Documentation: https://discordtickets.app + * > Discord support server: https://go.eartharoid.me/discord * * ############################################################################################### */ @@ -29,13 +23,13 @@ module.exports = { command_prefix: 'tickets/', log_messages: true, // transcripts/archives will be empty if false name_format: 'ticket-{number}', - prefix: '-', - ticket_welcome: 'Hello {{name}}, thank you for creating a ticket. A member of staff will soon be available to assist you.\n\n__All messages in this channel are stored for future reference.__', + ticket_welcome: 'Hello {name}, thank you for creating a ticket. A member of staff will soon be available to assist you.\n\n__All messages in this channel are stored for future reference.__', }, locale: 'en-GB', // used for globals (such as commands) and the default guild locale logs: { enabled: true, - keep_for: 30 + keep_for: 30, + split: true, }, max_listeners: 10, plugins: [],