mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
add channel categories (#1727)
* add channel categories * add specific class * speed * Update Channel.js * fix type typo * Update Channel.js * rewrite position stuff in prep for category sorting * fix small issues in generation of permissions * Update Guild.js * Update Constants.js * Update GuildChannel.js * doc fix * Update GuildChannel.js * <.<
This commit is contained in:
9
src/structures/CategoryChannel.js
Normal file
9
src/structures/CategoryChannel.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const GuildChannel = require('./GuildChannel');
|
||||
|
||||
class CategoryChannel extends GuildChannel {
|
||||
get children() {
|
||||
return this.guild.channels.filter(c => c.parentID === this.id);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CategoryChannel;
|
||||
@@ -17,6 +17,7 @@ class Channel extends Base {
|
||||
* * `group` - a Group DM channel
|
||||
* * `text` - a guild text channel
|
||||
* * `voice` - a guild voice channel
|
||||
* * `category` - a guild category channel
|
||||
* * `unknown` - a generic channel of unknown type, could be Channel or GuildChannel
|
||||
* @type {string}
|
||||
*/
|
||||
@@ -69,6 +70,7 @@ class Channel extends Base {
|
||||
const GroupDMChannel = require('./GroupDMChannel');
|
||||
const TextChannel = require('./TextChannel');
|
||||
const VoiceChannel = require('./VoiceChannel');
|
||||
const CategoryChannel = require('./CategoryChannel');
|
||||
const GuildChannel = require('./GuildChannel');
|
||||
const types = Constants.ChannelTypes;
|
||||
let channel;
|
||||
@@ -86,6 +88,9 @@ class Channel extends Base {
|
||||
case types.VOICE:
|
||||
channel = new VoiceChannel(guild, data);
|
||||
break;
|
||||
case types.CATEGORY:
|
||||
channel = new CategoryChannel(guild, data);
|
||||
break;
|
||||
default:
|
||||
channel = new GuildChannel(guild, data);
|
||||
}
|
||||
|
||||
@@ -891,10 +891,9 @@ class Guild extends Base {
|
||||
/**
|
||||
* Creates a new channel in the guild.
|
||||
* @param {string} name The name of the new channel
|
||||
* @param {string} type The type of the new channel, either `text` or `voice`
|
||||
* @param {Object} [options={}] Options
|
||||
* @param {string} type The type of the new channel, either `text`, `voice`, or `category`
|
||||
* @param {Object} [options] Options
|
||||
* @param {Array<PermissionOverwrites|ChannelCreationOverwrites>} [options.overwrites] Permission overwrites
|
||||
* to apply to the new channel
|
||||
* @param {string} [options.reason] Reason for creating this channel
|
||||
* @returns {Promise<TextChannel|VoiceChannel>}
|
||||
* @example
|
||||
@@ -1205,31 +1204,17 @@ class Guild extends Base {
|
||||
|
||||
/**
|
||||
* Fetches a collection of channels in the current guild sorted by position.
|
||||
* @param {string} type The channel type
|
||||
* @param {Channel} channel Channel
|
||||
* @returns {Collection<Snowflake, GuildChannel>}
|
||||
* @private
|
||||
*/
|
||||
_sortedChannels(type) {
|
||||
return this._sortPositionWithID(this.channels.filter(c => {
|
||||
if (type === 'voice' && c.type === 'voice') return true;
|
||||
else if (type !== 'voice' && c.type !== 'voice') return true;
|
||||
else return type === c.type;
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts a collection by object position or ID if the positions are equivalent.
|
||||
* Intended to be identical to Discord's sorting method.
|
||||
* @param {Collection} collection The collection to sort
|
||||
* @returns {Collection}
|
||||
* @private
|
||||
*/
|
||||
_sortPositionWithID(collection) {
|
||||
return collection.sort((a, b) =>
|
||||
a.position !== b.position ?
|
||||
a.position - b.position :
|
||||
Long.fromString(a.id).sub(Long.fromString(b.id)).toNumber()
|
||||
);
|
||||
_sortedChannels(channel) {
|
||||
const sort = col => col
|
||||
.sort((a, b) => a.rawPosition - b.rawPosition || Long.fromString(a.id).sub(Long.fromString(b.id)).toNumber());
|
||||
if (channel.type === Constants.ChannelTypes.CATEGORY) {
|
||||
return sort(this.channels.filter(c => c.type === Constants.ChannelTypes.CATEGORY));
|
||||
}
|
||||
return sort(this.channels.filter(c => c.parent === channel.parent));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ const Channel = require('./Channel');
|
||||
const Role = require('./Role');
|
||||
const Invite = require('./Invite');
|
||||
const PermissionOverwrites = require('./PermissionOverwrites');
|
||||
const Util = require('../util/Util');
|
||||
const Permissions = require('../util/Permissions');
|
||||
const Collection = require('../util/Collection');
|
||||
const Constants = require('../util/Constants');
|
||||
@@ -32,10 +33,16 @@ class GuildChannel extends Channel {
|
||||
this.name = data.name;
|
||||
|
||||
/**
|
||||
* The position of the channel in the list
|
||||
* The raw position of the channel from discord
|
||||
* @type {number}
|
||||
*/
|
||||
this.position = data.position;
|
||||
this.rawPosition = data.position;
|
||||
|
||||
/**
|
||||
* The ID of the category parent of this channel
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.parentID = data.parent_id;
|
||||
|
||||
/**
|
||||
* A map of permission overwrites in this channel for roles and users
|
||||
@@ -49,13 +56,21 @@ class GuildChannel extends Channel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The category parent of this channel
|
||||
* @type {?GuildChannel}
|
||||
*/
|
||||
get parent() {
|
||||
return this.guild.channels.get(this.parentID);
|
||||
}
|
||||
|
||||
/**
|
||||
* The position of the channel
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
get calculatedPosition() {
|
||||
const sorted = this.guild._sortedChannels(this.type);
|
||||
get position() {
|
||||
const sorted = this.guild._sortedChannels(this);
|
||||
return sorted.array().indexOf(sorted.get(this.id));
|
||||
}
|
||||
|
||||
@@ -70,34 +85,32 @@ class GuildChannel extends Channel {
|
||||
if (!member) return null;
|
||||
if (member.id === this.guild.ownerID) return new Permissions(Permissions.ALL);
|
||||
|
||||
let permissions = 0;
|
||||
|
||||
const roles = member.roles;
|
||||
for (const role of roles.values()) permissions |= role.permissions;
|
||||
|
||||
const overwrites = this.overwritesFor(member, true, roles);
|
||||
let resolved = this.guild.roles.get(this.guild.id).permissions;
|
||||
|
||||
const overwrites = this.overwritesFor(member, true);
|
||||
if (overwrites.everyone) {
|
||||
permissions &= ~overwrites.everyone._denied;
|
||||
permissions |= overwrites.everyone._allowed;
|
||||
resolved &= ~overwrites.everyone._denied;
|
||||
resolved |= overwrites.everyone._allowed;
|
||||
}
|
||||
|
||||
let allow = 0;
|
||||
let allows = 0;
|
||||
let denies = 0;
|
||||
for (const overwrite of overwrites.roles) {
|
||||
permissions &= ~overwrite._denied;
|
||||
allow |= overwrite._allowed;
|
||||
allows |= overwrite._allowed;
|
||||
denies |= overwrite._denied;
|
||||
}
|
||||
permissions |= allow;
|
||||
resolved &= ~denies;
|
||||
resolved |= allows;
|
||||
|
||||
if (overwrites.member) {
|
||||
permissions &= ~overwrites.member._denied;
|
||||
permissions |= overwrites.member._allowed;
|
||||
resolved &= ~overwrites.member._denied;
|
||||
resolved |= overwrites.member._allowed;
|
||||
}
|
||||
|
||||
const admin = Boolean(permissions & Permissions.FLAGS.ADMINISTRATOR);
|
||||
if (admin) permissions = Permissions.ALL;
|
||||
const admin = Boolean(resolved & Permissions.FLAGS.ADMINISTRATOR);
|
||||
if (admin) resolved = Permissions.ALL;
|
||||
|
||||
return new Permissions(permissions);
|
||||
return new Permissions(resolved);
|
||||
}
|
||||
|
||||
overwritesFor(member, verified = false, roles = null) {
|
||||
@@ -236,10 +249,12 @@ class GuildChannel extends Channel {
|
||||
return this.client.api.channels(this.id).patch({
|
||||
data: {
|
||||
name: (data.name || this.name).trim(),
|
||||
topic: data.topic || this.topic,
|
||||
topic: data.topic,
|
||||
position: data.position || this.position,
|
||||
bitrate: data.bitrate || (this.bitrate ? this.bitrate * 1000 : undefined),
|
||||
user_limit: data.userLimit || this.userLimit,
|
||||
user_limit: data.userLimit != null ? data.userLimit : this.userLimit, // eslint-disable-line eqeqeq
|
||||
parent_id: data.parentID,
|
||||
lock_permissions: data.lockPermissions,
|
||||
},
|
||||
reason,
|
||||
}).then(newData => {
|
||||
@@ -275,8 +290,34 @@ class GuildChannel extends Channel {
|
||||
* .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
setPosition(position, relative) {
|
||||
return this.guild.setChannelPosition(this, position, relative).then(() => this);
|
||||
setPosition(position, { relative, reason }) {
|
||||
position = Number(position);
|
||||
if (isNaN(position)) return Promise.reject(new TypeError('INVALID_TYPE', 'position', 'number'));
|
||||
let updatedChannels = this.guild._sortedChannels(this).array();
|
||||
Util.moveElementInArray(updatedChannels, this, position, relative);
|
||||
updatedChannels = updatedChannels.map((r, i) => ({ id: r.id, position: i }));
|
||||
return this.client.api.guilds(this.id).channels.patch({ data: updatedChannels, reason })
|
||||
.then(() => {
|
||||
this.client.actions.GuildChannelsPositionUpdate.handle({
|
||||
guild_id: this.id,
|
||||
channels: updatedChannels,
|
||||
});
|
||||
return this;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the category parent of this channel.
|
||||
* @param {GuildChannel|Snowflake} channel Parent channel
|
||||
* @param {boolean} [options.lockPermissions] Lock the permissions to what the parent's permissions are
|
||||
* @param {string} [options.reason] Reason for modifying the parent of this channel
|
||||
* @returns {Promise<GuildChannel>}
|
||||
*/
|
||||
setParent(channel, { lockPermissions = true, reason } = {}) {
|
||||
return this.edit({
|
||||
parentID: channel.id ? channel.id : channel,
|
||||
lockPermissions,
|
||||
}, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -165,13 +165,6 @@ exports.VoiceStatus = {
|
||||
DISCONNECTED: 4,
|
||||
};
|
||||
|
||||
exports.ChannelTypes = {
|
||||
TEXT: 0,
|
||||
DM: 1,
|
||||
VOICE: 2,
|
||||
GROUP: 3,
|
||||
};
|
||||
|
||||
exports.OPCodes = {
|
||||
DISPATCH: 0,
|
||||
HEARTBEAT: 1,
|
||||
@@ -574,6 +567,14 @@ exports.UserFlags = {
|
||||
HYPESQUAD: 1 << 2,
|
||||
};
|
||||
|
||||
exports.ChannelTypes = {
|
||||
TEXT: 0,
|
||||
DM: 1,
|
||||
VOICE: 2,
|
||||
GROUP: 3,
|
||||
CATEGORY: 4,
|
||||
};
|
||||
|
||||
exports.ClientApplicationAssetTypes = {
|
||||
SMALL: 1,
|
||||
BIG: 2,
|
||||
|
||||
Reference in New Issue
Block a user