From 926d062d9e879ee3d8897f377f45c5f7f54b6ae6 Mon Sep 17 00:00:00 2001 From: Cynthia Foxwell Date: Wed, 23 Apr 2025 22:52:31 -0600 Subject: [PATCH] logging: thread create/delete, try catch --- src/modules/logging.js | 337 +++++++++++++++++++++++++++-------------- 1 file changed, 226 insertions(+), 111 deletions(-) diff --git a/src/modules/logging.js b/src/modules/logging.js index ea6ec42..1c25c5c 100644 --- a/src/modules/logging.js +++ b/src/modules/logging.js @@ -1,5 +1,6 @@ -const {Member} = require("@projectdysnomia/dysnomia"); +const {Member, PrivateThreadChannel} = require("@projectdysnomia/dysnomia"); +const logger = require("#lib/logger.js"); const {getGuildData} = require("#lib/guildData.js"); const events = require("#lib/events.js"); @@ -17,50 +18,236 @@ async function getLoggingChannel(guild) { return guild.channels.get(channelId) ?? guild.threads.get(channelId); } +const WHITELISTED_EVENTS = new Set([ + "GUILD_UPDATE", + "CHANNEL_CREATE", + "CHANNEL_UPDATE", + "CHANNEL_DELETE", + "CHANNEL_OVERWRITE_CREATE", + "CHANNEL_OVERWRITE_UPDATE", + "CHANNEL_OVERWRITE_DELETE", + "MEMBER_KICK", + "MEMBER_BAN_ADD", + "MEMBER_BAN_REMOVE", + "MEMBER_UPDATE", + "BOT_ADD", + "ROLE_CREATE", + "ROLE_UPDATE", + "ROLE_DELETE", + "INVITE_CREATE", + "INVITE_UPDATE", + "INVITE_DELETE", + "EMOJI_CREATE", + "EMOJI_UPDATE", + "EMOJI_DELETE", + "INTEGRATION_CREATE", + "INTEGRATION_UPDATE", + "INTEGRATION_DELETE", + "STICKER_CREATE", + "STICKER_UPDATE", + "STICKER_DELETE", + "GUILD_SCHEDULED_EVENT_CREATE", + "GUILD_SCHEDULED_EVENT_UPDATE", + "GUILD_SCHEDULED_EVENT_DELETE", + "APPLICATION_COMMAND_PERMISSION_UPDATE", + "ONBOARDING_PROMPT_CREATE", + "ONBOARDING_PROMPT_UPDATE", + "ONBOARDING_PROMPT_DELETE", + "MEMBER_ROLE_UPDATE", + "THREAD_CREATE", + "THREAD_UPDATE", + "THREAD_DELETE", +]); + events.add("guildAuditLogEntryCreate", "logging", async function (entry) { const channel = await getLoggingChannel(entry.guild); if (!channel) return; - switch (entry.actionType) { - case AuditLogActions.GUILD_UPDATE: - case AuditLogActions.CHANNEL_CREATE: - case AuditLogActions.CHANNEL_UPDATE: - case AuditLogActions.CHANNEL_DELETE: - case AuditLogActions.CHANNEL_OVERWRITE_CREATE: - case AuditLogActions.CHANNEL_OVERWRITE_UPDATE: - case AuditLogActions.CHANNEL_OVERWRITE_DELETE: - case AuditLogActions.MEMBER_KICK: - case AuditLogActions.MEMBER_BAN_ADD: - case AuditLogActions.MEMBER_BAN_REMOVE: - case AuditLogActions.MEMBER_UPDATE: - case AuditLogActions.BOT_ADD: - case AuditLogActions.ROLE_CREATE: - case AuditLogActions.ROLE_UPDATE: - case AuditLogActions.ROLE_DELETE: - case AuditLogActions.INVITE_CREATE: - case AuditLogActions.INVITE_UPDATE: - case AuditLogActions.INVITE_DELETE: - case AuditLogActions.EMOJI_CREATE: - case AuditLogActions.EMOJI_UPDATE: - case AuditLogActions.EMOJI_DELETE: - case AuditLogActions.INTEGRATION_CREATE: - case AuditLogActions.INTEGRATION_UPDATE: - case AuditLogActions.INTEGRATION_DELETE: - case AuditLogActions.STICKER_CREATE: - case AuditLogActions.STICKER_UPDATE: - case AuditLogActions.STICKER_DELETE: - case AuditLogActions.GUILD_SCHEDULED_EVENT_CREATE: - case AuditLogActions.GUILD_SCHEDULED_EVENT_UPDATE: - case AuditLogActions.GUILD_SCHEDULED_EVENT_DELETE: - case AuditLogActions.THREAD_CREATE: - case AuditLogActions.THREAD_DELETE: - case AuditLogActions.APPLICATION_COMMAND_PERMISSION_UPDATE: - case AuditLogActions.ONBOARDING_PROMPT_CREATE: - case AuditLogActions.ONBOARDING_PROMPT_UPDATE: - case AuditLogActions.ONBOARDING_PROMPT_DELETE: { + try { + switch (entry.actionType) { + case AuditLogActions.GUILD_UPDATE: + case AuditLogActions.CHANNEL_CREATE: + case AuditLogActions.CHANNEL_UPDATE: + case AuditLogActions.CHANNEL_DELETE: + case AuditLogActions.CHANNEL_OVERWRITE_CREATE: + case AuditLogActions.CHANNEL_OVERWRITE_UPDATE: + case AuditLogActions.CHANNEL_OVERWRITE_DELETE: + case AuditLogActions.MEMBER_KICK: + case AuditLogActions.MEMBER_BAN_ADD: + case AuditLogActions.MEMBER_BAN_REMOVE: + case AuditLogActions.MEMBER_UPDATE: + case AuditLogActions.BOT_ADD: + case AuditLogActions.ROLE_CREATE: + case AuditLogActions.ROLE_UPDATE: + case AuditLogActions.ROLE_DELETE: + case AuditLogActions.INVITE_CREATE: + case AuditLogActions.INVITE_UPDATE: + case AuditLogActions.INVITE_DELETE: + case AuditLogActions.EMOJI_CREATE: + case AuditLogActions.EMOJI_UPDATE: + case AuditLogActions.EMOJI_DELETE: + case AuditLogActions.INTEGRATION_CREATE: + case AuditLogActions.INTEGRATION_UPDATE: + case AuditLogActions.INTEGRATION_DELETE: + case AuditLogActions.STICKER_CREATE: + case AuditLogActions.STICKER_UPDATE: + case AuditLogActions.STICKER_DELETE: + case AuditLogActions.GUILD_SCHEDULED_EVENT_CREATE: + case AuditLogActions.GUILD_SCHEDULED_EVENT_UPDATE: + case AuditLogActions.GUILD_SCHEDULED_EVENT_DELETE: + case AuditLogActions.APPLICATION_COMMAND_PERMISSION_UPDATE: + case AuditLogActions.ONBOARDING_PROMPT_CREATE: + case AuditLogActions.ONBOARDING_PROMPT_UPDATE: + case AuditLogActions.ONBOARDING_PROMPT_DELETE: { + channel + .createMessage({ + content: Object.entries(AuditLogActions).find(([name, val]) => val === entry.actionType)[0], + attachments: [ + { + filename: entry.id + ".json", + file: JSON.stringify(entry, null, 4), + }, + ], + }) + .catch(() => {}); + break; + } + case AuditLogActions.MEMBER_ROLE_UPDATE: { + const added = entry.after.$add != null; + const isSelf = entry.user.id === entry.targetID; + const role = (entry.after.$add ?? entry.after.$remove)[0]; + + channel + .createMessage({ + embeds: [ + { + color: added ? COLOR_ADDED : COLOR_REMOVED, + title: `Member Role Updated`, + description: `<@${entry.user.id}> (${formatUsername(entry.user)}) ${added ? "added" : "removed"} role ${ + added ? "to" : "from" + } ${isSelf ? "self" : `<@${entry.targetID}> (${formatUsername(entry.target.user)})`}`, + timestamp: new Date().toISOString(), + fields: [ + { + name: "Role", + value: `<@&${role.id}> (${role.name})`, + }, + ], + footer: { + text: `Role ID: ${role.id}`, + }, + }, + ], + }) + .catch(() => {}); + break; + } + case AuditLogActions.THREAD_CREATE: { + channel + .createMessage({ + embeds: [ + { + color: COLOR_ADDED, + title: `${entry.after.invitable != null ? "Private " : ""}Thread Created`, + description: `<#${entry.targetID}> (${entry.after.name})`, + timestamp: new Date().toISOString(), + fields: [ + { + name: "Created by", + value: `<@${entry.user.id}> (${formatUsername(entry.user)})`, + inline: true, + }, + ], + footer: { + text: `Thread ID: ${entry.targetID}`, + }, + }, + ], + }) + .catch(() => {}); + break; + } + case AuditLogActions.THREAD_UPDATE: { + channel + .createMessage({ + embeds: [ + { + color: COLOR_CHANGED, + title: `${ + entry.target != null && entry.target instanceof PrivateThreadChannel ? "Private " : "" + }Thread Updated`, + description: `<#${entry.targetID}>${entry.target?.name != null ? ` (${entry.target.name})` : ""} ${ + entry.before.locked === true && entry.after.locked === false + ? "unlocked" + : entry.before.locked === false && entry.after.locked === true + ? "locked" + : entry.before.archived === true && entry.after.archived === false + ? "unarchived" + : entry.before.archived === false && entry.after.archived === true + ? "archived" + : entry.before.invitable === false && entry.after.invitable === true + ? "mention inviting enabled" + : entry.before.invitable === true && entry.after.invitable === false + ? "mention inviting disabled" + : "updated" + } by <@${entry.user.id}> (${formatUsername(entry.user)})`, + timestamp: new Date().toISOString(), + fields: [ + entry.after.name != null && { + name: "Name", + value: `\`${entry.before.name}\` -> \`${entry.after.name}\``, + }, + entry.after.auto_archive_duration != null && { + name: "Hide After Inactivity", + value: `\`${entry.before.auto_archive_duration}\` -> \`${entry.after.auto_archive_duration}\``, + }, + entry.after.rate_limit_per_user != null && { + name: "Slowmode", + value: `\`${entry.before.rate_limit_per_user}\` -> \`${entry.after.rate_limit_per_user}\``, + }, + ].filter((x) => !!x), + footer: { + text: `Thread ID: ${entry.targetID}`, + }, + }, + ], + }) + .catch(() => {}); + break; + } + case AuditLogActions.THREAD_DELETE: { + channel + .createMessage({ + embeds: [ + { + color: COLOR_ADDED, + title: `${entry.before.invitable != null ? "Private " : ""}Thread Deleted`, + description: `<#${entry.targetID}> (${entry.before.name})`, + timestamp: new Date().toISOString(), + fields: [ + { + name: "Deleted by", + value: `<@${entry.user.id}> (${formatUsername(entry.user)})`, + inline: true, + }, + ], + footer: { + text: `Thread ID: ${entry.targetID}`, + }, + }, + ], + }) + .catch(() => {}); + break; + } + } + } catch (err) { + const eventName = Object.entries(AuditLogActions).find(([name, val]) => val === entry.actionType)[0]; + if (WHITELISTED_EVENTS.has(eventName)) { + logger.error("logging", `Failed to create log entry in ${entry.guild.id} for ${eventName}: ${err}`); channel .createMessage({ - content: Object.entries(AuditLogActions).find(([name, val]) => val === entry.actionType)[0], + content: `Failed to create pretty embed for ${eventName}`, attachments: [ { filename: entry.id + ".json", @@ -69,78 +256,6 @@ events.add("guildAuditLogEntryCreate", "logging", async function (entry) { ], }) .catch(() => {}); - break; - } - case AuditLogActions.MEMBER_ROLE_UPDATE: { - const added = entry.after.$add != null; - const isSelf = entry.user.id === entry.targetID; - const role = (entry.after.$add ?? entry.after.$remove)[0]; - - channel - .createMessage({ - embeds: [ - { - color: added ? COLOR_ADDED : COLOR_REMOVED, - title: `Member Role Updated`, - description: `<@${entry.user.id}> (${formatUsername(entry.user)}) ${added ? "added" : "removed"} role ${ - added ? "to" : "from" - } ${isSelf ? "self" : `<@${entry.targetID}> (${formatUsername(entry.target.user)})`}`, - timestamp: new Date().toISOString(), - fields: [ - { - name: "Role", - value: `<@&${role.id}> (${role.name})`, - }, - ], - footer: { - text: `Role ID: ${role.id}`, - }, - }, - ], - }) - .catch(() => {}); - break; - } - case AuditLogActions.THREAD_UPDATE: { - channel - .createMessage({ - embeds: [ - { - color: COLOR_CHANGED, - title: "Thread Updated", - description: `<#${entry.targetID}>${entry.target?.name != null ? ` (${entry.target.name})` : ""} ${ - entry.before.locked === true && entry.after.locked === false - ? "unlocked" - : entry.before.locked === false && entry.after.locked === true - ? "locked" - : entry.before.archived === true && entry.after.archived === false - ? "unarchived" - : entry.before.archived === false && entry.after.archived === true - ? "archived" - : "updated" - } by <@${entry.user.id}> (${formatUsername(entry.user)})`, - timestamp: new Date().toISOString(), - fields: [ - entry.after.name != null && { - name: "Name", - value: `\`${entry.before.name}\` -> \`${entry.after.name}\``, - }, - entry.after.auto_archive_duration != null && { - name: "Hide After Inactivity", - value: `\`${entry.before.auto_archive_duration}\` -> \`${entry.after.auto_archive_duration}\``, - }, - entry.after.rate_limit_per_user != null && { - name: "Slowmode", - value: `\`${entry.before.rate_limit_per_user}\` -> \`${entry.after.rate_limit_per_user}\``, - }, - ].filter((x) => !!x), - footer: { - text: `Thread ID: ${entry.targetID}`, - }, - }, - ], - }) - .catch(() => {}); } } });