diff --git a/src/structure/components/observers/GuildLogging.js b/src/structure/components/observers/GuildLogging.js index 2dea1ed..f063db7 100644 --- a/src/structure/components/observers/GuildLogging.js +++ b/src/structure/components/observers/GuildLogging.js @@ -12,7 +12,11 @@ const CONSTANTS = { RED: 16711680, // message delete YELLOW: 15120384, // message edit LIGHT_BLUE: 11337726, // message pin - BLUE: 479397 + BLUE: 479397, + THREAD_DELETE: 16711680, // red + THREAD_CREATE: 4245310, // green + THREAD_ARCHIVE: 16550915, // Orange + THREAD_UNARCHIVE: 4615101 // blue }, IMAGES: { PREMIUM_LIMIT: 2, @@ -44,7 +48,10 @@ class GuildLogger extends Observer { ['voiceStateUpdate', this.voiceState.bind(this)], ['guildMemberAdd', this.memberJoin.bind(this)], ['guildMemberRemove', this.memberLeave.bind(this)], - ['guildMemberUpdate', this.memberUpdate.bind(this)] + ['guildMemberUpdate', this.memberUpdate.bind(this)], + ['threadCreate', this.threadCreate.bind(this)], + ['threadDelete', this.threadDelete.bind(this)], + ['threadUpdate', this.threadUpdate.bind(this)] ]; this.attachmentWebhook = new WebhookClient( @@ -63,6 +70,69 @@ class GuildLogger extends Observer { // } + async threadCreate(thread) { + return this._logThread(thread, 'CREATE'); + } + + async threadDelete(thread) { + return this._logThread(thread, 'DELETE'); + } + + async threadUpdate(oldThread, newThread) { + if(oldThread.archived !== newThread.archived) return this._logThread(newThread, newThread.archived ? 'ARCHIVE': 'UNARCHIVE'); + } + + async _logThread(thread, type) { + const { ownerId, guildWrapper: guild, parent } = thread; + if (!this.client._built + || !guild + || !guild.available) return; + + const settings = await guild.settings(); + const { messages } = settings; + if (!messages.channel) return; + + const logChannel = await guild.resolveChannel(messages.channel); + if (!logChannel) return; + const owner = await guild.resolveUser(ownerId); + + const missing = logChannel.permissionsFor(guild.me).missing(['VIEW_CHANNEL', 'EMBED_LINKS', 'SEND_MESSAGES']); + if (missing.length) + return this.client.emit('logError', { guild, logger: 'threadLogger', reason: 'MSGLOG_NO_PERMS', params: { missing: missing.join(', ') } }); + + const hook = await guild.getWebhook('messages'); + if (!hook) { + this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`); + return this.client.emit('logError', { guild, logger: 'threadLogger', reason: 'MSGLOG_NO_HOOK' }); + } + + let actor = null; + if (type === 'CREATE') actor = owner; + else if (type === 'DELETE') { + const auditLogs = await guild.fetchAuditLogs({ type: 'THREAD_DELETE', limit: 1 }); + const log = auditLogs.entries.first(); + if (thread.id !== log.target.id) return; + actor = log.executor; + } else if (['ARCHIVE', 'UNARCHIVE'].includes(type)) { + const auditLogs = await guild.fetchAuditLogs({ type: 'THREAD_UPDATE', limit: 1 }); + const log = auditLogs.entries.first(); + if (thread.id !== log.target.id) return; + actor = log.executor; + } + if (!actor) return; + + const embed = { + title: guild.format(`MSGLOG_THREAD_TITLE`, { action: guild.format('THREAD_SWITCH', { type }, { code: true }), channel: parent.name }), + description: guild.format(`MSGLOG_THREAD_DESC_${type}`, { owner: owner.tag, actor: actor.tag, name: thread.name, id: thread.id }), + footer: { text: guild.format('MSGLOG_THREAD_FOOTER', { ownerId: owner.id, channelId: parent.id, threadId: thread.id }) }, + color: CONSTANTS.COLORS[`THREAD_${type}`] + }; + + if(thread.locked) embed.description += '\n\n' + guild.format('MSGLOG_THREAD_LOCKED'); + + await hook.send({ embeds: [embed] }); + } + async messageDelete(message) { if (!this.client._built @@ -86,9 +156,10 @@ class GuildLogger extends Observer { const { bypass, ignore } = messageLog; const logChannel = await wrapper.resolveChannel(messageLog.channel); if (!logChannel) return undefined; - - const perms = logChannel.permissionsFor(message.guild.me); - if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return undefined; + + const missing = logChannel.permissionsFor(wrapper.me).missing(['VIEW_CHANNEL', 'EMBED_LINKS', 'SEND_MESSAGES']); + if (missing.length) + return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_PERMS', params: { missing: missing.join(', ') } }); if (bypass.length && message.member.roles.cache.size) { const roles = message.member.roles.cache.map((r) => r.id); @@ -101,8 +172,8 @@ class GuildLogger extends Observer { const hook = await wrapper.getWebhook('messages'); if (!hook) { - this.logger.debug(`Missing messageLog hook in ${message.guild.name} (${message.guild.id})`); - return; + this.logger.debug(`Missing messageLog hook in ${wrapper.name} (${wrapper.id})`); + return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' }); } const { reference, channel, author, content, id } = message; @@ -252,8 +323,15 @@ class GuildLogger extends Observer { const { ignore, bypass } = chatlogs; if (ignore.includes(channel.id)) return; + const missing = logChannel.permissionsFor(guild.me).missing(['VIEW_CHANNEL', 'EMBED_LINKS', 'SEND_MESSAGES']); + if (missing.length) + return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_PERMS', params: { missing: missing.join(', ') } }); + const hook = await wrapper.getWebhook('messages'); - if (!hook) return; + if (!hook) { + this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`); + return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' }); + } const cutOff = EmbedLimits.fieldValue;// - 3; const fields = []; @@ -422,9 +500,20 @@ class GuildLogger extends Observer { const chatlogs = settings.messages; if (!chatlogs.channel) return; - const { ignore, bypass } = chatlogs; + const { ignore, bypass, channel: _channel } = chatlogs; + + const logChannel = await wrapper.resolveChannel(_channel); + if (!logChannel) return undefined; + + const missing = logChannel.permissionsFor(guild.me).missing(['VIEW_CHANNEL', 'EMBED_LINKS', 'SEND_MESSAGES']); + if (missing.length) + return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_PERMS', params: { missing: missing.join(', ') } }); + const hook = await wrapper.getWebhook('messages'); - if (!hook) return; + if (!hook) { + this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`); + return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' }); + } if (bypass && member.roles.cache.size) { const roles = member.roles.cache.map((r) => r.id); @@ -538,8 +627,9 @@ class GuildLogger extends Observer { const logChannel = await wrapper.resolveChannel(setting.channel); if (!logChannel) return; - const perms = logChannel.permissionsFor(guild.me); - if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return; + const missing = logChannel.permissionsFor(guild.me).missing(['VIEW_CHANNEL', 'EMBED_LINKS', 'SEND_MESSAGES']); + if (missing.length) + return this.client.emit('logError', { guild: wrapper, logger: 'vcLogger', reason: 'VCLOG_NO_PERMS', params: { missing: missing.join(', ') } }); let index = null; const langParams = { @@ -581,8 +671,9 @@ class GuildLogger extends Observer { const logChannel = await wrapper.resolveChannel(setting.channel); if (!logChannel) return; - const perms = logChannel.permissionsFor(guild.me); - if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return; + const missing = logChannel.permissionsFor(guild.me).missing(['VIEW_CHANNEL', 'EMBED_LINKS', 'SEND_MESSAGES']); + if (missing.length) + return this.client.emit('logError', { guild: wrapper, logger: 'vcLogger', reason: 'MEMBERLOG_NO_PERMS', params: { missing: missing.join(', ') } }); let { join: joinMessage } = setting; joinMessage = this._replaceTags(joinMessage, member); @@ -600,8 +691,9 @@ class GuildLogger extends Observer { const logChannel = await wrapper.resolveChannel(setting.channel); if (!logChannel) return; - const perms = logChannel.permissionsFor(guild.me); - if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return; + const missing = logChannel.permissionsFor(guild.me).missing(['VIEW_CHANNEL', 'EMBED_LINKS', 'SEND_MESSAGES']); + if (missing.length) + return this.client.emit('logError', { guild: wrapper, logger: 'vcLogger', reason: 'MEMBERLOG_NO_PERMS', params: { missing: missing.join(', ') } }); let { leave: leaveMessage } = setting; leaveMessage = this._replaceTags(leaveMessage, member); @@ -621,8 +713,9 @@ class GuildLogger extends Observer { const logChannel = await wrapper.resolveChannel(setting.channel); if (!logChannel) return; - const perms = logChannel.permissionsFor(guild.me); - if (!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL') || !perms.has('EMBED_LINKS')) return; + const missing = logChannel.permissionsFor(guild.me).missing(['VIEW_CHANNEL', 'EMBED_LINKS', 'SEND_MESSAGES']); + if (missing.length) + return this.client.emit('logError', { guild: wrapper, logger: 'vcLogger', reason: 'NICKLOG_NO_PERMS', params: { missing: missing.join(', ') } }); const oldNick = oldMember.nickname || oldMember.user.username; const newNick = newMember.nickname || newMember.user.username;