"use strict";
// models & utils
const Channel = require('./Channel');
const { ENDPOINTS } = require('../utils/Constants').HTTP;
const { PERMISSIONS } = require('../utils/Constants');
const Permissions = require('../utils/Permissions');
const Store = require('../utils/Store');
/**
* @extends Channel Represents a Guild Channel
* @prop {Guild} guild The guild the channel is in
* @prop {Snowflake} id The id of the guild channel
* @prop {String} name The name of the guild channel
* @prop {Array} permissionOverwrites An array of Permission Overwrites for the channel
* @prop {Number} position The position of the Channel
* @prop {String} type The type of the channel
* * `text` If the channel is a text channel
* * `dm` If the channel is a dm channel
* * `voice` If the channel is a voice channel
* * `groupdm` If the channel is a group dm channel
* * `category` if the channel is a Channel Category
*/
class GuildChannel extends Channel {
constructor(client, data) {
super(client, data);
Object.defineProperty(this, 'client', { value: client });
this.guild = data.guild;
this.name = data.name;
this.nsfw = data.nsfw;
this.permissionOverwrites = data.permission_overwrites;
this.position = data.position;
}
/**
* Edits the channel permission for the user or role
* @param {Snowflake} userOrRole The id of the user or role
* @param {Object} [options] Options for the permission change
* @param {String} [options.allow] The name of the permission to allow for the role or user
* @param {String} [options.deny] The name of the permission to deny for the role or user
* @param {String} [options.type] "member" for a user or "role" for a role
* @returns {Promise<Member|Role>}
*/
changePermissions(userOrRole, options = {}) {
if (options.allow && PERMISSIONS.hasOwnProperty(options.allow)) {
options.allow = PERMISSIONS[options.allow];
};
if (options.deny && PERMISSIONS.hasOwnProperty(options.deny)) {
options.deny = PERMISSIONS[options.deny];
};
if (options.type)
options.type = options.type.toLowerCase();
return this.client.rest.request("PUT", ENDPOINTS.CHANNEL_PERMISSION(this.id, userOrRole), {
data: {
allow: options.allow,
deny: options.deny,
type: options.type
}
}).then(() => {
if (options.type.toLowerCase() === 'member') {
return this.guild ? this.guild.members.get(userOrRole) : null;
} else if (options.type.toLowerCase() === 'role') {
return this.guild ? this.guild.roles.get(userOrRole) : null;
}
});
}
/**
* Checks a certain permission for a member in a Guild Channel
* * This function is still in testing and might not work. ( Small Chance of not working )
* @param {Snowlake} memberID The id of the member
* @param {String} permissionName The name of the permission to check
* @returns {Boolean}
*/
permissionsFor(memberID, permissionName) {
let member = this.guild.members.get(memberID);
let permissions = this.client.permissions.get(permissionName);
// If the member has administrator permissions, return true since administrator overrides any Channel overwrite
if (member.permissions.has('administrator')) return true;
// Overwrites cache
let overwrites = new Store();
for (var i = 0; i < this.permissionOverwrites.length; i++) {
overwrites.set(this.permissionOverwrites[i].id, this.permissionOverwrites[i]);
};
// Role Specific Overwrites
let roleIDs = member.roles.keyArray()
let perm_allow = 0;
let perm_deny = 0;
for (var roleID in roleIDs) {
let role = overwrites.get(roleIDs[roleID]);
if (role) {
perm_allow |= role.allow;
perm_deny |= role.deny;
};
};
permissions |= perm_allow;
permissions &= ~perm_deny;
// Member specific Overwrites
let overwrite_member = overwrites.get(member.user.id);
if (overwrite_member) {
permissions &= ~overwrite_member.deny;
permissions |= overwrite_member.allow;
}
return new Permissions(permissions).has(permissionName);
}
/**
* Closes a channel
* @returns {Promise<TextChannel|VoiceChannel|CategoryChannell>}
*/
close() {
return this.client.rest.request("DELETE", ENDPOINTS.CHANNEL(this.id))
.then(() => {
return this;
});
}
/**
* Creates an invite for the guild channel
* @param {Object} [options] Options for creating the invite
* @param {Number} [options.maxAge=86400] Duration of invite in seconds, or 0 for never
* @param {Number} [options.maxUses=0] Maximum uses for the invite, or 0 for unlimited
* @param {Boolean} [options.temporary=false] Whether this invite should be temporary
* @param {Boolean} [options.unique=] If true, don't try to reuse a similar invite
* @returns {Promise<Invite>}
*/
createInvite(options = { maxAge: 86400, maxUses: 0, temporary: false, unique: false }) {
return this.client.rest.request("POST", ENDPOINTS.CHANNEL_INVITES(this.id), {
data: {
max_age: options.maxAge,
max_uses: options.maxUses,
temporary: options.temporary,
unique: options.unique
}
}).then(res => {
return res.data;
});
}
/**
* Similar to `GuildChannel#delete`.
* Closes a channel
* @returns {Promise<TextChannel|VoiceChannel|CategoryChannell>}
*/
delete() {
this.close();
}
/**
* Edits the channel
* @param {String} [name] The new name of the channel
* @param {Number} [position] The new position of the channel
* @returns {Promise<TextChannel|VoiceChannel|CategoryChannel>}
*/
edit(name, position) {
if (!name) name = this.name;
if (!position) position = this.position;
return this.client.rest.request("PATCH", ENDPOINTS.CHANNEL(this.id), {
data: {
name,
position,
}
}).then(() => {
return this;
});
}
/**
* Returns an array of Channel Invites
* @returns {Promise<Array<Invite>>}
*/
getInvites() {
return this.client.rest.request("GET", ENDPOINTS.CHANNEL_INVITES(this.id))
.then(res => {
return res.data;
});
}
};
module.exports = GuildChannel;