From 16fe48d405f4dd9c40a68737b05aedc3f4f0d201 Mon Sep 17 00:00:00 2001 From: Schuyler Cebulskie Date: Mon, 6 Mar 2017 02:22:42 -0500 Subject: [PATCH] Overhaul Permissions utilities (EvaluatedPermissions no more) --- src/client/Client.js | 3 +- src/client/ClientDataResolver.js | 76 -------- src/client/rest/RESTMethods.js | 3 +- src/index.js | 3 +- src/structures/EvaluatedPermissions.js | 67 ------- src/structures/GuildChannel.js | 27 ++- src/structures/GuildMember.js | 17 +- src/structures/Message.js | 5 +- src/structures/Role.js | 4 +- src/util/Constants.js | 38 ---- src/util/Permissions.js | 249 +++++++++++++++++++++++++ 11 files changed, 280 insertions(+), 212 deletions(-) delete mode 100644 src/structures/EvaluatedPermissions.js create mode 100644 src/util/Permissions.js diff --git a/src/client/Client.js b/src/client/Client.js index faa8ad26d..b36f00148 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -1,6 +1,7 @@ const os = require('os'); const EventEmitter = require('events').EventEmitter; const Constants = require('../util/Constants'); +const Permissions = require('../util/Permissions'); const Util = require('../util/Util'); const RESTManager = require('./rest/RESTManager'); const ClientDataManager = require('./ClientDataManager'); @@ -398,7 +399,7 @@ class Client extends EventEmitter { */ generateInvite(permissions) { if (permissions) { - if (permissions instanceof Array) permissions = this.resolver.resolvePermissions(permissions); + if (permissions instanceof Array) permissions = Permissions.resolve(permissions); } else { permissions = 0; } diff --git a/src/client/ClientDataResolver.js b/src/client/ClientDataResolver.js index 2d5ddf944..07ae2280d 100644 --- a/src/client/ClientDataResolver.js +++ b/src/client/ClientDataResolver.js @@ -155,82 +155,6 @@ class ClientDataResolver { return data; } - /** - * Data that can be resolved to give a permission number. This can be: - * * A string - * * A permission number - * - * Possible strings: - * ```js - * [ - * 'CREATE_INSTANT_INVITE', - * 'KICK_MEMBERS', - * 'BAN_MEMBERS', - * 'ADMINISTRATOR', - * 'MANAGE_CHANNELS', - * 'MANAGE_GUILD', - * 'ADD_REACTIONS', // add reactions to messages - * 'READ_MESSAGES', - * 'SEND_MESSAGES', - * 'SEND_TTS_MESSAGES', - * 'MANAGE_MESSAGES', - * 'EMBED_LINKS', - * 'ATTACH_FILES', - * 'READ_MESSAGE_HISTORY', - * 'MENTION_EVERYONE', - * 'EXTERNAL_EMOJIS', // use external emojis - * 'CONNECT', // connect to voice - * 'SPEAK', // speak on voice - * 'MUTE_MEMBERS', // globally mute members on voice - * 'DEAFEN_MEMBERS', // globally deafen members on voice - * 'MOVE_MEMBERS', // move member's voice channels - * 'USE_VAD', // use voice activity detection - * 'CHANGE_NICKNAME', - * 'MANAGE_NICKNAMES', // change nicknames of others - * 'MANAGE_ROLES_OR_PERMISSIONS', - * 'MANAGE_WEBHOOKS', - * 'MANAGE_EMOJIS' - * ] - * ``` - * @typedef {string|number} PermissionResolvable - */ - - /** - * Resolves a PermissionResolvable to a permission number - * @param {PermissionResolvable} permission The permission resolvable to resolve - * @returns {number} - */ - resolvePermission(permission) { - if (typeof permission === 'string') permission = Constants.PermissionFlags[permission]; - if (typeof permission !== 'number' || permission < 1) throw new Error(Constants.Errors.NOT_A_PERMISSION); - return permission; - } - - /** - * Turn an array of permissions into a valid Discord permission bitfield - * @param {PermissionResolvable[]} permissions Permissions to resolve together - * @returns {number} - */ - resolvePermissions(permissions) { - let bitfield = 0; - for (const permission of permissions) bitfield |= this.resolvePermission(permission); - return bitfield; - } - - hasPermission(bitfield, name, explicit = false) { - const permission = this.resolvePermission(name); - if (!explicit && (bitfield & Constants.PermissionFlags.ADMINISTRATOR) > 0) return true; - return (bitfield & permission) > 0; - } - - serializePermissions(bitfield) { - const serializedPermissions = {}; - for (const name in Constants.PermissionFlags) { - serializedPermissions[name] = this.hasPermission(bitfield, name); - } - return serializedPermissions; - } - /** * Data that can be resolved to give a string. This can be: * * A string diff --git a/src/client/rest/RESTMethods.js b/src/client/rest/RESTMethods.js index 104de1b28..2d2829f2c 100644 --- a/src/client/rest/RESTMethods.js +++ b/src/client/rest/RESTMethods.js @@ -1,5 +1,6 @@ const querystring = require('querystring'); const long = require('long'); +const Permissions = require('../../util/Permissions'); const Constants = require('../../util/Constants'); const Collection = require('../../util/Collection'); const Snowflake = require('../../util/Snowflake'); @@ -581,7 +582,7 @@ class RESTMethods { if (_data.permissions) { let perms = 0; for (let perm of _data.permissions) { - if (typeof perm === 'string') perm = Constants.PermissionFlags[perm]; + if (typeof perm === 'string') perm = Permissions.FLAGS[perm]; perms |= perm; } data.permissions = perms; diff --git a/src/index.js b/src/index.js index 2b1345e34..3abc36a13 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,8 @@ module.exports = { // Utilities Collection: require('./util/Collection'), Constants: require('./util/Constants'), + EvaluatedPermissions: require('./util/Permissions'), + Permissions: require('./util/Permissions'), Snowflake: require('./util/Snowflake'), SnowflakeUtil: require('./util/Snowflake'), Util: Util, @@ -27,7 +29,6 @@ module.exports = { ClientUser: require('./structures/ClientUser'), DMChannel: require('./structures/DMChannel'), Emoji: require('./structures/Emoji'), - EvaluatedPermissions: require('./structures/EvaluatedPermissions'), Game: require('./structures/Presence').Game, GroupDMChannel: require('./structures/GroupDMChannel'), Guild: require('./structures/Guild'), diff --git a/src/structures/EvaluatedPermissions.js b/src/structures/EvaluatedPermissions.js deleted file mode 100644 index ae8a643ce..000000000 --- a/src/structures/EvaluatedPermissions.js +++ /dev/null @@ -1,67 +0,0 @@ -const Constants = require('../util/Constants'); - -/** - * The final evaluated permissions for a member in a channel - */ -class EvaluatedPermissions { - constructor(member, raw) { - /** - * The member this permissions refer to - * @type {GuildMember} - */ - this.member = member; - - /** - * A number representing the packed permissions - * @type {number} - */ - this.raw = raw; - } - - /** - * Get an object mapping permission name, e.g. `READ_MESSAGES` to a boolean - whether the user - * can perform this or not. - * @returns {Object} - */ - serialize() { - const serializedPermissions = {}; - for (const permissionName in Constants.PermissionFlags) { - serializedPermissions[permissionName] = this.hasPermission(permissionName); - } - return serializedPermissions; - } - - /** - * Checks whether the user has a certain permission, e.g. `READ_MESSAGES`. - * @param {PermissionResolvable} permission The permission to check for - * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permission - * @returns {boolean} - */ - hasPermission(permission, explicit = false) { - permission = this.member.client.resolver.resolvePermission(permission); - if (!explicit && (this.raw & Constants.PermissionFlags.ADMINISTRATOR) > 0) return true; - return (this.raw & permission) > 0; - } - - /** - * Checks whether the user has all specified permissions. - * @param {PermissionResolvable[]} permissions The permissions to check for - * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions - * @returns {boolean} - */ - hasPermissions(permissions, explicit = false) { - return permissions.every(p => this.hasPermission(p, explicit)); - } - - /** - * Checks whether the user has all specified permissions, and lists any missing permissions. - * @param {PermissionResolvable[]} permissions The permissions to check for - * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions - * @returns {PermissionResolvable[]} - */ - missingPermissions(permissions, explicit = false) { - return permissions.filter(p => !this.hasPermission(p, explicit)); - } -} - -module.exports = EvaluatedPermissions; diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index 9b8a5fbc4..5ae1a08da 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -1,8 +1,7 @@ const Channel = require('./Channel'); const Role = require('./Role'); const PermissionOverwrites = require('./PermissionOverwrites'); -const EvaluatedPermissions = require('./EvaluatedPermissions'); -const Constants = require('../util/Constants'); +const Permissions = require('../util/Permissions'); const Collection = require('../util/Collection'); /** @@ -51,12 +50,12 @@ class GuildChannel extends Channel { * Gets the overall set of permissions for a user in this channel, taking into account roles and permission * overwrites. * @param {GuildMemberResolvable} member The user that you want to obtain the overall permissions for - * @returns {?EvaluatedPermissions} + * @returns {?Permissions} */ permissionsFor(member) { member = this.client.resolver.resolveGuildMember(this.guild, member); if (!member) return null; - if (member.id === this.guild.ownerID) return new EvaluatedPermissions(member, Constants.ALL_PERMISSIONS); + if (member.id === this.guild.ownerID) return new Permissions(member, Permissions.ALL); let permissions = 0; @@ -71,10 +70,10 @@ class GuildChannel extends Channel { } permissions |= allow; - const admin = Boolean(permissions & Constants.PermissionFlags.ADMINISTRATOR); - if (admin) permissions = Constants.ALL_PERMISSIONS; + const admin = Boolean(permissions & Permissions.FLAGS.ADMINISTRATOR); + if (admin) permissions = Permissions.ALL; - return new EvaluatedPermissions(member, permissions); + return new Permissions(member, permissions); } overwritesFor(member, verified = false, roles = null) { @@ -151,14 +150,14 @@ class GuildChannel extends Channel { for (const perm in options) { if (options[perm] === true) { - payload.allow |= Constants.PermissionFlags[perm] || 0; - payload.deny &= ~(Constants.PermissionFlags[perm] || 0); + payload.allow |= Permissions.FLAGS[perm] || 0; + payload.deny &= ~(Permissions.FLAGS[perm] || 0); } else if (options[perm] === false) { - payload.allow &= ~(Constants.PermissionFlags[perm] || 0); - payload.deny |= Constants.PermissionFlags[perm] || 0; + payload.allow &= ~(Permissions.FLAGS[perm] || 0); + payload.deny |= Permissions.FLAGS[perm] || 0; } else if (options[perm] === null) { - payload.allow &= ~(Constants.PermissionFlags[perm] || 0); - payload.deny &= ~(Constants.PermissionFlags[perm] || 0); + payload.allow &= ~(Permissions.FLAGS[perm] || 0); + payload.deny &= ~(Permissions.FLAGS[perm] || 0); } } @@ -294,7 +293,7 @@ class GuildChannel extends Channel { */ get deletable() { return this.id !== this.guild.id && - this.permissionsFor(this.client.user).hasPermission(Constants.PermissionFlags.MANAGE_CHANNELS); + this.permissionsFor(this.client.user).hasPermission(Permissions.FLAGS.MANAGE_CHANNELS); } /** diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 135edde9f..037f001ec 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -1,6 +1,6 @@ const TextBasedChannel = require('./interface/TextBasedChannel'); const Role = require('./Role'); -const EvaluatedPermissions = require('./EvaluatedPermissions'); +const Permissions = require('../util/Permissions'); const Constants = require('../util/Constants'); const Collection = require('../util/Collection'); const Presence = require('./Presence').Presence; @@ -241,20 +241,17 @@ class GuildMember { /** * The overall set of permissions for the guild member, taking only roles into account - * @type {EvaluatedPermissions} + * @type {Permissions} * @readonly */ get permissions() { - if (this.user.id === this.guild.ownerID) return new EvaluatedPermissions(this, Constants.ALL_PERMISSIONS); + if (this.user.id === this.guild.ownerID) return new Permissions(this, Permissions.ALL); let permissions = 0; const roles = this.roles; for (const role of roles.values()) permissions |= role.permissions; - const admin = Boolean(permissions & Constants.PermissionFlags.ADMINISTRATOR); - if (admin) permissions = Constants.ALL_PERMISSIONS; - - return new EvaluatedPermissions(this, permissions); + return new Permissions(this, permissions); } /** @@ -266,7 +263,7 @@ class GuildMember { if (this.user.id === this.guild.ownerID) return false; if (this.user.id === this.client.user.id) return false; const clientMember = this.guild.member(this.client.user); - if (!clientMember.hasPermission(Constants.PermissionFlags.KICK_MEMBERS)) return false; + if (!clientMember.hasPermission(Permissions.FLAGS.KICK_MEMBERS)) return false; return clientMember.highestRole.comparePositionTo(this.highestRole) > 0; } @@ -279,14 +276,14 @@ class GuildMember { if (this.user.id === this.guild.ownerID) return false; if (this.user.id === this.client.user.id) return false; const clientMember = this.guild.member(this.client.user); - if (!clientMember.hasPermission(Constants.PermissionFlags.BAN_MEMBERS)) return false; + if (!clientMember.hasPermission(Permissions.FLAGS.BAN_MEMBERS)) return false; return clientMember.highestRole.comparePositionTo(this.highestRole) > 0; } /** * Returns `channel.permissionsFor(guildMember)`. Returns evaluated permissions for a member in a guild channel. * @param {ChannelResolvable} channel Guild channel to use as context - * @returns {?EvaluatedPermissions} + * @returns {?Permissions} */ permissionsIn(channel) { channel = this.client.resolver.resolveChannel(channel); diff --git a/src/structures/Message.js b/src/structures/Message.js index d8a28387e..fc8bf31b5 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -4,6 +4,7 @@ const MessageReaction = require('./MessageReaction'); const Util = require('../util/Util'); const Collection = require('../util/Collection'); const Constants = require('../util/Constants'); +const Permissions = require('../util/Permissions'); let GuildMember; /** @@ -334,7 +335,7 @@ class Message { */ get deletable() { return this.author.id === this.client.user.id || (this.guild && - this.channel.permissionsFor(this.client.user).hasPermission(Constants.PermissionFlags.MANAGE_MESSAGES) + this.channel.permissionsFor(this.client.user).hasPermission(Permissions.FLAGS.MANAGE_MESSAGES) ); } @@ -345,7 +346,7 @@ class Message { */ get pinnable() { return !this.guild || - this.channel.permissionsFor(this.client.user).hasPermission(Constants.PermissionFlags.MANAGE_MESSAGES); + this.channel.permissionsFor(this.client.user).hasPermission(Permissions.FLAGS.MANAGE_MESSAGES); } /** diff --git a/src/structures/Role.js b/src/structures/Role.js index 0cb5f8306..031a7a71d 100644 --- a/src/structures/Role.js +++ b/src/structures/Role.js @@ -1,4 +1,4 @@ -const Constants = require('../util/Constants'); +const Permissions = require('../util/Permissions'); /** * Represents a role on Discord @@ -118,7 +118,7 @@ class Role { get editable() { if (this.managed) return false; const clientMember = this.guild.member(this.client.user); - if (!clientMember.hasPermission(Constants.PermissionFlags.MANAGE_ROLES_OR_PERMISSIONS)) return false; + if (!clientMember.hasPermission(Permissions.FLAGS.MANAGE_ROLES_OR_PERMISSIONS)) return false; return clientMember.highestRole.comparePositionTo(this) > 0; } diff --git a/src/util/Constants.js b/src/util/Constants.js index 56369024a..65d8a08fd 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -371,39 +371,6 @@ exports.DefaultAvatars = { RED: '1cbd08c76f8af6dddce02c5138971129', }; -const PermissionFlags = exports.PermissionFlags = { - CREATE_INSTANT_INVITE: 1 << 0, - KICK_MEMBERS: 1 << 1, - BAN_MEMBERS: 1 << 2, - ADMINISTRATOR: 1 << 3, - MANAGE_CHANNELS: 1 << 4, - MANAGE_GUILD: 1 << 5, - ADD_REACTIONS: 1 << 6, - - READ_MESSAGES: 1 << 10, - SEND_MESSAGES: 1 << 11, - SEND_TTS_MESSAGES: 1 << 12, - MANAGE_MESSAGES: 1 << 13, - EMBED_LINKS: 1 << 14, - ATTACH_FILES: 1 << 15, - READ_MESSAGE_HISTORY: 1 << 16, - MENTION_EVERYONE: 1 << 17, - EXTERNAL_EMOJIS: 1 << 18, - - CONNECT: 1 << 20, - SPEAK: 1 << 21, - MUTE_MEMBERS: 1 << 22, - DEAFEN_MEMBERS: 1 << 23, - MOVE_MEMBERS: 1 << 24, - USE_VAD: 1 << 25, - - CHANGE_NICKNAME: 1 << 26, - MANAGE_NICKNAMES: 1 << 27, - MANAGE_ROLES_OR_PERMISSIONS: 1 << 28, - MANAGE_WEBHOOKS: 1 << 29, - MANAGE_EMOJIS: 1 << 30, -}; - exports.Colors = { DEFAULT: 0x000000, AQUA: 0x1ABC9C, @@ -431,8 +398,3 @@ exports.Colors = { DARK_BUT_NOT_BLACK: 0x2C2F33, NOT_QUITE_BLACK: 0x23272A, }; - -let _ALL_PERMISSIONS = 0; -for (const key in PermissionFlags) _ALL_PERMISSIONS |= PermissionFlags[key]; -exports.ALL_PERMISSIONS = _ALL_PERMISSIONS; -exports.DEFAULT_PERMISSIONS = 104324097; diff --git a/src/util/Permissions.js b/src/util/Permissions.js new file mode 100644 index 000000000..34785ff6b --- /dev/null +++ b/src/util/Permissions.js @@ -0,0 +1,249 @@ +const Constants = require('../util/Constants'); + +/** + * Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of + * permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member + * that override their default permissions. + */ +class Permissions { + /** + * @param {GuildMember} [member] Member the permissions are for __**(deprecated)**__ + * @param {number} bitfield Permissions bitfield to read from + */ + constructor(member, bitfield) { + /** + * Member the permissions are for + * @type {GuildMember} + * @deprecated + */ + this.member = typeof member === 'object' ? member : null; + + /** + * Bitfield of the packed permissions + * @type {number} + */ + this.bitfield = typeof member === 'object' ? bitfield : member; + } + + /** + * Bitfield of the packed permissions + * @type {number} + * @see {@link Permissions#bitfield} + * @deprecated + */ + get raw() { + return this.bitfield; + } + + set raw(raw) { + this.bitfield = raw; + } + + /** + * Checks whether the bitfield has a permission, or multiple permissions. + * @param {PermissionResolvable|PermissionResolvable[]} permission Permission(s) to check for + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {boolean} + */ + has(permission, checkAdmin = true) { + if (permission instanceof Array) return permission.every(p => this.has(p, checkAdmin)); + permission = this.constructor.resolve(permission); + if (checkAdmin && (this.bitfield & this.constructor.FLAGS.ADMINISTRATOR) > 0) return true; + return (this.bitfield & permission) === permission; + } + + /** + * Gets all given permissions that are missing from the bitfield. + * @param {PermissionResolvable[]} permissions Permissions to check for + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {PermissionResolvable[]} + */ + missing(permissions, checkAdmin = true) { + return permissions.filter(p => !this.has(p, checkAdmin)); + } + + /** + * Adds permissions to this one, creating a new instance to represent the new bitfield. + * @param {...PermissionResolvable} permissions Permissions to add + * @returns {Permissions} + */ + add(...permissions) { + let total = 0; + for (let p = 0; p < permissions.length; p++) { + const perm = this.constructor.resolve(permissions[p]); + if ((this.bitfield & perm) !== perm) total |= perm; + } + return new this.constructor(this.bitfield | total); + } + + /** + * Removes permissions to this one, creating a new instance to represent the new bitfield. + * @param {...PermissionResolvable} permissions Permissions to remove + * @returns {Permissions} + */ + remove(...permissions) { + let total = 0; + for (let p = 0; p < permissions.length; p++) { + const perm = this.constructor.resolve(permissions[p]); + if ((this.bitfield & perm) === perm) total |= perm; + } + return new this.constructor(this.bitfield & ~total); + } + + /** + * Gets an object mapping permission name (like `READ_MESSAGES`) to a {@link boolean} indicating whether the + * permission is available. + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @returns {Object} + */ + serialize(checkAdmin = true) { + const serialized = {}; + for (const perm in this.constructor.FLAGS) serialized[perm] = this.has(perm, checkAdmin); + return serialized; + } + + /** + * Checks whether the user has a certain permission, e.g. `READ_MESSAGES`. + * @param {PermissionResolvable} permission The permission to check for + * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permission + * @returns {boolean} + * @see {@link Permissions#has} + * @deprecated + */ + hasPermission(permission, explicit = false) { + return this.has(permission, !explicit); + } + + /** + * Checks whether the user has all specified permissions. + * @param {PermissionResolvable[]} permissions The permissions to check for + * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions + * @returns {boolean} + * @see {@link Permissions#has} + * @deprecated + */ + hasPermissions(permissions, explicit = false) { + return this.has(permissions, !explicit); + } + + /** + * Checks whether the user has all specified permissions, and lists any missing permissions. + * @param {PermissionResolvable[]} permissions The permissions to check for + * @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions + * @returns {PermissionResolvable[]} + * @see {@link Permissions#missing} + * @deprecated + */ + missingPermissions(permissions, explicit = false) { + return this.missing(permissions, !explicit); + } + + /** + * Data that can be resolved to give a permission number. This can be: + * - A string (see {@link Permissions.flags}) + * - A permission number + * @typedef {string|number} PermissionResolvable + */ + + /** + * Resolves permissions to their numeric form. + * @param {PermissionResolvable|Permissions[]} permission - Permission(s) to resolve + * @returns {number|number[]} + */ + static resolve(permission) { + if (permission instanceof Array) return permission.map(p => this.resolve(p)); + if (typeof permission === 'string') permission = this.FLAGS[permission]; + if (typeof permission !== 'number' || permission < 1) throw new RangeError(Constants.Errors.NOT_A_PERMISSION); + return permission; + } +} + +/** + * Numeric permission flags. All available properties: + * - `ADMINISTRATOR` (implicitly has *all* permissions, and bypasses all channel overwrites) + * - `CREATE_INSTANT_INVITE` (create invitations to the guild) + * - `KICK_MEMBERS` + * - `BAN_MEMBERS` + * - `MANAGE_CHANNELS` (edit and reorder channels) + * - `MANAGE_GUILD` (edit the guild information, region, etc.) + * - `ADD_REACTIONS` (add new reactions to messages) + * - `READ_MESSAGES` + * - `SEND_MESSAGES` + * - `SEND_TTS_MESSAGES` + * - `MANAGE_MESSAGES` (delete messages and reactions) + * - `EMBED_LINKS` (links posted will have a preview embedded) + * - `ATTACH_FILES` + * - `READ_MESSAGE_HISTORY` (view messages that were posted prior to opening Discord) + * - `MENTION_EVERYONE` + * - `USE_EXTERNAL_EMOJIS` (use emojis from different guilds) + * - `EXTERNAL_EMOJIS` __**(deprecated)**__ + * - `CONNECT` (connect to a voice channel) + * - `SPEAK` (speak in a voice channel) + * - `MUTE_MEMBERS` (mute members across all voice channels) + * - `DEAFEN_MEMBERS` (deafen members across all voice channels) + * - `MOVE_MEMBERS` (move members between voice channels) + * - `USE_VAD` (use voice activity detection) + * - `CHANGE_NICKNAME` + * - `MANAGE_NICKNAMES` (change other members' nicknames) + * - `MANAGE_ROLES` + * - `MANAGE_ROLES_OR_PERMISSIONS` __**(deprecated)**__ + * - `MANAGE_WEBHOOKS` + * - `MANAGE_EMOJIS' + * @type {Object} + * @see {@link https://discordapp.com/developers/docs/topics/permissions} + */ +Permissions.FLAGS = { + CREATE_INSTANT_INVITE: 1 << 0, + KICK_MEMBERS: 1 << 1, + BAN_MEMBERS: 1 << 2, + ADMINISTRATOR: 1 << 3, + MANAGE_CHANNELS: 1 << 4, + MANAGE_GUILD: 1 << 5, + ADD_REACTIONS: 1 << 6, + + READ_MESSAGES: 1 << 10, + SEND_MESSAGES: 1 << 11, + SEND_TTS_MESSAGES: 1 << 12, + MANAGE_MESSAGES: 1 << 13, + EMBED_LINKS: 1 << 14, + ATTACH_FILES: 1 << 15, + READ_MESSAGE_HISTORY: 1 << 16, + MENTION_EVERYONE: 1 << 17, + EXTERNAL_EMOJIS: 1 << 18, + USE_EXTERNAL_EMOJIS: 1 << 18, + + CONNECT: 1 << 20, + SPEAK: 1 << 21, + MUTE_MEMBERS: 1 << 22, + DEAFEN_MEMBERS: 1 << 23, + MOVE_MEMBERS: 1 << 24, + USE_VAD: 1 << 25, + + CHANGE_NICKNAME: 1 << 26, + MANAGE_NICKNAMES: 1 << 27, + MANAGE_ROLES: 1 << 28, + MANAGE_ROLES_OR_PERMISSIONS: 1 << 28, + MANAGE_WEBHOOKS: 1 << 29, + MANAGE_EMOJIS: 1 << 30, +}; + +/** + * Bitfield representing every permission combined + * @type {number} + */ +Permissions.ALL = Object.values(Permissions.FLAGS).reduce((all, p) => all | p, 0); + +/** + * Bitfield representing the default permissions for users + * @type {number} + */ +Permissions.DEFAULT = 104324097; + +/** + * The final evaluated permissions for a member in a channel + * @class EvaluatedPermissions + * @see {@link Permissions} + * @deprecated + */ + +module.exports = Permissions;