Files
discord.js/src/structures/GuildChannel.js
2016-11-12 20:52:37 -05:00

293 lines
9.0 KiB
JavaScript

const Channel = require('./Channel');
const Role = require('./Role');
const PermissionOverwrites = require('./PermissionOverwrites');
const EvaluatedPermissions = require('./EvaluatedPermissions');
const Constants = require('../util/Constants');
const Collection = require('../util/Collection');
const arraysEqual = require('../util/ArraysEqual');
/**
* Represents a guild channel (i.e. text channels and voice channels)
* @extends {Channel}
*/
class GuildChannel extends Channel {
constructor(guild, data) {
super(guild.client, data);
/**
* The guild the channel is in
* @type {Guild}
*/
this.guild = guild;
}
setup(data) {
super.setup(data);
/**
* The name of the guild channel
* @type {string}
*/
this.name = data.name;
/**
* The position of the channel in the list.
* @type {number}
*/
this.position = data.position;
/**
* A map of permission overwrites in this channel for roles and users.
* @type {Collection<string, PermissionOverwrites>}
*/
this.permissionOverwrites = new Collection();
if (data.permission_overwrites) {
for (const overwrite of data.permission_overwrites) {
this.permissionOverwrites.set(overwrite.id, new PermissionOverwrites(this, overwrite));
}
}
}
/**
* 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}
*/
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);
let permissions = 0;
const roles = member.roles;
for (const role of roles.values()) permissions |= role.permissions;
const overwrites = this.overwritesFor(member, true, roles);
for (const overwrite of overwrites.role.concat(overwrites.member)) {
permissions &= ~overwrite.denyData;
permissions |= overwrite.allowData;
}
const admin = Boolean(permissions & Constants.PermissionFlags.ADMINISTRATOR);
if (admin) permissions = Constants.ALL_PERMISSIONS;
return new EvaluatedPermissions(member, permissions);
}
overwritesFor(member, verified = false, roles = null) {
if (!verified) member = this.client.resolver.resolveGuildMember(this.guild, member);
if (!member) return [];
roles = roles || member.roles;
const roleOverwrites = [];
const memberOverwrites = [];
for (const overwrite of this.permissionOverwrites.values()) {
if (overwrite.id === member.id) {
memberOverwrites.push(overwrite);
} else if (roles.has(overwrite.id)) {
roleOverwrites.push(overwrite);
}
}
return {
role: roleOverwrites,
member: memberOverwrites,
};
}
/**
* An object mapping permission flags to `true` (enabled) or `false` (disabled)
* ```js
* {
* 'SEND_MESSAGES': true,
* 'ATTACH_FILES': false,
* }
* ```
* @typedef {Object} PermissionOverwriteOptions
*/
/**
* Overwrites the permissions for a user or role in this channel.
* @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
* @param {PermissionOverwriteOptions} options The configuration for the update
* @returns {Promise}
* @example
* // overwrite permissions for a message author
* message.channel.overwritePermissions(message.author, {
* SEND_MESSAGES: false
* })
* .then(() => console.log('Done!'))
* .catch(console.error);
*/
overwritePermissions(userOrRole, options) {
const payload = {
allow: 0,
deny: 0,
};
if (userOrRole instanceof Role) {
payload.type = 'role';
} else if (this.guild.roles.has(userOrRole)) {
userOrRole = this.guild.roles.get(userOrRole);
payload.type = 'role';
} else {
userOrRole = this.client.resolver.resolveUser(userOrRole);
payload.type = 'member';
if (!userOrRole) return Promise.reject(new TypeError('Supplied parameter was neither a User nor a Role.'));
}
payload.id = userOrRole.id;
const prevOverwrite = this.permissionOverwrites.get(userOrRole.id);
if (prevOverwrite) {
payload.allow = prevOverwrite.allowData;
payload.deny = prevOverwrite.denyData;
}
for (const perm in options) {
if (options[perm] === true) {
payload.allow |= Constants.PermissionFlags[perm] || 0;
payload.deny &= ~(Constants.PermissionFlags[perm] || 0);
} else if (options[perm] === false) {
payload.allow &= ~(Constants.PermissionFlags[perm] || 0);
payload.deny |= Constants.PermissionFlags[perm] || 0;
} else if (options[perm] === null) {
payload.allow &= ~(Constants.PermissionFlags[perm] || 0);
payload.deny &= ~(Constants.PermissionFlags[perm] || 0);
}
}
return this.client.rest.methods.setChannelOverwrite(this, payload);
}
/**
* The data for a guild channel
* @typedef {Object} ChannelData
* @property {string} [name] The name of the channel
* @property {number} [position] The position of the channel
* @property {string} [topic] The topic of the text channel
* @property {number} [bitrate] The bitrate of the voice channel
* @property {number} [userLimit] The user limit of the channel
*/
/**
* Edits the channel
* @param {ChannelData} data The new data for the channel
* @returns {Promise<GuildChannel>}
* @example
* // edit a channel
* channel.edit({name: 'new-channel'})
* .then(c => console.log(`Edited channel ${c}`))
* .catch(console.error);
*/
edit(data) {
return this.client.rest.methods.updateChannel(this, data);
}
/**
* Set a new name for the guild channel
* @param {string} name The new name for the guild channel
* @returns {Promise<GuildChannel>}
* @example
* // set a new channel name
* channel.setName('not_general')
* .then(newChannel => console.log(`Channel's new name is ${newChannel.name}`))
* .catch(console.error);
*/
setName(name) {
return this.edit({ name });
}
/**
* Set a new position for the guild channel
* @param {number} position The new position for the guild channel
* @returns {Promise<GuildChannel>}
* @example
* // set a new channel position
* channel.setPosition(2)
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
* .catch(console.error);
*/
setPosition(position) {
return this.client.rest.methods.updateChannel(this, { position });
}
/**
* Set a new topic for the guild channel
* @param {string} topic The new topic for the guild channel
* @returns {Promise<GuildChannel>}
* @example
* // set a new channel topic
* channel.setTopic('needs more rate limiting')
* .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))
* .catch(console.error);
*/
setTopic(topic) {
return this.client.rest.methods.updateChannel(this, { topic });
}
/**
* Options given when creating a guild channel invite
* @typedef {Object} InviteOptions
* @property {boolean} [temporary=false] Whether the invite should kick users after 24hrs if they are not given a role
* @property {number} [maxAge=0] Time in seconds the invite expires in
* @property {number} [maxUses=0] Maximum amount of uses for this invite
*/
/**
* Create an invite to this guild channel
* @param {InviteOptions} [options={}] The options for the invite
* @returns {Promise<Invite>}
*/
createInvite(options = {}) {
return this.client.rest.methods.createChannelInvite(this, options);
}
/**
* Checks if this channel has the same type, topic, position, name, overwrites and ID as another channel.
* In most cases, a simple `channel.id === channel2.id` will do, and is much faster too.
* @param {GuildChannel} channel The channel to compare this channel to
* @returns {boolean}
*/
equals(channel) {
let equal = channel &&
this.id === channel.id &&
this.type === channel.type &&
this.topic === channel.topic &&
this.position === channel.position &&
this.name === channel.name;
if (equal) {
if (this.permissionOverwrites && channel.permissionOverwrites) {
const thisIDSet = this.permissionOverwrites.keyArray();
const otherIDSet = channel.permissionOverwrites.keyArray();
equal = arraysEqual(thisIDSet, otherIDSet);
} else {
equal = !this.permissionOverwrites && !channel.permissionOverwrites;
}
}
return equal;
}
/**
* When concatenated with a string, this automatically returns the channel's mention instead of the Channel object.
* @returns {string}
* @example
* // Outputs: Hello from #general
* console.log(`Hello from ${channel}`);
* @example
* // Outputs: Hello from #general
* console.log('Hello from ' + channel);
*/
toString() {
return `<#${this.id}>`;
}
}
module.exports = GuildChannel;