From bb4f872c41c7c5bbdc5e318717b6e5f602799d39 Mon Sep 17 00:00:00 2001 From: Isaac Date: Tue, 18 Oct 2022 17:25:31 +0100 Subject: [PATCH] Archive & log message updates/deletes --- src/i18n/en-GB.yml | 15 +++++++- src/lib/logging.js | 53 +++++++++++++++++++++++++++ src/listeners/client/messageDelete.js | 43 ++++++++++++++++++++-- src/listeners/client/messageUpdate.js | 38 +++++++++++++++++-- 4 files changed, 141 insertions(+), 8 deletions(-) diff --git a/src/i18n/en-GB.yml b/src/i18n/en-GB.yml index aa7adf7..f2eb93f 100644 --- a/src/i18n/en-GB.yml +++ b/src/i18n/en-GB.yml @@ -84,7 +84,9 @@ commands: title: ❌ Error options: category: - description: Close all tickets in the specified category (can be used with `time`) + description: >- + Close all tickets in the specified category (can be used with + `time`) name: category reason: description: The reason for closing the ticket(s) @@ -93,7 +95,9 @@ commands: description: The ticket to close name: ticket time: - description: Close all tickets that have been inactive for the specified time (can be used with `category`) + description: >- + Close all tickets that have been inactive for the specified time + (can be used with `category`) name: time help: description: Show the help menu @@ -213,6 +217,13 @@ log: create: created delete: deleted update: updated + message: + description: "{user} {verb} a message" + message: Message + title: Message {verb} + verb: + delete: deleted + update: updated ticket: description: "{user} {verb} a ticket" ticket: Ticket diff --git a/src/lib/logging.js b/src/lib/logging.js index 2be4d98..5c5af8f 100644 --- a/src/lib/logging.js +++ b/src/lib/logging.js @@ -183,8 +183,61 @@ async function logTicketEvent(client, { return await channel.send({ embeds }); } +/** + * @param {import("client")} client + * @param {object} details + * @param {string} details.action + * @param {import("discord.js").Message} details.target + * @param {import("@prisma/client").Ticket & {guild: import("@prisma/client").Guild}} details.ticket +*/ +async function logMessageEvent(client, { + action, target, ticket, diff, +}) { + if (!ticket) return; + client.log.info.tickets(`${target.member.user.tag} ${client.i18n.getMessage('en-GB', `log.message.verb.${action}`)} message ${target.id}`); + if (!ticket.guild.logChannel) return; + const colour = action === 'update' + ? 'Purple' : action === 'delete' + ? 'DarkPurple' : 'Default'; + const getMessage = client.i18n.getLocale(ticket.guild.locale); + const i18nOptions = { + user: `<@${target.member.user.id}>`, + verb: getMessage(`log.message.verb.${action}`), + }; + const channel = client.channels.cache.get(ticket.guild.logChannel); + if (!channel) return; + const embeds = [ + new EmbedBuilder() + .setColor(colour) + .setAuthor({ + iconURL: target.member.displayAvatarURL(), + name: target.member.displayName, + }) + .setTitle(getMessage('log.message.title', i18nOptions)) + .setDescription(getMessage('log.message.description', i18nOptions)) + .addFields([ + { + name: getMessage('log.message.message'), + value: `[${target.id}](${target.url})`, + }, + ]), + ]; + + if (diff && diff.original) { + embeds.push( + new EmbedBuilder() + .setColor(colour) + .setTitle(getMessage('log.admin.changes')) + .setFields(makeDiff(diff)), + ); + } + + return await channel.send({ embeds }); +} + module.exports = { getLogChannel, logAdminEvent, + logMessageEvent, logTicketEvent, }; \ No newline at end of file diff --git a/src/listeners/client/messageDelete.js b/src/listeners/client/messageDelete.js index a6dd3dc..1d307a6 100644 --- a/src/listeners/client/messageDelete.js +++ b/src/listeners/client/messageDelete.js @@ -1,4 +1,5 @@ const { Listener } = require('@eartharoid/dbf'); +const { logMessageEvent } = require('../../lib/logging'); module.exports = class extends Listener { constructor(client, options) { @@ -9,8 +10,44 @@ module.exports = class extends Listener { }); } - run(message) { - // TODO: archive messages in tickets - // TODO: log channel + /** + * @param {import("discord.js").Message} oldMessage + * @param {import("discord.js").Message} message + */ + async run(message) { + /** @type {import("client")} */ + const client = this.client; + + if (message.partial) message.fetch().then(m => (message = m)).catch(client.log.error); + const ticket = await client.prisma.ticket.findUnique({ + include: { guild: true }, + where: { id: message.channel.id }, + }); + if (!ticket) return; + + if (ticket.guild.archive) { + try { + const archived = await client.prisma.archivedMessage.findUnique({ where: { id: message.id } }); + if (archived) { + await client.prisma.archivedMessage.update({ + data: { deleted: true }, + where: { id: message.id }, + }); + } + } catch (error) { + client.log.warn('Failed to "delete" archived message', message.id); + client.log.error(error); + } + } + + await logMessageEvent(this.client, { + action: 'delete', + diff: { + original: { content: message.cleanContent }, + updated: { content: '' }, + }, + target: message, + ticket, + }); } }; diff --git a/src/listeners/client/messageUpdate.js b/src/listeners/client/messageUpdate.js index 6792eb6..4239cb6 100644 --- a/src/listeners/client/messageUpdate.js +++ b/src/listeners/client/messageUpdate.js @@ -1,4 +1,5 @@ const { Listener } = require('@eartharoid/dbf'); +const { logMessageEvent } = require('../../lib/logging'); module.exports = class extends Listener { constructor(client, options) { @@ -9,8 +10,39 @@ module.exports = class extends Listener { }); } - run(oldMessage, newMessage) { - // TODO: archive messages in tickets - // TODO: log channel + + /** + * @param {import("discord.js").Message} oldMessage + * @param {import("discord.js").Message} newMessage + */ + async run(oldMessage, newMessage) { + /** @type {import("client")} */ + const client = this.client; + + if (newMessage.partial) newMessage.fetch().then(m => (newMessage = m)).catch(client.log.error); + const ticket = await client.prisma.ticket.findUnique({ + include: { guild: true }, + where: { id: newMessage.channel.id }, + }); + if (!ticket) return; + + if (ticket.guild.archive) { + try { + await client.tickets.archiver.saveMessage(ticket.id, newMessage); + } catch (error) { + client.log.warn('Failed to update archived message', newMessage.id); + client.log.error(error); + } + } + + await logMessageEvent(this.client, { + action: 'update', + diff: { + original: { content: oldMessage.cleanContent }, + updated: { content: newMessage.cleanContent }, + }, + target: newMessage, + ticket, + }); } };