From ce0b7ded080faf6c607754a8dc367019d55d5554 Mon Sep 17 00:00:00 2001 From: Dragory Date: Sat, 22 Dec 2018 13:06:40 +0200 Subject: [PATCH] Message archive formatting tweaks and fixes; only emit deleteBulk event from SavedMessages if any messages were actually marked as deleted --- src/data/GuildArchives.ts | 23 ++++++++++------------- src/data/GuildSavedMessages.ts | 16 ++++++++++++---- src/plugins/Logs.ts | 3 +-- src/plugins/Spam.ts | 7 +++---- src/plugins/Utility.ts | 13 ++++++++++--- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/data/GuildArchives.ts b/src/data/GuildArchives.ts index 1e58ecc0..4539d474 100644 --- a/src/data/GuildArchives.ts +++ b/src/data/GuildArchives.ts @@ -11,10 +11,9 @@ const DEFAULT_EXPIRY_DAYS = 30; const MESSAGE_ARCHIVE_HEADER_FORMAT = trimLines(` Server: {guild.name} ({guild.id}) - Channel: #{channel.name} ({channel.id}) - User: {user.username}#{user.discriminator} ({user.id}) `); -const MESSAGE_ARCHIVE_MESSAGE_FORMAT = "[MSG ID {id}] [{timestamp}] {user.username}: {content}{attachments}"; +const MESSAGE_ARCHIVE_MESSAGE_FORMAT = + "[#{channel.name}] [{user.id}] [{timestamp}] {user.username}#{user.discriminator}: {content}{attachments}"; const MESSAGE_ARCHIVE_FOOTER_FORMAT = trimLines(` Log file generated on {timestamp} Expires at {expires} @@ -65,22 +64,20 @@ export class GuildArchives extends BaseRepository { return result.identifiers[0].id; } - createFromSavedMessages( - savedMessages: SavedMessage[], - guild: Guild, - channel: Channel = null, - user: User = null, - expiresAt = null - ) { + createFromSavedMessages(savedMessages: SavedMessage[], guild: Guild, expiresAt = null) { if (expiresAt == null) expiresAt = moment().add(DEFAULT_EXPIRY_DAYS, "days"); - const headerStr = formatTemplateString(MESSAGE_ARCHIVE_HEADER_FORMAT, { guild, channel, user }); + const headerStr = formatTemplateString(MESSAGE_ARCHIVE_HEADER_FORMAT, { guild }); const msgLines = savedMessages.map(msg => { + const channel = guild.channels.get(msg.channel_id); + const user = { ...msg.data.author, id: msg.user_id }; + return formatTemplateString(MESSAGE_ARCHIVE_MESSAGE_FORMAT, { id: msg.id, - timestamp: moment(msg.posted_at).format("HH:mm:ss"), + timestamp: moment(msg.posted_at).format("YYYY-MM-DD HH:mm:ss"), content: msg.data.content, - user + user, + channel }); }); const messagesStr = msgLines.join("\n"); diff --git a/src/data/GuildSavedMessages.ts b/src/data/GuildSavedMessages.ts index 94cfa249..2c1b03e2 100644 --- a/src/data/GuildSavedMessages.ts +++ b/src/data/GuildSavedMessages.ts @@ -180,23 +180,31 @@ export class GuildSavedMessages extends BaseRepository { this.events.emit("delete", [deleted]); } + /** + * Marks the specified messages as deleted in the database (if they weren't already marked before). + * If any messages were marked as deleted, also emits the deleteBulk event. + */ async markBulkAsDeleted(ids) { + const deletedAt = moment().format("YYYY-MM-DD HH:mm:ss.SSS"); + await this.messages .createQueryBuilder() .update() - .set({ - deleted_at: () => "NOW(3)" - }) + .set({ deleted_at: deletedAt }) .where("guild_id = :guild_id", { guild_id: this.guildId }) .andWhere("id IN (:ids)", { ids }) + .andWhere("deleted_at IS NULL") .execute(); const deleted = await this.messages .createQueryBuilder() .where("id IN (:ids)", { ids }) + .where("deleted_at = :deletedAt", { deletedAt }) .getMany(); - this.events.emit("deleteBulk", [deleted]); + if (deleted.length) { + this.events.emit("deleteBulk", [deleted]); + } } async saveEdit(id, newData: ISavedMessageData) { diff --git a/src/plugins/Logs.ts b/src/plugins/Logs.ts index 02774d5d..e6f8531e 100644 --- a/src/plugins/Logs.ts +++ b/src/plugins/Logs.ts @@ -326,8 +326,7 @@ export class LogsPlugin extends Plugin { // Uses events from savesMessages async onMessageDeleteBulk(savedMessages: SavedMessage[]) { const channel = this.guild.channels.get(savedMessages[0].channel_id); - const user = this.bot.users.get(savedMessages[0].user_id); - const archiveId = await this.archives.createFromSavedMessages(savedMessages, this.guild, channel, user); + const archiveId = await this.archives.createFromSavedMessages(savedMessages, this.guild); const baseUrl = this.knub.getGlobalConfig().url; this.guildLogs.log( diff --git a/src/plugins/Spam.ts b/src/plugins/Spam.ts index 400e3127..07787a76 100644 --- a/src/plugins/Spam.ts +++ b/src/plugins/Spam.ts @@ -157,9 +157,9 @@ export class SpamPlugin extends Plugin { this.recentActions = this.recentActions.filter(action => action.timestamp >= expiryTimestamp); } - async saveSpamArchives(savedMessages: SavedMessage[], channel: Channel, user: User) { + async saveSpamArchives(savedMessages: SavedMessage[], channel: Channel) { const expiresAt = moment().add(SPAM_ARCHIVE_EXPIRY_DAYS, "days"); - const archiveId = await this.archives.createFromSavedMessages(savedMessages, this.guild, channel, user, expiresAt); + const archiveId = await this.archives.createFromSavedMessages(savedMessages, this.guild, expiresAt); const url = this.knub.getGlobalConfig().url; return url ? `${url}/archives/${archiveId}` : `Archive ID: ${archiveId}`; @@ -249,8 +249,7 @@ export class SpamPlugin extends Plugin { // Generate a log from the detected messages const channel = this.guild.channels.get(savedMessage.channel_id); - const user = this.bot.users.get(savedMessage.user_id); - const archiveUrl = await this.saveSpamArchives(uniqueMessages, channel, user); + const archiveUrl = await this.saveSpamArchives(uniqueMessages, channel); // Create a case and log the actions taken above const caseType = spamConfig.mute ? CaseTypes.Mute : CaseTypes.Note; diff --git a/src/plugins/Utility.ts b/src/plugins/Utility.ts index 6d34630e..e2015a90 100644 --- a/src/plugins/Utility.ts +++ b/src/plugins/Utility.ts @@ -140,13 +140,20 @@ export class UtilityPlugin extends ZeppelinPlugin { this.logs.ignoreLog(LogType.MESSAGE_DELETE, savedMessages[0].id); this.logs.ignoreLog(LogType.MESSAGE_DELETE_BULK, savedMessages[0].id); + // Delete & archive in ID order + savedMessages = Array.from(savedMessages).sort((a, b) => (a.id > b.id ? 1 : -1)); const idsToDelete = savedMessages.map(m => m.id); + + // Make sure the deletions aren't double logged + idsToDelete.forEach(id => this.logs.ignoreLog(LogType.MESSAGE_DELETE, id)); + this.logs.ignoreLog(LogType.MESSAGE_DELETE_BULK, idsToDelete[0]); + + // Actually delete the messages await this.bot.deleteMessages(channel.id, idsToDelete); await this.savedMessages.markBulkAsDeleted(idsToDelete); - savedMessages.reverse(); - const user = this.bot.users.get(savedMessages[0].user_id); - const archiveId = await this.archives.createFromSavedMessages(savedMessages, this.guild, channel, user); + // Create an archive + const archiveId = await this.archives.createFromSavedMessages(savedMessages, this.guild); const archiveUrl = `${this.knub.getGlobalConfig().url}/archives/${archiveId}`; this.logs.log(LogType.CLEAN, {