From db94bf696944ba0b9ccf5f430053b5713463f636 Mon Sep 17 00:00:00 2001 From: Isaac Date: Sun, 25 Apr 2021 15:40:07 +0100 Subject: [PATCH] Fixes and improvements for database and other things Also continued to add to ticket creation stuff - now includes opening questions --- src/database/models/category.model.js | 4 +- src/database/models/channel_entity.model.js | 4 +- src/database/models/guild.model.js | 2 +- src/database/models/message.model.js | 6 +- src/database/models/role_entity.model.js | 4 +- src/database/models/survey.model.js | 2 +- src/database/models/survey_response.model.js | 7 +- src/database/models/ticket.model.js | 12 +- src/database/models/user_entity.model.js | 4 +- src/listeners/message.js | 41 +-- src/locales/custom.json | 1 - src/locales/en-GB.json | 15 +- src/modules/commands/manager.js | 21 ++ src/modules/tickets/archives.js | 272 +++++++++++-------- src/modules/tickets/manager.js | 37 ++- src/utils/discord.js | 2 +- 16 files changed, 245 insertions(+), 189 deletions(-) delete mode 100644 src/locales/custom.json diff --git a/src/database/models/category.model.js b/src/database/models/category.model.js index f5667ad..6e5c223 100644 --- a/src/database/models/category.model.js +++ b/src/database/models/category.model.js @@ -3,12 +3,12 @@ module.exports = ({ config }, sequelize) => { const { DB_TABLE_PREFIX } = process.env; sequelize.define('Category', { id: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), primaryKey: true, allowNull: false, }, guild: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, references: { model: DB_TABLE_PREFIX + 'guilds', diff --git a/src/database/models/channel_entity.model.js b/src/database/models/channel_entity.model.js index f14707d..0a4f124 100644 --- a/src/database/models/channel_entity.model.js +++ b/src/database/models/channel_entity.model.js @@ -3,13 +3,13 @@ module.exports = (client, sequelize) => { const { DB_TABLE_PREFIX } = process.env; sequelize.define('ChannelEntity', { channel: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, unique: 'id-ticket' }, name: DataTypes.TEXT, ticket: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, unique: 'id-ticket', references: { diff --git a/src/database/models/guild.model.js b/src/database/models/guild.model.js index 7498179..e76dae0 100644 --- a/src/database/models/guild.model.js +++ b/src/database/models/guild.model.js @@ -3,7 +3,7 @@ module.exports = ({ config }, sequelize) => { const { DB_TABLE_PREFIX } = process.env; sequelize.define('Guild', { id: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), primaryKey: true, allowNull: false, }, diff --git a/src/database/models/message.model.js b/src/database/models/message.model.js index 63c73be..0dc2253 100644 --- a/src/database/models/message.model.js +++ b/src/database/models/message.model.js @@ -3,12 +3,12 @@ module.exports = (client, sequelize) => { const { DB_TABLE_PREFIX } = process.env; sequelize.define('Message', { id: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), primaryKey: true, allowNull: false, }, author: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, }, data: { @@ -24,7 +24,7 @@ module.exports = (client, sequelize) => { defaultValue: false, }, ticket: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, references: { model: DB_TABLE_PREFIX + 'tickets', diff --git a/src/database/models/role_entity.model.js b/src/database/models/role_entity.model.js index 621301e..0fbb9e6 100644 --- a/src/database/models/role_entity.model.js +++ b/src/database/models/role_entity.model.js @@ -8,12 +8,12 @@ module.exports = (client, sequelize) => { }, name: DataTypes.TEXT, role: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, unique: 'id-ticket' }, ticket: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, unique: 'id-ticket', references: { diff --git a/src/database/models/survey.model.js b/src/database/models/survey.model.js index 1e4153e..5e9fa53 100644 --- a/src/database/models/survey.model.js +++ b/src/database/models/survey.model.js @@ -3,7 +3,7 @@ module.exports = (client, sequelize) => { const { DB_TABLE_PREFIX } = process.env; sequelize.define('Survey', { guild: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, references: { model: DB_TABLE_PREFIX + 'guilds', diff --git a/src/database/models/survey_response.model.js b/src/database/models/survey_response.model.js index abaffbc..b0ed174 100644 --- a/src/database/models/survey_response.model.js +++ b/src/database/models/survey_response.model.js @@ -7,17 +7,18 @@ module.exports = (client, sequelize) => { allowNull: true, }, survey: { - type: DataTypes.CHAR(18), + type: DataTypes.INTEGER, allowNull: false, + unique: 'survey-ticket', references: { model: DB_TABLE_PREFIX + 'surveys', key: 'id' }, }, ticket: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, - unique: 'id-ticket', + unique: 'survey-ticket', references: { model: DB_TABLE_PREFIX + 'tickets', key: 'id' diff --git a/src/database/models/ticket.model.js b/src/database/models/ticket.model.js index a87720a..86fd433 100644 --- a/src/database/models/ticket.model.js +++ b/src/database/models/ticket.model.js @@ -3,12 +3,12 @@ module.exports = (client, sequelize) => { const { DB_TABLE_PREFIX } = process.env; sequelize.define('Ticket', { id: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), primaryKey: true, allowNull: false, }, category: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, references: { model: DB_TABLE_PREFIX + 'categories', @@ -16,7 +16,7 @@ module.exports = (client, sequelize) => { }, }, closed_by: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: true, }, closed_reason: { @@ -24,7 +24,7 @@ module.exports = (client, sequelize) => { allowNull: true, }, creator: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, }, first_response: { @@ -32,7 +32,7 @@ module.exports = (client, sequelize) => { allowNull: true, }, guild: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, references: { model: DB_TABLE_PREFIX + 'guilds', @@ -50,7 +50,7 @@ module.exports = (client, sequelize) => { defaultValue: true }, opening_message: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: true, }, topic: { diff --git a/src/database/models/user_entity.model.js b/src/database/models/user_entity.model.js index bb22134..5dfe940 100644 --- a/src/database/models/user_entity.model.js +++ b/src/database/models/user_entity.model.js @@ -8,7 +8,7 @@ module.exports = (client, sequelize) => { discriminator: DataTypes.STRING, display_name: DataTypes.TEXT, ticket: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, unique: 'id-ticket', references: { @@ -17,7 +17,7 @@ module.exports = (client, sequelize) => { }, }, user: { - type: DataTypes.CHAR(18), + type: DataTypes.CHAR(19), allowNull: false, unique: 'id-ticket' }, diff --git a/src/listeners/message.js b/src/listeners/message.js index 7ac8c5e..1b02c7e 100644 --- a/src/listeners/message.js +++ b/src/listeners/message.js @@ -6,40 +6,23 @@ module.exports = { let settings = await message.guild.settings; if (!settings) settings = await message.guild.createSettings(); - let is_blacklisted = false; - if (settings.blacklist.includes(message.author.id)) { - is_blacklisted = true; - client.log.info(`Ignoring blacklisted member ${message.author.tag}`); - } else { - settings.blacklist.forEach(element => { - if (message.guild.roles.cache.has(element) && message.member.roles.cache.has(element)) { - is_blacklisted = true; - client.log.info(`Ignoring member ${message.author.tag} with blacklisted role`); - } - }); - } - - if (is_blacklisted) { - try { - return message.react('❌'); - } catch (error) { - return client.log.debug('Failed to react to a message'); - } - } - - 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({ + let t_row = await client.db.models.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() - }); + if (t_row) { + if (settings.log_messages && !message.system) { + client.tickets.archives.addMessage(message); // add the message to the archives (if it is in a ticket channel) + } + + const ignore = [client.user.id, t_row.creator]; + if (!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 diff --git a/src/locales/custom.json b/src/locales/custom.json deleted file mode 100644 index 9e26dfe..0000000 --- a/src/locales/custom.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/src/locales/en-GB.json b/src/locales/en-GB.json index fb3e9ef..f045068 100644 --- a/src/locales/en-GB.json +++ b/src/locales/en-GB.json @@ -102,6 +102,12 @@ }, "description": "Create a new ticket", "name": "new", + "opening_message": { + "fields": { + "topic": "Topic" + } + }, + "questions": "Please answer the following questions:\n\n%s", "response": { "created": { "title": "✅ Ticket created", @@ -128,14 +134,9 @@ "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." + "title": "Ticket topic", + "description": "Please briefly state what this ticket is about in a a few words." } }, "settings": { diff --git a/src/modules/commands/manager.js b/src/modules/commands/manager.js index ec5f73b..e12c5c8 100644 --- a/src/modules/commands/manager.js +++ b/src/modules/commands/manager.js @@ -61,6 +61,27 @@ module.exports = class CommandManager { * @param {Message} message - Command message */ async handle(message) { + let is_blacklisted = false; + if (settings.blacklist.includes(message.author.id)) { + is_blacklisted = true; + this.client.log.info(`Ignoring blacklisted member ${message.author.tag}`); + } else { + settings.blacklist.forEach(element => { + if (message.guild.roles.cache.has(element) && message.member.roles.cache.has(element)) { + is_blacklisted = true; + this.client.log.info(`Ignoring member ${message.author.tag} with blacklisted role`); + } + }); + } + + if (is_blacklisted) { + try { + return message.react('❌'); + } catch (error) { + return this.client.log.warn('Failed to react to a message'); + } + } + let settings = await message.guild.settings; const i18n = this.client.i18n.get(settings.locale); diff --git a/src/modules/tickets/archives.js b/src/modules/tickets/archives.js index ef0f70d..9586004 100644 --- a/src/modules/tickets/archives.js +++ b/src/modules/tickets/archives.js @@ -17,150 +17,184 @@ module.exports = class TicketArchives { } async addMessage(message) { - let t_row = await this.client.db.models.Ticket.findOne({ - where: { - id: message.channel.id - } - }); + try { + await this.client.db.transaction(async t => { + let t_row = await this.client.db.models.Ticket.findOne({ + where: { + id: message.channel.id + }, + transaction: t + }); - if (t_row) { - await this.client.db.models.Message.create({ - id: message.id, - ticket: t_row.id, - author: message.author.id, - data: this.encrypt(JSON.stringify({ - content: message.content, - // time: message.createdTimestamp, - embeds: message.embeds.map(embed => { - return { embed }; - }), - attachments: [...message.attachments.values()] - })) + if (t_row) { + await this.client.db.models.Message.create({ + id: message.id, + ticket: t_row.id, + author: message.author.id, + data: this.encrypt(JSON.stringify({ + content: message.content, + embeds: message.embeds.map(embed => { + return { embed }; + }), + attachments: [...message.attachments.values()] + })), + createdAt: new Date(message.createdTimestamp) + }, { transaction: t }); + + this.updateEntities(message); + } }); - - this.updateEntities(message); + } catch (e) { + this.client.log.warn('Failed to add a message to the ticket archive'); + this.client.log.error(e); } } async updateMessage(message) { - let m_row = await this.client.db.models.Message.findOne({ - where: { - id: message.id - } - }); + try { + await this.client.db.transaction(async t => { + let m_row = await this.client.db.models.Message.findOne({ + where: { + id: message.id + }, + transaction: t + }); - if (m_row) { - m_row.data = this.encrypt(JSON.stringify({ - content: message.content, - embeds: message.embeds.map(embed => { - return { embed }; - }), - attachments: [...message.attachments.values()] - })); + if (m_row) { + m_row.data = this.encrypt(JSON.stringify({ + content: message.content, + embeds: message.embeds.map(embed => { + return { embed }; + }), + attachments: [...message.attachments.values()] + })); - if (message.editedTimestamp) { - m_row.edited = true; - this.updateEntities(message); - } + if (message.editedTimestamp) { + m_row.edited = true; + this.updateEntities(message); + } - await m_row.save(); // save changes + await m_row.save({ transaction: t }); // save changes + } + }); + } catch (e) { + this.client.log.warn('Failed to update message in the ticket archive'); + this.client.log.error(e); } } async deleteMessage(message) { - let msg = await this.client.db.models.Message.findOne({ - where: { - id: message.id - } - }); + try { + await this.client.db.transaction(async t => { + let msg = await this.client.db.models.Message.findOne({ + where: { + id: message.id + }, + transaction: t + }); - if (msg) { - msg.deleted = true; - await msg.save(); // save changes to message row + if (msg) { + msg.deleted = true; + await msg.save({ transaction: t }); // save changes to message row + } + }); + } catch (e) { + this.client.log.warn('Failed to delete message in ticket archive'); + this.client.log.error(e); } } - async updateEntities(message) { - let m_row = await this.client.db.models.Message.findOne({ - where: { - id: message.id - } - }); + try { + await this.client.db.transaction(async t => { + let m_row = await this.client.db.models.Message.findOne({ + where: { + id: message.id + }, + transaction: t + }); - if (!m_row) return; + if (!m_row) return; - // message author - let u_model_data = { - user: message.author.id, - ticket: message.channel.id - }; - let [u_row] = await this.client.db.models.UserEntity.findOrCreate({ - where: u_model_data, - defaults: u_model_data - }); - await u_row.update({ - avatar: message.author.displayAvatarURL(), - username: this.encrypt(message.author.username), - discriminator: message.author.discriminator, - display_name: this.encrypt(message.member.displayName), - colour: message.member.displayColor === 0 ? null : int2hex(message.member.displayColor), - bot: message.author.bot - }); + // message author + let u_model_data = { + user: message.author.id, + ticket: message.channel.id + }; + let [u_row] = await this.client.db.models.UserEntity.findOrCreate({ + where: u_model_data, + defaults: u_model_data, + transaction: t + }); - // mentioned members - message.mentions.members.forEach(async member => { - let m_model_data = { - user: member.user.id, - ticket: message.channel.id - }; - let [m_row] = await this.client.db.models.UserEntity.findOrCreate({ - where: m_model_data, - defaults: m_model_data - }); + await u_row.update({ + avatar: message.author.displayAvatarURL(), + username: this.encrypt(message.author.username), + discriminator: message.author.discriminator, + display_name: this.encrypt(message.member.displayName), + colour: message.member.displayColor === 0 ? null : int2hex(message.member.displayColor), + bot: message.author.bot + }, { transaction: t }); - await m_row.update({ - avatar: member.user.displayAvatarURL(), - username: this.encrypt(member.user.username), - discriminator: member.user.discriminator, - display_name: this.encrypt(member.displayName), - colour: member.displayColor === 0 ? null : int2hex(member.displayColor), - bot: member.user.bot - }); - }); + // mentioned members + message.mentions.members.forEach(async member => { + let m_model_data = { + user: member.user.id, + ticket: message.channel.id + }; + let [m_row] = await this.client.db.models.UserEntity.findOrCreate({ + where: m_model_data, + defaults: m_model_data, + transaction: t + }); - // mentioned channels - message.mentions.channels.forEach(async channel => { - let c_model_data = { - channel: channel.id, - ticket: message.channel.id - }; - let [c_row] = await this.client.db.models.ChannelEntity.findOrCreate({ - where: c_model_data, - defaults: c_model_data - }); - await c_row.update({ - name: this.encrypt(channel.name) - }); - }); + await m_row.update({ + avatar: member.user.displayAvatarURL(), + username: this.encrypt(member.user.username), + discriminator: member.user.discriminator, + display_name: this.encrypt(member.displayName), + colour: member.displayColor === 0 ? null : int2hex(member.displayColor), + bot: member.user.bot + }, { transaction: t }); + }); - // mentioned roles - message.mentions.roles.forEach(async role => { - let r_model_data = { - role: role.id, - ticket: message.channel.id - }; - let [r_row] = await this.client.db.models.RoleEntity.findOrCreate({ - where: r_model_data, - defaults: r_model_data + // mentioned channels + message.mentions.channels.forEach(async channel => { + let c_model_data = { + channel: channel.id, + ticket: message.channel.id + }; + let [c_row] = await this.client.db.models.ChannelEntity.findOrCreate({ + where: c_model_data, + defaults: c_model_data, + transaction: t + }); + await c_row.update({ + name: this.encrypt(channel.name) + }, { transaction: t }); + }); + + // mentioned roles + message.mentions.roles.forEach(async role => { + let r_model_data = { + role: role.id, + ticket: message.channel.id + }; + let [r_row] = await this.client.db.models.RoleEntity.findOrCreate({ + where: r_model_data, + defaults: r_model_data, + transaction: t + }); + await r_row.update({ + name: this.encrypt(role.name), + colour: role.color === 0 ? '7289DA' : int2hex(role.color) // 7289DA = 7506394 + }, { transaction: t }); + }); }); - await r_row.update({ - name: this.encrypt(role.name), - colour: role.color === 0 ? '7289DA' : int2hex(role.color) // 7289DA = 7506394 - }); - }); - + } catch (e) { + this.client.log.warn('Failed to update message entities in ticket archive'); + this.client.log.error(e); + } } - }; \ No newline at end of file diff --git a/src/modules/tickets/manager.js b/src/modules/tickets/manager.js index 858206b..7f9e2ee 100644 --- a/src/modules/tickets/manager.js +++ b/src/modules/tickets/manager.js @@ -2,6 +2,7 @@ const EventEmitter = require('events'); const TicketArchives = require('./archives'); const { MessageEmbed } = require('discord.js'); const { int2hex } = require('../../utils'); +const { footer } = require('../../utils/discord'); /** Manages tickets */ module.exports = class TicketManager extends EventEmitter { @@ -69,13 +70,17 @@ module.exports = class TicketManager extends EventEmitter { .catch(() => this.client.log.warn('Failed to delete system pin message')); } + let questions = cat_row.opening_questions + .map((q, index) => `**${index + 1}.** ${q}`) + .join('\n\n'); + 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')) + .setTitle('⚠️ ' + i18n('commands.new.request_topic.title')) .setDescription(i18n('commands.new.request_topic.description')) - .setFooter(settings.footer) + .setFooter(footer(settings.footer, i18n('collector_expires_in', 120)), guild.iconURL()) ); const collector_filter = (message) => message.author.id === t_row.creator; @@ -99,17 +104,29 @@ module.exports = class TicketManager extends EventEmitter { .setFooter(settings.footer) ); await message.react('✅'); + collector.stop(); }); - collector.on('end', async (collected) => { - if (collected.size === 0) { - collector_message - .delete() - .catch(() => this.client.log.warn('Failed to delete topic collector message')); - } + collector.on('end', async () => { + collector_message + .delete() + .catch(() => this.client.log.warn('Failed to delete topic collector message')); + await t_channel.send( + new MessageEmbed() + .setColor(settings.colour) + .setDescription(i18n('commands.new.questions', questions)) + .setFooter(settings.footer) + ); }); - - + } else { + if (cat_row.opening_questions.length > 0) { + await t_channel.send( + new MessageEmbed() + .setColor(settings.colour) + .setDescription(i18n('commands.new.questions', questions)) + .setFooter(settings.footer) + ); + } } } diff --git a/src/utils/discord.js b/src/utils/discord.js index b4675f4..8e1216b 100644 --- a/src/utils/discord.js +++ b/src/utils/discord.js @@ -11,7 +11,7 @@ module.exports = { */ footer: (text, additional) => { if (text && additional) return `${text} | ${additional}`; - else return text || additional || ''; + else return additional || text || ''; }, /** * Select a presence from the config