From a7248d88ead7fc379b001d1dd5302d3dd33bbfdd Mon Sep 17 00:00:00 2001 From: Isaac Date: Mon, 3 May 2021 16:30:52 +0100 Subject: [PATCH] Database things, pinned messages, start on ticket claiming --- src/commands/blacklist.js | 2 +- src/commands/close.js | 2 +- src/commands/new.js | 2 +- src/commands/settings.js | 3 + src/commands/transfer.js | 31 +++++++++++ src/database/index.js | 1 + src/database/models/category.model.js | 4 ++ src/database/models/ticket.model.js | 8 +++ src/listeners/messageReactionAdd.js | 24 ++++++++ src/locales/en-GB.json | 15 ++++- src/modules/tickets/archives.js | 79 +++++++++++++++++++-------- src/modules/tickets/manager.js | 39 ++++++++----- src/structures/guild_member.js | 8 +-- 13 files changed, 169 insertions(+), 49 deletions(-) create mode 100644 src/commands/transfer.js diff --git a/src/commands/blacklist.js b/src/commands/blacklist.js index 990fde4..26fab2d 100644 --- a/src/commands/blacklist.js +++ b/src/commands/blacklist.js @@ -1,5 +1,5 @@ -const { MessageEmbed } = require('discord.js'); const Command = require('../modules/commands/command'); +const { MessageEmbed } = require('discord.js'); module.exports = class BlacklistCommand extends Command { constructor(client) { diff --git a/src/commands/close.js b/src/commands/close.js index bb1b932..3b697fb 100644 --- a/src/commands/close.js +++ b/src/commands/close.js @@ -1,5 +1,5 @@ -const { MessageEmbed } = require('discord.js'); const Command = require('../modules/commands/command'); +const { MessageEmbed } = require('discord.js'); const { footer } = require('../utils/discord'); module.exports = class CloseCommand extends Command { diff --git a/src/commands/new.js b/src/commands/new.js index 2399a68..bff28c5 100644 --- a/src/commands/new.js +++ b/src/commands/new.js @@ -1,5 +1,5 @@ -const { MessageEmbed } = require('discord.js'); const Command = require('../modules/commands/command'); +const { MessageEmbed } = require('discord.js'); const { footer } = require('../utils/discord'); const { letters } = require('../utils/emoji'); const { wait } = require('../utils'); diff --git a/src/commands/settings.js b/src/commands/settings.js index 2cbd130..6806926 100644 --- a/src/commands/settings.js +++ b/src/commands/settings.js @@ -46,6 +46,7 @@ module.exports = class SettingsCommand extends Command { id: c.id } }); + cat_row.claiming = c.claiming; cat_row.image = c.image; cat_row.max_per_member = c.max_per_member; cat_row.name = c.name; @@ -103,6 +104,7 @@ module.exports = class SettingsCommand extends Command { await this.client.db.models.Category.create({ id: cat_channel.id, + claiming: c.claiming, guild: message.guild.id, image: c.image, max_per_member: c.max_per_member, @@ -154,6 +156,7 @@ module.exports = class SettingsCommand extends Command { categories: categories.map(c => { return { id: c.id, + claiming: c.claiming, image: c.image, max_per_member: c.max_per_member, name: c.name, diff --git a/src/commands/transfer.js b/src/commands/transfer.js new file mode 100644 index 0000000..09cdd96 --- /dev/null +++ b/src/commands/transfer.js @@ -0,0 +1,31 @@ +const Command = require('../modules/commands/command'); +const { MessageEmbed } = require('discord.js'); +const { footer } = require('../utils/discord'); + +module.exports = class TransferCommand extends Command { + constructor(client) { + const i18n = client.i18n.getLocale(client.config.locale); + super(client, { + internal: true, + name: i18n('commands.transfer.name'), + description: i18n('commands.transfer.description'), + aliases: [], + process_args: false, + args: [ + { + name: i18n('commands.transfer.args.member.name'), + description: i18n('commands.transfer.args.member.description'), + example: i18n('commands.transfer.args.member.example'), + required: false, + } + ] + }); + } + + async execute(message, args) { + + let settings = await message.guild.settings; + const i18n = this.client.i18n.getLocale(settings.locale); + + } +}; \ No newline at end of file diff --git a/src/database/index.js b/src/database/index.js index 30110f1..08142d9 100644 --- a/src/database/index.js +++ b/src/database/index.js @@ -39,6 +39,7 @@ module.exports = async (client) => { storage: path('./user/database.sqlite'), logging: text => client.log.debug(text) }); + client.log.warn('SQLite is not sufficient for a production environment if you want to use ticket archives. You should disable "log_messages" in your servers\' settings or use a different database.'); } else { client.log.info(`Connecting to ${types[type].name} database...`); sequelize = new Sequelize(DB_NAME, DB_USER, DB_PASS, { diff --git a/src/database/models/category.model.js b/src/database/models/category.model.js index 6e5c223..4bd4533 100644 --- a/src/database/models/category.model.js +++ b/src/database/models/category.model.js @@ -7,6 +7,10 @@ module.exports = ({ config }, sequelize) => { primaryKey: true, allowNull: false, }, + claiming: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, guild: { type: DataTypes.CHAR(19), allowNull: false, diff --git a/src/database/models/ticket.model.js b/src/database/models/ticket.model.js index 86fd433..41857e6 100644 --- a/src/database/models/ticket.model.js +++ b/src/database/models/ticket.model.js @@ -15,6 +15,10 @@ module.exports = (client, sequelize) => { key: 'id' }, }, + claimed_by: { + type: DataTypes.CHAR(19), + allowNull: true, + }, closed_by: { type: DataTypes.CHAR(19), allowNull: true, @@ -53,6 +57,10 @@ module.exports = (client, sequelize) => { type: DataTypes.CHAR(19), allowNull: true, }, + pinned_messages: { + type: DataTypes.JSON, + defaultValue: [] + }, topic: { type: DataTypes.TEXT, allowNull: true, diff --git a/src/listeners/messageReactionAdd.js b/src/listeners/messageReactionAdd.js index 4ee812e..9ef50ee 100644 --- a/src/listeners/messageReactionAdd.js +++ b/src/listeners/messageReactionAdd.js @@ -1,11 +1,19 @@ module.exports = { event: 'messageReactionAdd', execute: async (client, r, u) => { + if (r.partial) { + r = await r.fetch(); + } + + if (u.id === client.user.id) return; + const guild = r.message.guild; if (!guild) return; let settings = await guild.settings; if (!settings) settings = await guild.createSettings(); + + let member = await guild.members.fetch(u.id); if (settings.blacklist.includes(u.id)) { return client.log.info(`Ignoring blacklisted member ${u.tag}`); @@ -17,6 +25,22 @@ module.exports = { } }); } + let t_row = await client.db.models.Ticket.findOne({ + where: { + id: r.message.channel.id + } + }); + client.log.info('got t row') + if (t_row) { + if ( + t_row.opening_message === r.message.id + && r.emoji.name === '🙌' + && await member.isStaff() + ) { + // ticket claiming + client.log.info('claimed') + } + } } }; \ No newline at end of file diff --git a/src/locales/en-GB.json b/src/locales/en-GB.json index c2a93a4..0055ad5 100644 --- a/src/locales/en-GB.json +++ b/src/locales/en-GB.json @@ -25,7 +25,7 @@ "member_or_role": { "name": "memberOrRole", "description": "A member mention, a role mention, or the ID of a member or role", - "example": "@naughty-member" + "example": "@NaughtyMember" } }, "description": "Blacklist/unblacklist a member from interacting with the bot", @@ -152,6 +152,19 @@ "response": { "updated": "✅ Settings have been updated." } + }, + "transfer": { + "aliases": {}, + "args": { + "member": { + "description": "A member mention or the ID of the member to transfer the ticket to", + "example": "@StaffMember", + "name": "member" + } + }, + "description": "Transfer a ticket to another staff member", + "name": "transfer", + "response": {} } }, "command_execution_error": { diff --git a/src/modules/tickets/archives.js b/src/modules/tickets/archives.js index 9586004..159930d 100644 --- a/src/modules/tickets/archives.js +++ b/src/modules/tickets/archives.js @@ -105,22 +105,23 @@ module.exports = class TicketArchives { } async updateEntities(message) { + + let m_row = await this.client.db.models.Message.findOne({ + where: { + id: message.id + } + }); + + if (!m_row) return; + + // message author 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; - - // message author + await this.client.db.transaction(async t => { 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, @@ -136,8 +137,17 @@ module.exports = class TicketArchives { bot: message.author.bot }, { transaction: t }); - // mentioned members - message.mentions.members.forEach(async member => { + return u_row; + }); + } catch (e) { + this.client.log.warn('Failed to update message author entity in ticket archive'); + this.client.log.error(e); + } + + // mentioned members + message.mentions.members.forEach(async member => { + try { + await this.client.db.transaction(async t => { let m_model_data = { user: member.user.id, ticket: message.channel.id @@ -156,10 +166,19 @@ module.exports = class TicketArchives { colour: member.displayColor === 0 ? null : int2hex(member.displayColor), bot: member.user.bot }, { transaction: t }); - }); - // mentioned channels - message.mentions.channels.forEach(async channel => { + return m_row; + }); + } catch (e) { + this.client.log.warn('Failed to update mentioned members entities in ticket archive'); + this.client.log.error(e); + } + }); + + // mentioned channels + message.mentions.channels.forEach(async channel => { + try { + await this.client.db.transaction(async t => { let c_model_data = { channel: channel.id, ticket: message.channel.id @@ -172,10 +191,19 @@ module.exports = class TicketArchives { await c_row.update({ name: this.encrypt(channel.name) }, { transaction: t }); - }); - // mentioned roles - message.mentions.roles.forEach(async role => { + return c_row; + }); + } catch (e) { + this.client.log.warn('Failed to update mentioned channels entities in ticket archive'); + this.client.log.error(e); + } + }); + + // mentioned roles + message.mentions.roles.forEach(async role => { + try { + await this.client.db.transaction(async t => { let r_model_data = { role: role.id, ticket: message.channel.id @@ -189,12 +217,15 @@ module.exports = class TicketArchives { name: this.encrypt(role.name), colour: role.color === 0 ? '7289DA' : int2hex(role.color) // 7289DA = 7506394 }, { transaction: t }); + + return r_row; }); - }); - } catch (e) { - this.client.log.warn('Failed to update message entities in ticket archive'); - this.client.log.error(e); - } + } catch (e) { + this.client.log.warn('Failed to update mentioned roles 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 a934ebb..32e556f 100644 --- a/src/modules/tickets/manager.js +++ b/src/modules/tickets/manager.js @@ -23,8 +23,8 @@ module.exports = class TicketManager extends EventEmitter { /** * Handle post-creation tasks - * @param {*} t_row - * @param {*} cat_row + * @param {Model} t_row + * @param {Model} cat_row */ async postCreate(t_row, cat_row) { @@ -70,10 +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.claiming) { + await sent.react('🙌'); + } + let questions; + if (cat_row.opening_questions) { + 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() @@ -111,15 +118,17 @@ module.exports = class TicketManager extends EventEmitter { 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) - ); + if (cat_row.opening_questions) { + 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) { + if (cat_row.opening_questions) { await t_channel.send( new MessageEmbed() .setColor(settings.colour) @@ -280,13 +289,15 @@ module.exports = class TicketManager extends EventEmitter { } this.client.log.info(`A ticket was closed (${ticket_id})${reason ? `: "${reason}"` : ''}`); - } + let pinned = await channel.messages.fetchPinned(); + await t_row.update({ open: false, closed_by: closer_id || null, - closed_reason: reason || null + closed_reason: reason || null, + pinned: [ ...pinned.keys() ] }); this.emit('close', ticket_id); diff --git a/src/structures/guild_member.js b/src/structures/guild_member.js index 7f913cc..1d31cd5 100644 --- a/src/structures/guild_member.js +++ b/src/structures/guild_member.js @@ -12,14 +12,8 @@ Structures.extend('GuildMember', GuildMember => { guild: this.guild.id } }); - - guild_categories.forEach(cat => { - cat.roles.forEach(r => { - if (this.roles.cache.has(r)) return true; - }); - }); - return false; + return guild_categories.some(cat => cat.roles.some(r => this.roles.cache.has(r))); } };