FAQs/tags/canned responses

This commit is contained in:
Isaac 2021-05-18 22:08:49 +01:00
parent f40fabfbf3
commit c03a32dbb4
No known key found for this signature in database
GPG Key ID: F6812DBC6719B4E3
5 changed files with 154 additions and 9 deletions

View File

@ -60,7 +60,6 @@ module.exports = class SettingsCommand extends Command {
for (const c of data.categories) { for (const c of data.categories) {
if (c.id) { if (c.id) {
// existing category // existing category
const cat_row = await this.client.db.models.Category.findOne({ const cat_row = await this.client.db.models.Category.findOne({
where: { where: {
@ -95,9 +94,7 @@ module.exports = class SettingsCommand extends Command {
}, `Tickets category updated by ${message.author.tag}`); }, `Tickets category updated by ${message.author.tag}`);
} }
} }
} else { } else {
// create a new category // create a new category
const allowed_permissions = ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY', 'SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES']; const allowed_permissions = ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY', 'SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES'];
const cat_channel = await message.guild.channels.create(c.name, { const cat_channel = await message.guild.channels.create(c.name, {
@ -139,7 +136,6 @@ module.exports = class SettingsCommand extends Command {
roles: c.roles, roles: c.roles,
survey: c.survey survey: c.survey
}); });
} }
} }
@ -158,9 +154,7 @@ module.exports = class SettingsCommand extends Command {
this.client.log.success(`Updated guild settings for "${message.guild.name}"`); this.client.log.success(`Updated guild settings for "${message.guild.name}"`);
return await message.channel.send(i18n('commands.settings.response.updated')); return await message.channel.send(i18n('commands.settings.response.updated'));
} else { } else {
// upload settings as json to be edited // upload settings as json to be edited
const categories = await this.client.db.models.Category.findAll({ const categories = await this.client.db.models.Category.findAll({
@ -216,7 +210,6 @@ module.exports = class SettingsCommand extends Command {
message.channel.send({ message.channel.send({
files: [attachment] files: [attachment]
}); });
} }
} }
}; };

125
src/commands/tag.js Normal file
View File

@ -0,0 +1,125 @@
const Command = require('../modules/commands/command');
// eslint-disable-next-line no-unused-vars
const { MessageEmbed, Message } = require('discord.js');
const { parseArgsStringToArgv: argv } = require('string-argv');
const parseArgs = require('command-line-args');
module.exports = class TagCommand extends Command {
constructor(client) {
const i18n = client.i18n.getLocale(client.config.locale);
super(client, {
internal: true,
name: i18n('commands.tag.name'),
description: i18n('commands.tag.description'),
aliases: [
i18n('commands.tag.aliases.faq'),
i18n('commands.tag.aliases.t'),
i18n('commands.tag.aliases.tags'),
],
process_args: false,
args: [
{
name: i18n('commands.tag.args.tag.name'),
description: i18n('commands.tag.args.command.description'),
example: i18n('commands.tag.args.tag.example'),
required: false,
}
]
});
}
/**
* @param {Message} message
* @param {string} args
* @returns {Promise<void|any>}
*/
async execute(message, args) {
const settings = await message.guild.settings;
const i18n = this.client.i18n.getLocale(settings.locale);
const t_row = await this.client.db.models.Ticket.findOne({
where: {
id: message.channel.id
}
});
args = args.split(/\s/g); // convert to an array
const tag_name = args.shift(); // shift the first element
args = args.join(' '); // convert back to a string with the first word removed
if (tag_name && settings.tags[tag_name]) {
const tag = settings.tags[tag_name];
const placeholders = [...tag.matchAll(/(?<!\\){{1,2}\s?([A-Za-z0-9._:]+)\s?(?<!\\)}{1,2}/gi) ].map(p => p[1]);
const requires_ticket = placeholders.some(p => p.startsWith('ticket.'));
if (requires_ticket && !t_row) {
return await message.channel.send(
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.tag.response.not_a_ticket.title'))
.setDescription(i18n('commands.tag.response.not_a_ticket.description'))
.setFooter(settings.footer, message.guild.iconURL())
);
}
let expected = placeholders
.filter(p => p.startsWith(':'))
.map(p => {
return {
name: p.substr(1, p.length),
type: String,
};
});
if (expected.length >= 1) {
try {
args = parseArgs(expected, { argv: argv(args) });
} catch (error) {
return await message.channel.send(
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.tag.response.error'))
.setDescription(`\`\`\`${error.message}\`\`\``)
.setFooter(settings.footer, message.guild.iconURL())
);
}
} else {
args = {};
}
for (const p of expected) {
if (!args[p.name]) {
const list = expected.map(p => `\`${p.name}\``);
return await message.channel.send(
new MessageEmbed()
.setColor(settings.error_colour)
.setTitle(i18n('commands.tag.response.error'))
.setDescription(i18n('commands.tag.response.missing', list.join(', ')))
.setFooter(settings.footer, message.guild.iconURL())
);
}
}
if (requires_ticket) {
args.ticket = t_row.toJSON();
args.ticket.topic = this.client.cryptr.decrypt(args.ticket.topic);
}
const text = tag.replace(/(?<!\\){{1,2}\s?:?([A-Za-z0-9._]+)\s?(?<!\\)}{1,2}/gi, ($, $1) => this.client.i18n.resolve(args, $1));
return await message.channel.send(
new MessageEmbed()
.setColor(settings.colour)
.setDescription(text)
);
} else {
const list = Object.keys(settings.tags).map(t => ` **\`${t}\`**`);
return await message.channel.send(
new MessageEmbed()
.setColor(settings.colour)
.setTitle(i18n('commands.tag.response.list.title'))
.setDescription(list.join('\n'))
.setFooter(settings.footer, message.guild.iconURL())
);
}
}
};

View File

@ -359,6 +359,33 @@
} }
} }
}, },
"tag": {
"aliases": {
"faq": "faq",
"t": "t",
"tags": "tags"
},
"args": {
"tag": {
"description": "The name of the tag to use",
"example": "website",
"name": "tag"
}
},
"description": "Use a tag response",
"name": "tag",
"response": {
"error": "❌ Error",
"list": {
"title": "📃 Tag list"
},
"missing": "This tag requires the following arguments:\n%s",
"not_a_ticket": {
"description": "This tag can only be used within a ticket channel as it uses ticket references.",
"title": "❌ This isn't a ticket channel"
}
}
},
"topic": { "topic": {
"aliases": {}, "aliases": {},
"args": { "args": {

View File

@ -117,7 +117,7 @@ module.exports = class Command {
* Send a message with the command usage * Send a message with the command usage
* @param {TextChannel} channel - The channel to send the message to * @param {TextChannel} channel - The channel to send the message to
* @param {string} [alias] - The command alias * @param {string} [alias] - The command alias
* @returns {Message} * @returns {Promise<Message>}
*/ */
async sendUsage(channel, alias) { async sendUsage(channel, alias) {
const settings = await channel.guild.settings; const settings = await channel.guild.settings;

View File

@ -176,7 +176,7 @@ module.exports = class CommandManager {
} }
} }
} else { } else {
const args_num = raw_args.split(' ').filter(arg => arg.length !== 0).length; // count the number of single-word args were given const args_num = raw_args.split(/\s/g).filter(arg => arg.length !== 0).length; // count the number of single-word args were given
const required_args = cmd.args.reduce((acc, arg) => arg.required ? acc + 1 : acc, 0); // count how many of the args are required const required_args = cmd.args.reduce((acc, arg) => arg.required ? acc + 1 : acc, 0); // count how many of the args are required
if (args_num < required_args) { if (args_num < required_args) {
return await cmd.sendUsage(message.channel, cmd_name); return await cmd.sendUsage(message.channel, cmd_name);