From 97e34af8c4d1a6b4239ea339579bf277051b9519 Mon Sep 17 00:00:00 2001 From: nolan Date: Tue, 28 Jul 2020 11:49:34 -0700 Subject: [PATCH] enable/disable and message logging --- .eslintrc.json | 1 - storage/StorageManager.js | 7 +- structure/client/Resolver.js | 8 +- .../components/observers/GuildLogging.js | 254 ++++++++++-------- .../components/observers/MessageCache.js | 8 +- structure/extensions/Message.js | 5 +- 6 files changed, 151 insertions(+), 132 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index c512854..04b8bad 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -35,7 +35,6 @@ "warn", "never" ], - "consistent-return": "warn", "consistent-this": "warn", "dot-notation": [ "warn", diff --git a/storage/StorageManager.js b/storage/StorageManager.js index 1e67044..a3487be 100644 --- a/storage/StorageManager.js +++ b/storage/StorageManager.js @@ -61,9 +61,10 @@ class StorageManager { if(!this.providers.has(message.provider)) return this._send(shard, { error: true, message: `Invalid provider, expected 'mongodb' or 'mariadb', got '${message.provider}'`, transactionID: message.transactionID }); if(!message.request) return this._send(shard, { error: true, message: `Missing request.`, transactionID: message.transactionID }); - const response = await this.providers.get(message.provider)._query(message.request).catch((error) => { - this.manager.logger.write('error', `Provider ${message.provider} errored: ${error}`, shard); - }); + const response = await this.providers.get(message.provider)._query(message.request) + .catch((error) => { + this.manager.logger.write('error', `Provider ${message.provider} errored: ${error}`, shard); + }); if(response && response.error) { this.manager.logger.write('error', `Provider ${message.provider} errored: ${response.message}`, shard); diff --git a/structure/client/Resolver.js b/structure/client/Resolver.js index 3dbf2ae..2d7e805 100644 --- a/structure/client/Resolver.js +++ b/structure/client/Resolver.js @@ -15,13 +15,12 @@ class Resolver { * @returns * @memberof Resolver */ -<<<<<<< HEAD - resolveComponent(arg, strict = true, type) { + resolveComponent(arg, strict = true, type = 'any') { const string = arg.toLowerCase(); const components = this.client.registry.components - .filter((c) => c.type === type) + .filter((c) => type === 'any' ? ['command', 'setting'].includes(c.type) : c.type === type) .filter(strict ? filterExact(string) : filterInexact(string)); //eslint-disable-line no-use-before-define return components.first(); @@ -29,9 +28,6 @@ class Resolver { } components(str = '', type, exact = true) { -======= - components(str = '', type = 'any', exact = true) { ->>>>>>> 79e0bce3b5fd9afe59f5c5e7d8bbc4a78f518acd const string = str.toLowerCase(); diff --git a/structure/client/components/observers/GuildLogging.js b/structure/client/components/observers/GuildLogging.js index 510acb7..74195f4 100644 --- a/structure/client/components/observers/GuildLogging.js +++ b/structure/client/components/observers/GuildLogging.js @@ -1,3 +1,5 @@ +const { MessageAttachment, WebhookClient } = require('discord.js'); + const { Observer } = require('../../../interfaces/'); const { Util } = require('../../../../util'); @@ -27,105 +29,27 @@ class GuildLogger extends Observer { super(client, { name: 'guildLogger', - priority: 3, - disabled: true + priority: 3 + // disabled: true }); this.hooks = [ - ['message', this.storeAttachment.bind(this)], //Attachment logging - ['messageDelete', this.messageDelete.bind(this)], - ['messageDeleteBulk', this.messageDeleteBulk.bind(this)], - ['messageUpdate', this.messageEdit.bind(this)], - ['voiceStateUpdate', this.voiceState.bind(this)], - ['guildBanAdd', this.ban.bind(this)], - ['guildBanRemove', this.unban.bind(this)], - ['guildMemberAdd', this.memberJoin.bind(this)], - ['guildMemberRemove', this.memberLeave.bind(this)], - ['guildMemberUpdate', this.memberUpdate.bind(this)] + // ['message', this.storeAttachment.bind(this)], //Attachment logging + ['messageDelete', this.messageDelete.bind(this)] + // ['messageDeleteBulk', this.messageDeleteBulk.bind(this)], + // ['messageUpdate', this.messageEdit.bind(this)], + // ['voiceStateUpdate', this.voiceState.bind(this)], + // ['guildBanAdd', this.ban.bind(this)], + // ['guildBanRemove', this.unban.bind(this)], + // ['guildMemberAdd', this.memberJoin.bind(this)], + // ['guildMemberRemove', this.memberLeave.bind(this)], + // ['guildMemberUpdate', this.memberUpdate.bind(this)] ]; - } - - async storeAttachment(message) { - - const { guild, member, author, channel } = message; - if(!guild || author.bot) return; - if(!message.attachments.size) return; - console.log('Store call'); - - const settings = await guild.settings(), - setting = settings.messageLog, - roles = member.roles.cache.map((r) => r.id), - { ignoredRoles } = setting; - - //if(guild._settings.premium < CONSTANTS.IMAGES.PREMIUM_LIMIT) return; - if(!setting.attachments || setting.ignoredChannels.includes(channel.id)) return; - if(setting.ignoredRoles.length && roles.length) for(const role of ignoredRoles) if(roles.includes(role)) return; - - console.log('Can store'); - - const attachments = message.attachments.values(); - for(const attachment of attachments) { - - const TH = this.client.transactionHandler; - const { size, name, id } = attachment; - const fsize = size/CONSTANTS.IMAGES.MB_DIVIDER; // File size in MB - if(fsize > CONSTANTS.IMAGES.UPLOAD_LIMIT[guild.premiumTier]) continue; - - const buffer = await Util.downloadAsBuffer(attachment.url).catch((err) => { - this.client.logger.error(err); return null; - }); - if(!buffer) return; - const data = { - buffer, - id - }; - - try { - //TODO: test this - //const start = Date.now(); - const result = await TH.send({ - provider: 'mongodb', - request: { - type: 'insertOne', - collection: 'attachment_logs', - data - } - }); - - //console.log(`Took ${Date.now()-start}ms to insert image.`); - //console.log(result); - - const metadata = { - database_ID: result.insertedId, - id, - guild: guild.id, - message: message.id, - author: author.id, - name, - size, - timestamp: Math.floor(Date.now()/1000), - removeAt: Math.floor(Date.now()/1000 + guild._settings.premium * CONSTANTS.WEEK * 0.25) - }; - - //console.log(metadata); - - await TH.send({ - provider: 'mongodb', - request: { - type: 'insertOne', - collection: 'attachment_logs_index', - data: metadata - } - }); - - //console.log(`Took ${Date.now()-start}ms to insert entire entry.`); - - } catch (err) { - this.client.logger.error('Something went wrong with storing image to db:\n' + err.stack); - } - - } + this.attachmentWebhook = new WebhookClient( + this.client._options.moderation.attachments.webhook.id, + this.client._options.moderation.attachments.webhook.token + ); } @@ -138,35 +62,138 @@ class GuildLogger extends Observer { async messageDelete(message) { - if(message.author.bot) return; + if(!this.client._built + || message.webhookID + || message.author.bot + || !message.guild + || !message.guild.available) return; - const { guild } = message; - if (!guild) return; + await message.guild.settings(); - if (!message.member) message.member = await guild.members.fetch(message.author); - const { member, channel, author } = message; + if (!message.member) message.member = await message.guild.members.fetch(message.author.id); - const settings = await guild.settings(); - const chatlogs = settings.messageLog; - if (!chatlogs || !chatlogs.channel) return; + const { messageLog } = message.guild._settings; + if(!messageLog.channel) return undefined; + + const { ignoredRoles, ignoredChannels } = messageLog; + const logChannel = await message.guild.resolveChannel(messageLog.channel); + if(!logChannel) return undefined; - const { ignoredRoles, ignoredChannels } = chatlogs; - const logChannel = await guild.resolveChannel(chatlogs.channel); - if(!logChannel) return; + const perms = logChannel.permissionsFor(message.guild.me); + if(!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL')) return undefined; - const perms = logChannel.permissionsFor(guild.me); - if(!perms.has('SEND_MESSAGES') || !perms.has('VIEW_CHANNEL')) return; - - if (ignoredRoles.length && member.roles.cache.size) { - const roles = member.roles.cache.map((r) => r.id); + if(ignoredRoles.length && message.member.roles.cache.size) { + const roles = message.member.roles.cache.map((r) => r.id); for (const role of ignoredRoles) { - if (roles.includes(role)) return; + if (roles.includes(role)) return undefined; } } - if (ignoredChannels && ignoredChannels.includes(channel.id)) return; + if(ignoredChannels && ignoredChannels.includes(message.channel.id)) return undefined; - if (message.attachments.size) return this.logAttachment({ msgID: message.id, guildID: guild.id, channelID: channel.id, logChannel }); + const embed = { + author: { + name: `${message.author.tag} (${message.author.id})`, + icon_url: message.author.displayAvatarURL({ size: 32 }) //eslint-disable-line camelcase + }, + description: Util.escapeMarkdown(message.content).replace(/\\n/gu, ' '), + color: CONSTANTS.COLORS.RED, + footer: { + text: `Message deleted in #${message.channel.name} | Message ID: ${message.id}` + }, + timestamp: message.createdAt + }; + + const uploadedFiles = []; + if(message.attachments.size > 0 && messageLog.attachments) { + const imageExtensions = ['.png', '.webp', '.jpg', '.jpeg', '.gif']; + const data = await this.client.transactionHandler.send({ + provider: 'mongodb', + request: { + collection: 'messages', + type: 'findOne', + query: { + id: message.id + } + } + }); + + const attachments = await this.client.transactionHandler.send({ + provider: 'mongodb', + request: { + collection: 'attachments', + type: 'find', + query: { + _id: { $in: data.attachments.filter((a) => a.index).map((a) => a.index) } + } + } + }); + + const sortedAttachments = data.attachments.sort((a, b) => b.size-a.size); + + const files = []; + for(const attachment of sortedAttachments) { + const attachmentData = attachments.find((a) => a.attachmentId === attachment.id); + if(attachmentData) { + attachmentData.buffer = Buffer.from(attachmentData.buffer, 'base64'); + const messageAttachment = new MessageAttachment(attachmentData.buffer, attachment.name, { size: attachment.size }); + if(messageAttachment.size < CONSTANTS.IMAGES.UPLOAD_LIMIT[message.guild.premiumTier]*CONSTANTS.IMAGES.MB_DIVIDER) { + if(imageExtensions.includes(attachment.extension) && uploadedFiles.length === 0) { + uploadedFiles.push(messageAttachment); + embed.image = { + url: `attachment://${attachment.name}` + }; + } else { + if(messageAttachment.size > 8*CONSTANTS.IMAGES.MB_DIVIDER) { + const combined = uploadedFiles.length > 0 ? uploadedFiles.map((f) => f.size).reduce((p, v) => p+v) : 0; + if((combined + messageAttachment.size)/CONSTANTS.IMAGES.MB_DIVIDER < CONSTANTS.IMAGES.UPLOAD_LIMIT[message.guild.premiumTier]) { + uploadedFiles.push(messageAttachment); + } + } else { + files.push(messageAttachment); + } + } + } + } + } + + let currentFiles = []; + const uploaded = []; + + const upload = async (files) => { + const attachmentMessage = await this.attachmentWebhook.send(null, files).catch((error) => console.error(error)); + attachmentMessage.attachments.map((a) => uploaded.push(`[${a.filename} (${(a.size/CONSTANTS.IMAGES.MB_DIVIDER).toFixed(2)}mb)](${a.url})`)); + console.log(attachmentMessage.attachments); + }; + + for(const file of files) { + const currentMb = currentFiles.length > 0 ? currentFiles.map((f) => f.size).reduce((p, v) => p+v) : 0; + if(currentMb + file.size > 8*CONSTANTS.IMAGES.MB_DIVIDER) { + await upload(currentFiles); + currentFiles = []; + } else { + currentFiles.push(file); + } + } + + if(currentFiles.length > 0) { + await upload(currentFiles); + } + + console.log(uploaded.length); + + if(uploaded.length > 0) { + embed.description += `\n\n**${uploadedFiles.length > 0 ? 'Additional ' : ''}Attachment${uploaded.length > 1 ? 's' : ''}:** ${uploaded.join(', ')}`; + } + + } + + message.respond(null, { embed, files: uploadedFiles }); + + /* + if(message.attachments.size > 0) { + return this.logAttachment({ msgID: message.id, guildID: guild.id, channelID: channel.id, logChannel }); + } const embed = { title: message.format('MSGLOG_DELETE_TITLE', { author: Util.escapeMarkdown(author.tag), channel: channel.name }), @@ -179,6 +206,7 @@ class GuildLogger extends Observer { }; await logChannel.send({ embed }); + */ } diff --git a/structure/client/components/observers/MessageCache.js b/structure/client/components/observers/MessageCache.js index 81f7a62..3cbe11d 100644 --- a/structure/client/components/observers/MessageCache.js +++ b/structure/client/components/observers/MessageCache.js @@ -55,8 +55,8 @@ class MessageCache extends Observer { if(!this.client._built || message.webhookID || message.author.bot - || !message.guild.available - || !message.guild) return undefined; + || !message.guild + || !message.guild.available) return undefined; await message.guild.settings(); @@ -126,11 +126,7 @@ class MessageCache extends Observer { } const buffer = await Util.downloadAsBuffer(attachment.proxyURL || attachment.url).catch((err) => { -<<<<<<< HEAD this.client.logger.error(`Failed to download buffer for "${chalk.bold(data.name)}".\n${err.stack || err}`); -======= - this.client.logger.error(`Failed to save buffer with image data: ${data} ${data.name}\n${err.stack || err}`); ->>>>>>> 79e0bce3b5fd9afe59f5c5e7d8bbc4a78f518acd return null; }); diff --git a/structure/extensions/Message.js b/structure/extensions/Message.js index 8b3f6db..e26f7b0 100644 --- a/structure/extensions/Message.js +++ b/structure/extensions/Message.js @@ -94,7 +94,7 @@ const Message = Structures.extend('Message', (Message) => { } - async respond(str, opts = { attachments: [], embed: null }) { + async respond(str, opts = { files: [], embed: null }) { if(typeof str === 'string') { if(opts.emoji) { @@ -105,8 +105,7 @@ const Message = Structures.extend('Message', (Message) => { if(opts.reply) str = `<@!${this.author.id}> ${str}`; } - //console.log(str) - this._pending = await this.channel.send(str, { files: opts.attachments, embed: opts.embed }); + this._pending = await this.channel.send(str, { files: opts.files, embed: opts.embed }); return this._pending; }