From 674f29b4032c74e33abc0a21e8537d9c9cd09223 Mon Sep 17 00:00:00 2001 From: Isaac Date: Sat, 24 Apr 2021 23:49:17 +0100 Subject: [PATCH] Ticket creation --- src/commands/settings.js | 23 +++--- src/database/models/category.model.js | 2 +- src/database/models/ticket.model.js | 8 ++ src/listeners/guildMemberRemove.js | 2 +- src/listeners/message.js | 13 +++ src/locales/en-GB.json | 9 +++ src/modules/tickets/manager.js | 112 ++++++++++++++++++++++++-- 7 files changed, 151 insertions(+), 18 deletions(-) diff --git a/src/commands/settings.js b/src/commands/settings.js index 5ac0a98..cfd5521 100644 --- a/src/commands/settings.js +++ b/src/commands/settings.js @@ -59,16 +59,18 @@ module.exports = class SettingsCommand extends Command { let cat_channel = await this.client.channels.fetch(c.id); - if (cat_channel.name !== c.name) - await cat_channel.setName(c.name, `Tickets category updated by ${message.member.user.tag}`); + if (cat_channel) { + if (cat_channel.name !== c.name) + await cat_channel.setName(c.name, `Tickets category updated by ${message.member.user.tag}`); - for (let r of c.roles) { - await cat_channel.updateOverwrite(r, { - VIEW_CHANNEL: true, - READ_MESSAGE_HISTORY: true, - SEND_MESSAGES: true, - ATTACH_FILES: true - }, `Tickets category updated by ${message.member.user.tag}`); + for (let r of c.roles) { + await cat_channel.updateOverwrite(r, { + VIEW_CHANNEL: true, + READ_MESSAGE_HISTORY: true, + SEND_MESSAGES: true, + ATTACH_FILES: true + }, `Tickets category updated by ${message.member.user.tag}`); + } } } else { @@ -174,7 +176,8 @@ module.exports = class SettingsCommand extends Command { }; for (let survey in surveys) { - data.surveys[surveys[survey].name] = surveys[survey].questions; + const { name, questions } = surveys[survey]; + data.surveys[name] = questions; } let attachment = new MessageAttachment( diff --git a/src/database/models/category.model.js b/src/database/models/category.model.js index c984a48..f5667ad 100644 --- a/src/database/models/category.model.js +++ b/src/database/models/category.model.js @@ -44,7 +44,7 @@ module.exports = ({ config }, sequelize) => { }, require_topic: { type: DataTypes.BOOLEAN, - defaultValue: true, + defaultValue: false, }, roles: { type: DataTypes.JSON, diff --git a/src/database/models/ticket.model.js b/src/database/models/ticket.model.js index 1ca4461..a87720a 100644 --- a/src/database/models/ticket.model.js +++ b/src/database/models/ticket.model.js @@ -19,6 +19,10 @@ module.exports = (client, sequelize) => { type: DataTypes.CHAR(18), allowNull: true, }, + closed_reason: { + type: DataTypes.STRING, + allowNull: true, + }, creator: { type: DataTypes.CHAR(18), allowNull: false, @@ -45,6 +49,10 @@ module.exports = (client, sequelize) => { type: DataTypes.BOOLEAN, defaultValue: true }, + opening_message: { + type: DataTypes.CHAR(18), + allowNull: true, + }, topic: { type: DataTypes.TEXT, allowNull: true, diff --git a/src/listeners/guildMemberRemove.js b/src/listeners/guildMemberRemove.js index 94231f9..03cafa1 100644 --- a/src/listeners/guildMemberRemove.js +++ b/src/listeners/guildMemberRemove.js @@ -9,7 +9,7 @@ module.exports = { }); for (let ticket of tickets.rows) { - client.tickets.close(ticket.id, null, member.guild.id, 'Member left the guild'); + await client.tickets.close(ticket.id, null, member.guild.id, 'Member left the guild'); } client.log.info(`Closed ${tickets.count} ticket(s) belonging to ${member.user.tag} who left "${member.guild.name}"`); diff --git a/src/listeners/message.js b/src/listeners/message.js index 30fcaaa..7ac8c5e 100644 --- a/src/listeners/message.js +++ b/src/listeners/message.js @@ -29,6 +29,19 @@ module.exports = { if (settings.log_messages && !message.system) client.tickets.archives.addMessage(message); // add the message to the archives (if it is in a ticket channel) + let t_row = await client.db.Ticket.findOne({ + where: { + id: message.channel.id + } + }); + + const ignore = [client.user.id, t_row.creator]; + if (t_row && !t_row.first_response && !ignore.includes(message.author.id)) { + t_row.update({ + first_response: new Date() + }); + } + client.commands.handle(message); // pass the message to the command handler } }; \ No newline at end of file diff --git a/src/locales/en-GB.json b/src/locales/en-GB.json index 97e3444..fb3e9ef 100644 --- a/src/locales/en-GB.json +++ b/src/locales/en-GB.json @@ -127,6 +127,15 @@ "title": "❌ Reaction time expired", "description": "You took too long to select the ticket category." } + }, + "opening_message": { + "fields": { + "topic": "Topic" + } + }, + "request_topic": { + "title": "⚠️ Ticket topic", + "description": "Please briefly state what this ticket is about in a short sentence." } }, "settings": { diff --git a/src/modules/tickets/manager.js b/src/modules/tickets/manager.js index 70fb21e..858206b 100644 --- a/src/modules/tickets/manager.js +++ b/src/modules/tickets/manager.js @@ -20,6 +20,99 @@ module.exports = class TicketManager extends EventEmitter { this.archives = new TicketArchives(this.client); } + /** + * Handle post-creation tasks + * @param {*} t_row + * @param {*} cat_row + */ + async postCreate(t_row, cat_row) { + + let guild = this.client.guilds.cache.get(cat_row.guild); + let settings = await guild.settings; + const i18n = this.client.i18n.get(settings.locale); + let member = guild.members.cache.get(t_row.creator); + let t_channel = this.client.channels.cache.get(t_row.id); + + let topic = t_row.topic + ? this.client.cryptr.decrypt(t_row.topic) + : ''; + + await t_channel.send(member.user.toString()); + + if (cat_row.image) { + await t_channel.send(cat_row.image); + } + + let description = cat_row.opening_message + .replace(/{+\s?(user)?name\s?}+/gi, member.displayName) + .replace(/{+\s?(tag|ping|mention)?\s?}+/gi, member.user.toString()); + let embed = new MessageEmbed() + .setColor(settings.colour) + .setAuthor(member.user.username, member.user.displayAvatarURL()) + .setDescription(description) + .setFooter(settings.footer); + + if (topic) embed.addField(i18n('commands.new.opening_message.fields.topic'), topic); + + let sent = await t_channel.send(embed); + await sent.pin({ reason: 'Ticket opening message' }); + + await t_row.update({ + opening_message: sent.id + }); + + let pinned = t_channel.messages.cache.last(); + + if (pinned.system) { + pinned + .delete({ reason: 'Cleaning up system message' }) + .catch(() => this.client.log.warn('Failed to delete system pin message')); + } + + if (cat_row.require_topic && topic.length === 0) { + let collector_message = await t_channel.send( + new MessageEmbed() + .setColor(settings.colour) + .setTitle(i18n('commands.new.request_topic.title')) + .setDescription(i18n('commands.new.request_topic.description')) + .setFooter(settings.footer) + ); + + const collector_filter = (message) => message.author.id === t_row.creator; + + let collector = t_channel.createMessageCollector(collector_filter, { + time: 120000 + }); + + collector.on('collect', async (message) => { + topic = message.content; + await t_row.update({ + topic: this.client.cryptr.encrypt(topic) + }); + await t_channel.setTopic(`${member} | ${topic}`, { reason: 'User updated ticket topic' }); + await sent.edit( + new MessageEmbed() + .setColor(settings.colour) + .setAuthor(member.user.username, member.user.displayAvatarURL()) + .setDescription(description) + .addField(i18n('commands.new.opening_message.fields.topic'), topic) + .setFooter(settings.footer) + ); + await message.react('✅'); + }); + + collector.on('end', async (collected) => { + if (collected.size === 0) { + collector_message + .delete() + .catch(() => this.client.log.warn('Failed to delete topic collector message')); + } + }); + + + } + } + /** * Create a new ticket * @param {string} guild_id - ID of the guild to create the ticket in @@ -45,7 +138,7 @@ module.exports = class TicketManager extends EventEmitter { } })) + 1; - let guild = await this.client.guilds.cache.get(guild_id); + let guild = this.client.guilds.cache.get(guild_id); let member = await guild.members.fetch(creator_id); let name = cat_row.name_format .replace(/{+\s?(user)?name\s?}+/gi, member.displayName) @@ -58,7 +151,7 @@ module.exports = class TicketManager extends EventEmitter { reason: `${member.user.tag} requested a new ticket channel` }); - await t_channel.updateOverwrite(creator_id, { + t_channel.updateOverwrite(creator_id, { VIEW_CHANNEL: true, READ_MESSAGE_HISTORY: true, SEND_MESSAGES: true, @@ -71,12 +164,15 @@ module.exports = class TicketManager extends EventEmitter { guild: guild_id, category: category_id, creator: creator_id, - topic: this.client.cryptr.encrypt(topic) + topic: topic.length === 0 ? null : this.client.cryptr.encrypt(topic) }); this.client.log.info(`${member.user.tag} created a new ticket in "${guild.name}"`); this.emit('create', t_row.id, creator_id); + + this.postCreate(t_row, cat_row); + return t_row; } @@ -136,8 +232,10 @@ module.exports = class TicketManager extends EventEmitter { await channel.send( new MessageEmbed() .setColor(settings.success_colour) + .setAuthor(member.user.username, member.user.displayAvatarURL()) .setTitle(i18n('commands.close.response.closed.title')) .setDescription(description) + .setFooter(settings.footer) ); setTimeout(async () => { @@ -156,6 +254,7 @@ module.exports = class TicketManager extends EventEmitter { .setColor(settings.success_colour) .setTitle(i18n('commands.close.response.closed.title')) .setDescription(description) + .setFooter(settings.footer) ); setTimeout(async () => { @@ -169,8 +268,8 @@ module.exports = class TicketManager extends EventEmitter { await t_row.update({ open: false, - closed_by: closer_id, - reason: reason + closed_by: closer_id || null, + closed_reason: reason || null }); this.emit('close', ticket_id); @@ -190,7 +289,8 @@ module.exports = class TicketManager extends EventEmitter { guild_id } }); - ticket_id = t_row?.id; + if (!t_row) return null; + ticket_id = t_row.id; } let t_row = await this.client.db.models.Ticket.findOne({