diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index a7c5b5244..36c8a47d6 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -92,31 +92,16 @@ 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 + * Gets the overall set of permissions for a member or role in this channel, taking into account channel overwrites. + * @param {GuildMemberResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for * @returns {?Permissions} */ - permissionsFor(member) { - member = this.guild.members.resolve(member); - if (!member) return null; - if (member.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze(); - - const roles = member.roles; - const permissions = new Permissions(roles.map(role => role.permissions)); - - if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze(); - - const overwrites = this.overwritesFor(member, true, roles); - - return permissions - .remove(overwrites.everyone ? overwrites.everyone.denied : 0) - .add(overwrites.everyone ? overwrites.everyone.allowed : 0) - .remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.denied) : 0) - .add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allowed) : 0) - .remove(overwrites.member ? overwrites.member.denied : 0) - .add(overwrites.member ? overwrites.member.allowed : 0) - .freeze(); + permissionsFor(memberOrRole) { + const member = this.guild.members.resolve(memberOrRole); + if (member) return this.memberPermissions(member); + const role = this.guild.roles.resolve(memberOrRole); + if (role) return this.rolePermissions(role); + return null; } overwritesFor(member, verified = false, roles = null) { @@ -145,6 +130,52 @@ class GuildChannel extends Channel { }; } + /** + * Gets the overall set of permissions for a member in this channel, taking into account channel overwrites. + * @param {GuildMember} member The member to obtain the overall permissions for + * @returns {Permissions} + * @private + */ + memberPermissions(member) { + if (member.id === this.guild.ownerID) return new Permissions(Permissions.ALL).freeze(); + + const roles = member.roles; + const permissions = new Permissions(roles.map(role => role.permissions)); + + if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze(); + + const overwrites = this.overwritesFor(member, true, roles); + + return permissions + .remove(overwrites.everyone ? overwrites.everyone.denied : 0) + .add(overwrites.everyone ? overwrites.everyone.allowed : 0) + .remove(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.denied) : 0) + .add(overwrites.roles.length > 0 ? overwrites.roles.map(role => role.allowed) : 0) + .remove(overwrites.member ? overwrites.member.denied : 0) + .add(overwrites.member ? overwrites.member.allowed : 0) + .freeze(); + } + + /** + * Gets the overall set of permissions for a role in this channel, taking into account channel overwrites. + * @param {Role} role The role to obtain the overall permissions for + * @returns {Permissions} + * @private + */ + rolePermissions(role) { + if (role.permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze(); + + const everyoneOverwrites = this.permissionOverwrites.get(this.guild.id); + const roleOverwrites = this.permissionOverwrites.get(role.id); + + return role.permissions + .remove(everyoneOverwrites ? everyoneOverwrites.denied : 0) + .add(everyoneOverwrites ? everyoneOverwrites.allowed : 0) + .remove(roleOverwrites ? roleOverwrites.denied : 0) + .add(roleOverwrites ? roleOverwrites.allowed : 0) + .freeze(); + } + /** * An object mapping permission flags to `true` (enabled), `null` (default) or `false` (disabled). * ```js diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index c7384d875..08561c757 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -295,9 +295,9 @@ class GuildMember extends Base { * @returns {?Permissions} */ permissionsIn(channel) { - channel = this.client.channels.resolve(channel); - if (!channel || !channel.guild) throw new Error('GUILD_CHANNEL_RESOLVE'); - return channel.permissionsFor(this); + channel = this.guild.channels.resolve(channel); + if (!channel) throw new Error('GUILD_CHANNEL_RESOLVE'); + return channel.memberPermissions(this); } /** diff --git a/src/structures/Role.js b/src/structures/Role.js index 39c28e11b..1d82f63ba 100644 --- a/src/structures/Role.js +++ b/src/structures/Role.js @@ -195,6 +195,18 @@ class Role extends Base { }); } + /** + * Returns `channel.permissionsFor(role)`. Returns permissions for a role in a guild channel, + * taking into account permission overwrites. + * @param {ChannelResolvable} channel The guild channel to use as context + * @returns {?Permissions} + */ + permissionsIn(channel) { + channel = this.guild.channels.resolve(channel); + if (!channel) throw new Error('GUILD_CHANNEL_RESOLVE'); + return channel.rolePermissions(this); + } + /** * Sets a new name for the role. * @param {string} name The new name of the role