From e99f88e0978152a22946f5be1a44ae6f5f7ce2aa Mon Sep 17 00:00:00 2001 From: bdistin Date: Wed, 15 Mar 2017 09:29:34 -0500 Subject: [PATCH] Fix #1253: Permission Overwrites Resolution (#1255) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #1253 * apparently @ everyone role can be undefined * Fix oops * Fixes possible mutiple roles named '@​everyone' * Clean up order/logic --- src/client/rest/APIRequest.js | 8 +-- src/client/rest/RESTMethods.js | 6 +-- src/structures/GuildChannel.js | 25 +++++++-- src/structures/interface/TextBasedChannel.js | 54 ++++++++++++++------ 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/client/rest/APIRequest.js b/src/client/rest/APIRequest.js index 5e83c143bf59..9fc6a40de9c6 100644 --- a/src/client/rest/APIRequest.js +++ b/src/client/rest/APIRequest.js @@ -2,13 +2,13 @@ const request = require('superagent'); const Constants = require('../../util/Constants'); class APIRequest { - constructor(rest, method, url, auth, data, file) { + constructor(rest, method, url, auth, data, files) { this.rest = rest; this.method = method; this.url = url; this.auth = auth; this.data = data; - this.file = file; + this.files = files; this.route = this.getRoute(this.url); } @@ -34,8 +34,8 @@ class APIRequest { gen() { const apiRequest = request[this.method](this.url); if (this.auth) apiRequest.set('authorization', this.getAuth()); - if (this.file && this.file.file) { - apiRequest.attach('file', this.file.file, this.file.name); + if (this.files) { + for (const file of this.files) if (file && file.file) apiRequest.attach(file.name, file.file, file.name); this.data = this.data || {}; apiRequest.field('payload_json', JSON.stringify(this.data)); } else if (this.data) { diff --git a/src/client/rest/RESTMethods.js b/src/client/rest/RESTMethods.js index 727245fc452f..306749b14d9a 100644 --- a/src/client/rest/RESTMethods.js +++ b/src/client/rest/RESTMethods.js @@ -57,7 +57,7 @@ class RESTMethods { }); } - sendMessage(channel, content, { tts, nonce, embed, disableEveryone, split, code, reply } = {}, file = null) { + sendMessage(channel, content, { tts, nonce, embed, disableEveryone, split, code, reply } = {}, files = null) { return new Promise((resolve, reject) => { // eslint-disable-line complexity if (typeof content !== 'undefined') content = this.client.resolver.resolveString(content); @@ -99,7 +99,7 @@ class RESTMethods { const messages = []; (function sendChunk(list, index) { const options = index === list.length ? { tts, embed } : { tts }; - chan.send(list[index], options, index === list.length ? file : null).then(message => { + chan.send(list[index], options, index === list.length ? files : null).then(message => { messages.push(message); if (index >= list.length - 1) return resolve(messages); return sendChunk(list, ++index); @@ -108,7 +108,7 @@ class RESTMethods { } else { this.rest.makeRequest('post', Constants.Endpoints.channelMessages(chan.id), true, { content, tts, nonce, embed, - }, file).then(data => resolve(this.client.actions.MessageCreate.handle(data).message), reject); + }, files).then(data => resolve(this.client.actions.MessageCreate.handle(data).message), reject); } }; diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index 5ae1a08daa5f..c9d1e3f4136b 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -63,13 +63,24 @@ class GuildChannel extends Channel { for (const role of roles.values()) permissions |= role.permissions; const overwrites = this.overwritesFor(member, true, roles); + + if (overwrites.everyone) { + permissions &= ~overwrites.everyone.deny; + permissions |= overwrites.everyone.allow; + } + let allow = 0; - for (const overwrite of overwrites.role.concat(overwrites.member)) { + for (const overwrite of overwrites.roles) { permissions &= ~overwrite.deny; allow |= overwrite.allow; } permissions |= allow; + if (overwrites.member) { + permissions &= ~overwrites.member.deny; + permissions |= overwrites.member.allow; + } + const admin = Boolean(permissions & Permissions.FLAGS.ADMINISTRATOR); if (admin) permissions = Permissions.ALL; @@ -82,18 +93,22 @@ class GuildChannel extends Channel { roles = roles || member.roles; const roleOverwrites = []; - const memberOverwrites = []; + let memberOverwrites; + let everyoneOverwrites; for (const overwrite of this.permissionOverwrites.values()) { - if (overwrite.id === member.id) { - memberOverwrites.push(overwrite); + if (overwrite.id === this.guild.id) { + everyoneOverwrites = overwrite; } else if (roles.has(overwrite.id)) { roleOverwrites.push(overwrite); + } else if (overwrite.id === member.id) { + memberOverwrites = overwrite; } } return { - role: roleOverwrites, + everyone: everyoneOverwrites, + roles: roleOverwrites, member: memberOverwrites, }; } diff --git a/src/structures/interface/TextBasedChannel.js b/src/structures/interface/TextBasedChannel.js index 05169e5a67d1..8cb1d5f788ea 100644 --- a/src/structures/interface/TextBasedChannel.js +++ b/src/structures/interface/TextBasedChannel.js @@ -37,7 +37,8 @@ class TextBasedChannel { * (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details) * @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here * should be replaced with plain-text - * @property {FileOptions|string} [file] A file to send with the message + * @property {FileOptions|string} [file] A file to send with the message **(deprecated)** + * @property {FileOptions[]|string[]} [files] Files to send with the message * @property {string|boolean} [code] Language for optional codeblock formatting to apply * @property {boolean|SplitOptions} [split=false] Whether or not the message should be split into multiple messages if * it exceeds the character limit. If an object is provided, these are the options for splitting the message. @@ -78,26 +79,34 @@ class TextBasedChannel { options = {}; } - if (options.embed && options.embed.file) options.file = options.embed.file; - + // backward compat if (options.file) { - if (typeof options.file === 'string') options.file = { attachment: options.file }; - if (!options.file.name) { - if (typeof options.file.attachment === 'string') { - options.file.name = path.basename(options.file.attachment); - } else if (options.file.attachment && options.file.attachment.path) { - options.file.name = path.basename(options.file.attachment.path); - } else { - options.file.name = 'file.jpg'; + if (options.files) options.files.push(options.file); + else options.files = [options.file]; + } + + if (options.files) { + for (const i in options.files) { + let file = options.files[i]; + if (typeof file === 'string') file = { attachment: file }; + if (!file.name) { + if (typeof file.attachment === 'string') { + file.name = path.basename(file.attachment); + } else if (file.attachment && file.attachment.path) { + file.name = path.basename(file.attachment.path); + } else { + file.name = 'file.jpg'; + } } + options.files[i] = file; } - return this.client.resolver.resolveBuffer(options.file.attachment).then(file => - this.client.rest.methods.sendMessage(this, content, options, { - file, - name: options.file.name, + return Promise.all(options.files.map(file => + this.client.resolver.resolveBuffer(file.attachment).then(buffer => { + file.file = buffer; + return file; }) - ); + )).then(files => this.client.rest.methods.sendMessage(this, content, options, files)); } return this.client.rest.methods.sendMessage(this, content, options); @@ -135,6 +144,17 @@ class TextBasedChannel { return this.send(content, Object.assign(options, { embed })); } + /** + * Send files to this channel + * @param {FileOptions[]|string[]} files Files to send with the message + * @param {StringResolvable} [content] Text for the message + * @param {MessageOptions} [options] Options for the message + * @returns {Promise} + */ + sendFiles(files, content, options) { + return this.send(content, Object.assign(options, { files })); + } + /** * Send a file to this channel * @param {BufferResolvable} attachment File to send @@ -144,7 +164,7 @@ class TextBasedChannel { * @returns {Promise} */ sendFile(attachment, name, content, options = {}) { - return this.send(content, Object.assign(options, { file: { attachment, name } })); + return this.sendFiles([{ attachment, name }], content, options); } /**