Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: PermissionOverwriteManager #5318

Merged
merged 33 commits into from
Jul 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
93eef9a
Merge pull request #4 from discordjs/master
Dec 18, 2020
c39c0cc
Merge pull request #8 from discordjs/master
Feb 12, 2021
66dd1ca
feat: PermissionOverwriteManager
Feb 12, 2021
a8f38b5
refactor: GuildChannel
Feb 12, 2021
304a96e
refactor: PermissionOverwrites
Feb 12, 2021
aacc25c
typings: various stuff
Feb 12, 2021
b1b2e70
index: export PermissionOverwriteManager
Feb 12, 2021
f15fbb4
esm: export PermissionOverwriteManager
Feb 12, 2021
4b451da
typings: fix order
Feb 12, 2021
255f7be
index: fix export order
Feb 12, 2021
32bec30
esm: fix export order
Feb 12, 2021
38ea934
feat(PermissionOverwriteManager): make use of OverwriteTypes
Feb 12, 2021
d3ceb2b
typings: add more resolvables
Feb 12, 2021
42b993c
Merge branch 'master' into feat-permissionoverwritemanager
Apr 14, 2021
7c91eee
Merge branch 'master' into feat-permissionoverwritemanager
Apr 29, 2021
83bf188
typings: rebase
May 10, 2021
48f3550
feat: address requested changes
May 11, 2021
eda6462
typings: +1
May 11, 2021
98d1c7f
feat: remove unnecessary check
May 11, 2021
358aa73
feat: remove unnecessary check x2
May 11, 2021
814fc70
feat: more changes!
May 11, 2021
7b57c30
feat: missed change
May 11, 2021
f01e805
typings: fix fucked up trailing whitespace
May 11, 2021
54903aa
Merge branch 'master' into feat-permissionoverwritemanager
May 12, 2021
9a52ec5
Merge branch 'master' into feat-permissionoverwritemanager
May 28, 2021
a6fa160
feat: use PermissionOverwriteOptions over PermissionOverwriteOption
May 28, 2021
8fa9b31
Merge branch 'master' into feat-permissionoverwritemanager
Jun 3, 2021
73d8beb
feat: delete index.mjs
Jun 6, 2021
e7b0c61
Merge branch 'master' into feat-permissionoverwritemanager
Jun 13, 2021
089097d
Merge branch 'master' into feat-permissionoverwritemanager
Jun 15, 2021
3700199
feat: address requested changes
Jun 22, 2021
a220200
Merge branch 'master' into feat-permissionoverwritemanager
Jul 2, 2021
c612029
feat: address requested changes x2
Jul 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module.exports = {
ReactionManager: require('./managers/ReactionManager'),
ReactionUserManager: require('./managers/ReactionUserManager'),
MessageManager: require('./managers/MessageManager'),
PermissionOverwriteManager: require('./managers/PermissionOverwriteManager'),
PresenceManager: require('./managers/PresenceManager'),
RoleManager: require('./managers/RoleManager'),
ThreadManager: require('./managers/ThreadManager'),
Expand Down
147 changes: 147 additions & 0 deletions src/managers/PermissionOverwriteManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
'use strict';

const BaseManager = require('./BaseManager');
const { TypeError } = require('../errors');
const PermissionOverwrites = require('../structures/PermissionOverwrites');
const Role = require('../structures/Role');
const Collection = require('../util/Collection');
const { OverwriteTypes } = require('../util/Constants');

/**
* Manages API methods for guild channel permission overwrites and stores their cache.
* @extends {BaseManager}
*/
class PermissionOverwriteManager extends BaseManager {
Extroonie marked this conversation as resolved.
Show resolved Hide resolved
constructor(channel, iterable) {
super(channel.client, iterable, PermissionOverwrites);

/**
* The channel of the permission overwrite this manager belongs to
* @type {GuildChannel}
*/
this.channel = channel;
}

/**
* The cache of this Manager
* @type {Collection<Snowflake, PermissionOverwrites>}
* @name PermissionOverwriteManager#cache
*/

add(data, cache) {
return super.add(data, cache, { extras: [this.channel] });
}

/**
* Replaces the permission overwrites in this channel.
* @param {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} overwrites
* Permission overwrites the channel gets updated with
* @param {string} [reason] Reason for updating the channel overwrites
* @returns {Promise<GuildChannel>}
* @example
* message.channel.permissionOverwrites.set([
* {
* id: message.author.id,
* deny: [Permissions.FLAGS.VIEW_CHANNEL],
* },
* ], 'Needed to change permissions');
*/
set(overwrites, reason) {
if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {
throw new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true);
}
return this.channel.edit({ permissionOverwrites: overwrites, reason });
}

/**
* Extra information about the overwrite
* @typedef {Object} GuildChannelOverwriteOptions
* @property {string} [reason] Reason for creating/editing this overwrite
* @property {number} [type] The type of overwrite, either `0` for a role or `1` for a member. Use this to bypass
* automatic resolution of type that results in an error for uncached structure
*/

/**
* Creates or edits permission overwrites for a user or role in this channel.
* @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
* @param {PermissionOverwriteOptions} options The options for the update
* @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update
* @param {PermissionOverwrites} [existing] The existing overwrites to merge with this update
* @returns {Promise<GuildChannel>}
* @private
*/
Extroonie marked this conversation as resolved.
Show resolved Hide resolved
async upsert(userOrRole, options, overwriteOptions = {}, existing) {
let userOrRoleID = this.channel.guild.roles.resolveID(userOrRole) ?? this.client.users.resolveID(userOrRole);
let { type, reason } = overwriteOptions;
if (typeof type !== 'number') {
userOrRole = this.channel.guild.roles.resolve(userOrRole) ?? this.client.users.resolve(userOrRole);
if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role'));
type = userOrRole instanceof Role ? OverwriteTypes.role : OverwriteTypes.member;
}

const { allow, deny } = PermissionOverwrites.resolveOverwriteOptions(options, existing);

await this.client.api
.channels(this.channel.id)
.permissions(userOrRoleID)
.put({
data: { id: userOrRoleID, type, allow, deny },
reason,
});
return this.channel;
}

/**
* Creates permission overwrites for a user or role in this channel, or replaces them if already present.
* @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
* @param {PermissionOverwriteOptions} options The options for the update
* @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update
* @returns {Promise<GuildChannel>}
* @example
* // Create or Replace permission overwrites for a message author
* message.channel.permissionOverwrites.create(message.author, {
* SEND_MESSAGES: false
* })
* .then(channel => console.log(channel.permissionOverwrites.cache.get(message.author.id)))
* .catch(console.error);
*/
create(userOrRole, options, overwriteOptions) {
return this.upsert(userOrRole, options, overwriteOptions);
}

/**
* Edits permission overwrites for a user or role in this channel, or creates an entry if not already present.
* @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
* @param {PermissionOverwriteOptions} options The options for the update
* @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update
* @returns {Promise<GuildChannel>}
* @example
* // Edit or Create permission overwrites for a message author
* message.channel.permissionOverwrites.edit(message.author, {
* SEND_MESSAGES: false
* })
* .then(channel => console.log(channel.permissionOverwrites.cache.get(message.author.id)))
* .catch(console.error);
*/
edit(userOrRole, options, overwriteOptions) {
userOrRole = this.channel.guild.roles.resolveID(userOrRole) ?? this.client.users.resolveID(userOrRole);
const existing = this.cache.get(userOrRole);
return this.upsert(userOrRole, options, overwriteOptions, existing);
}

/**
* Deletes permission overwrites for a user or role in this channel.
* @param {UserResolvable|RoleResolvable} userOrRole The user or role to delete
* @param {string} [reason] The reason for deleting the overwrite
* @returns {GuildChannel}
*/
async delete(userOrRole, reason) {
userOrRole = this.channel.guild.roles.resolveID(userOrRole) ?? this.client.users.resolveID(userOrRole);
if (!userOrRole) throw new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role');

await this.client.api.channels(this.channel.id).permissions(userOrRole.id).delete({ reason });
return this.channel;
}
}

module.exports = PermissionOverwriteManager;
119 changes: 12 additions & 107 deletions src/structures/GuildChannel.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
const Channel = require('./Channel');
const Invite = require('./Invite');
const PermissionOverwrites = require('./PermissionOverwrites');
const Role = require('./Role');
const { Error, TypeError } = require('../errors');
const { Error } = require('../errors');
const PermissionOverwriteManager = require('../managers/PermissionOverwriteManager');
const Collection = require('../util/Collection');
const { ChannelTypes } = require('../util/Constants');
const { OverwriteTypes } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const Util = require('../util/Util');

Expand All @@ -28,7 +27,7 @@ class GuildChannel extends Channel {
* @param {APIChannel} data The data for the guild channel
*/
constructor(guild, data) {
super(guild.client, data);
super(guild.client, data, false);

/**
* The guild the channel is in
Expand All @@ -37,7 +36,13 @@ class GuildChannel extends Channel {
this.guild = guild;

this.parentID = this.parentID ?? null;
this.permissionOverwrites = this.permissionOverwrites ?? new Collection();
/**
* A manager of permission overwrites that belong to this channel
* @type {PermissionOverwriteManager}
*/
this.permissionOverwrites = new PermissionOverwriteManager(this);
Extroonie marked this conversation as resolved.
Show resolved Hide resolved

this._patch(data);
}

_patch(data) {
Expand Down Expand Up @@ -68,13 +73,9 @@ class GuildChannel extends Channel {
}

if ('permission_overwrites' in data) {
/**
* A map of permission overwrites in this channel for roles and users
* @type {Collection<Snowflake, PermissionOverwrites>}
*/
this.permissionOverwrites = new Collection();
Extroonie marked this conversation as resolved.
Show resolved Hide resolved
this.permissionOverwrites.cache.clear();
for (const overwrite of data.permission_overwrites) {
this.permissionOverwrites.set(overwrite.id, new PermissionOverwrites(this, overwrite));
this.permissionOverwrites.add(overwrite);
}
}
}
Expand Down Expand Up @@ -220,102 +221,6 @@ class GuildChannel extends Channel {
.freeze();
}

/**
* Replaces the permission overwrites in this channel.
* @param {OverwriteResolvable[]|Collection<Snowflake, OverwriteResolvable>} overwrites
* Permission overwrites the channel gets updated with
* @param {string} [reason] Reason for updating the channel overwrites
* @returns {Promise<GuildChannel>}
* @example
* channel.overwritePermissions([
* {
* id: message.author.id,
* deny: [Permissions.FLAGS.VIEW_CHANNEL],
* },
* ], 'Needed to change permissions');
*/
async overwritePermissions(overwrites, reason) {
if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {
throw new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true);
}
await this.edit({ permissionOverwrites: overwrites }, reason);
return this;
}

/**
* Extra information about the overwrite
* @typedef {Object} GuildChannelOverwriteOptions
* @property {string} [reason] Reason for creating/editing this overwrite
* @property {number} [type] The type of overwrite, either `0` for a role or `1` for a member. Use this to bypass
* automatic resolution of type that results in an error for uncached structure
*/

/**
* Updates permission overwrites for a user or role in this channel, or creates an entry if not already present.
* @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
* @param {PermissionOverwriteOptions} options The options for the update
* @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update
* @returns {Promise<GuildChannel>}
* @example
* // Update or Create permission overwrites for a message author
* message.channel.updateOverwrite(message.author, {
* SEND_MESSAGES: false
* })
* .then(channel => console.log(channel.permissionOverwrites.get(message.author.id)))
* .catch(console.error);
*/
async updateOverwrite(userOrRole, options, overwriteOptions = {}) {
const userOrRoleID = this.guild.roles.resolveID(userOrRole) ?? this.client.users.resolveID(userOrRole);
const { reason } = overwriteOptions;
const existing = this.permissionOverwrites.get(userOrRoleID);
if (existing) {
await existing.update(options, reason);
} else {
await this.createOverwrite(userOrRole, options, overwriteOptions);
}
return this;
}

/**
* Creates permission overwrites for a user or role in this channel, or replaces them if already present.
* @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
* @param {PermissionOverwriteOptions} options The options for the update
* @param {GuildChannelOverwriteOptions} [overwriteOptions] The extra information for the update
* @returns {Promise<GuildChannel>}
* @example
* // Create or Replace permission overwrites for a message author
* message.channel.createOverwrite(message.author, {
* SEND_MESSAGES: false
* })
* .then(channel => console.log(channel.permissionOverwrites.get(message.author.id)))
* .catch(console.error);
*/
createOverwrite(userOrRole, options, overwriteOptions = {}) {
let userOrRoleID = this.guild.roles.resolveID(userOrRole) ?? this.client.users.resolveID(userOrRole);
let { type, reason } = overwriteOptions;
if (typeof type !== 'number') {
userOrRole = this.guild.roles.resolve(userOrRole) ?? this.client.users.resolve(userOrRole);
if (!userOrRole) return Promise.reject(new TypeError('INVALID_TYPE', 'parameter', 'User nor a Role'));
userOrRoleID = userOrRole.id;
type = userOrRole instanceof Role ? OverwriteTypes.role : OverwriteTypes.member;
}
const { allow, deny } = PermissionOverwrites.resolveOverwriteOptions(options);

return this.client.api
.channels(this.id)
.permissions(userOrRoleID)
.put({
data: {
id: userOrRoleID,
type,
allow,
deny,
},
reason,
})
.then(() => this);
}

/**
* Locks in the permission overwrites from the parent channel.
* @returns {Promise<GuildChannel>}
Expand Down
33 changes: 12 additions & 21 deletions src/structures/PermissionOverwrites.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
'use strict';

const Base = require('./Base');
const Role = require('./Role');
const { TypeError } = require('../errors');
const { OverwriteTypes } = require('../util/Constants');
const Permissions = require('../util/Permissions');

/**
* Represents a permission overwrite for a role or member in a guild channel.
* @extends {Base}
*/
Extroonie marked this conversation as resolved.
Show resolved Hide resolved
class PermissionOverwrites {
constructor(guildChannel, data) {
class PermissionOverwrites extends Base {
constructor(client, data, channel) {
super(client);

/**
* The GuildChannel this overwrite is for
* @name PermissionOverwrites#channel
* @type {GuildChannel}
* @readonly
*/
Object.defineProperty(this, 'channel', { value: guildChannel });
Object.defineProperty(this, 'channel', { value: channel });

if (data) this._patch(data);
}
Expand Down Expand Up @@ -48,33 +52,20 @@ class PermissionOverwrites {
}

/**
* Updates this permissionOverwrites.
* Edits this Permission Overwrite.
* @param {PermissionOverwriteOptions} options The options for the update
* @param {string} [reason] Reason for creating/editing this overwrite
* @returns {Promise<PermissionOverwrites>}
* @example
* // Update permission overwrites
* permissionOverwrites.update({
* permissionOverwrites.edit({
* SEND_MESSAGES: false
* })
* .then(channel => console.log(channel.permissionOverwrites.get(message.author.id)))
* .catch(console.error);
*/
async update(options, reason) {
const { allow, deny } = this.constructor.resolveOverwriteOptions(options, this);

await this.channel.client.api
.channels(this.channel.id)
.permissions(this.id)
.put({
data: {
id: this.id,
type: OverwriteTypes[this.type],
allow,
deny,
},
reason,
});
async edit(options, reason) {
await this.channel.permissionOverwrites.upsert(this.id, options, { type: OverwriteTypes[this.type], reason }, this);
return this;
}

Expand All @@ -84,7 +75,7 @@ class PermissionOverwrites {
* @returns {Promise<PermissionOverwrites>}
*/
async delete(reason) {
await this.channel.client.api.channels(this.channel.id).permissions(this.id).delete({ reason });
await this.channel.permissionOverwrites.delete(this.id, reason);
return this;
}

Expand Down
Loading