Merge branch 'master' into indev-prism

This commit is contained in:
Schuyler Cebulskie
2017-02-06 01:54:31 -05:00
17 changed files with 167 additions and 120 deletions

View File

@@ -7,6 +7,7 @@ const Constants = require('../util/Constants');
const Collection = require('../util/Collection');
const cloneObject = require('../util/CloneObject');
const arraysEqual = require('../util/ArraysEqual');
const moveElementInArray = require('../util/MoveElementInArray');
/**
* Represents a guild (or a server) on Discord.
@@ -300,7 +301,7 @@ class Guild {
/**
* Fetch a collection of banned users in this guild.
* @returns {Promise<Collection<string, User>>}
* @returns {Promise<Collection<Snowflake, User>>}
*/
fetchBans() {
return this.client.rest.methods.getGuildBans(this);
@@ -316,7 +317,7 @@ class Guild {
/**
* Fetch all webhooks for the guild.
* @returns {Collection<Webhook>}
* @returns {Collection<Snowflake, Webhook>}
*/
fetchWebhooks() {
return this.client.rest.methods.getGuildWebhooks(this);
@@ -643,9 +644,10 @@ class Guild {
* Set the position of a role in this guild
* @param {string|Role} role the role to edit, can be a role object or a role ID.
* @param {number} position the new position of the role
* @param {boolean} [relative=false] Position moves the role relative to its current position
* @returns {Promise<Guild>}
*/
setRolePosition(role, position) {
setRolePosition(role, position, relative = false) {
if (typeof role === 'string') {
role = this.roles.get(role);
if (!role) return Promise.reject(new Error('Supplied role is not a role or string.'));
@@ -654,27 +656,12 @@ class Guild {
position = Number(position);
if (isNaN(position)) return Promise.reject(new Error('Supplied position is not a number.'));
const lowestAffected = Math.min(role.position, position);
const highestAffected = Math.max(role.position, position);
let updatedRoles = Object.assign([], this.roles.array()
.sort((r1, r2) => r1.position !== r2.position ? r1.position - r2.position : r1.id - r2.id));
const rolesToUpdate = this.roles.filter(r => r.position >= lowestAffected && r.position <= highestAffected);
// stop role positions getting stupidly inflated
if (position > role.position) {
position = rolesToUpdate.first().position;
} else {
position = rolesToUpdate.last().position;
}
const updatedRoles = [];
for (const uRole of rolesToUpdate.values()) {
updatedRoles.push({
id: uRole.id,
position: uRole.id === role.id ? position : uRole.position + (position < role.position ? 1 : -1),
});
}
moveElementInArray(updatedRoles, role, position, relative);
updatedRoles = updatedRoles.map((r, i) => ({ id: r.id, position: i }));
return this.client.rest.methods.setRolePositions(this.id, updatedRoles);
}

View File

@@ -64,10 +64,12 @@ class GuildChannel extends Channel {
for (const role of roles.values()) permissions |= role.permissions;
const overwrites = this.overwritesFor(member, true, roles);
let allow = 0;
for (const overwrite of overwrites.role.concat(overwrites.member)) {
permissions &= ~overwrite.deny;
permissions |= overwrite.allow;
allow |= overwrite.allow;
}
permissions |= allow;
const admin = Boolean(permissions & Constants.PermissionFlags.ADMINISTRATOR);
if (admin) permissions = Constants.ALL_PERMISSIONS;
@@ -250,10 +252,12 @@ class GuildChannel extends Channel {
* Clone this channel
* @param {string} [name=this.name] Optional name for the new channel, otherwise it has the name of this channel
* @param {boolean} [withPermissions=true] Whether to clone the channel with this channel's permission overwrites
* @param {boolean} [withTopic=true] Whether to clone the channel with this channel's topic
* @returns {Promise<GuildChannel>}
*/
clone(name = this.name, withPermissions = true) {
return this.guild.createChannel(name, this.type, withPermissions ? this.permissionOverwrites : []);
clone(name = this.name, withPermissions = true, withTopic = true) {
return this.guild.createChannel(name, this.type, withPermissions ? this.permissionOverwrites : [])
.then(channel => withTopic ? channel.setTopic(this.topic) : channel);
}
/**

View File

@@ -322,7 +322,7 @@ class GuildMember {
/**
* Sets the roles applied to the member.
* @param {Collection<string, Role>|Role[]|string[]} roles The roles or role IDs to apply
* @param {Collection<Snowflake, Role>|Role[]|string[]} roles The roles or role IDs to apply
* @returns {Promise<GuildMember>}
*/
setRoles(roles) {
@@ -341,7 +341,7 @@ class GuildMember {
/**
* Adds multiple roles to the member.
* @param {Collection<string, Role>|Role[]|string[]} roles The roles or role IDs to add
* @param {Collection<Snowflake, Role>|Role[]|string[]} roles The roles or role IDs to add
* @returns {Promise<GuildMember>}
*/
addRoles(roles) {
@@ -367,7 +367,7 @@ class GuildMember {
/**
* Removes multiple roles from the member.
* @param {Collection<string, Role>|Role[]|string[]} roles The roles or role IDs to remove
* @param {Collection<Snowflake, Role>|Role[]|string[]} roles The roles or role IDs to remove
* @returns {Promise<GuildMember>}
*/
removeRoles(roles) {

View File

@@ -137,7 +137,7 @@ class MessageCollector extends EventEmitter {
this.channel.client.removeListener('message', this.listener);
/**
* Emitted when the Collector stops collecting.
* @param {Collection<string, Message>} collection A collection of messages collected
* @param {Collection<Snowflake, Message>} collection A collection of messages collected
* during the lifetime of the collector, mapped by the ID of the messages.
* @param {string} reason The reason for the end of the collector. If it ended because it reached the specified time
* limit, this would be `time`. If you invoke `.stop()` without specifying a reason, this would be `user`. If it

View File

@@ -48,7 +48,7 @@ class Role {
this.hoist = data.hoist;
/**
* The position of the role in the role manager
* The position of the role from the API
* @type {number}
*/
this.position = data.position;
@@ -122,6 +122,16 @@ class Role {
return clientMember.highestRole.comparePositionTo(this) > 0;
}
/**
* The position of the role in the role manager
* @type {number}
*/
get calculatedPosition() {
const sorted = this.guild.roles.array()
.sort((r1, r2) => r1.position !== r2.position ? r1.position - r2.position : r1.id - r2.id);
return sorted.indexOf(sorted.find(r => r.id === this.id));
}
/**
* Get an object mapping permission names to whether or not the role enables that permission
* @returns {Object<string, boolean>}
@@ -246,6 +256,7 @@ class Role {
/**
* Set the position of the role
* @param {number} position The position of the role
* @param {boolean} [relative=false] Move the position relative to its current value
* @returns {Promise<Role>}
* @example
* // set the position of the role
@@ -253,8 +264,8 @@ class Role {
* .then(r => console.log(`Role position: ${r.position}`))
* .catch(console.error);
*/
setPosition(position) {
return this.guild.setRolePosition(this, position).then(() => this);
setPosition(position, relative) {
return this.guild.setRolePosition(this, position, relative).then(() => this);
}
/**

View File

@@ -22,13 +22,13 @@ class UserProfile {
/**
* Guilds that the client user and the user share
* @type {Collection<Guild>}
* @type {Collection<Snowflake, Guild>}
*/
this.mutualGuilds = new Collection();
/**
* The user's connections
* @type {Collection<UserConnection>}
* @type {Collection<String, UserConnection>}
*/
this.connections = new Collection();

View File

@@ -188,7 +188,7 @@ class TextBasedChannel {
/**
* Gets the past messages sent in this channel. Resolves with a collection mapping message ID's to Message objects.
* @param {ChannelLogsQueryOptions} [options={}] Query parameters to pass in
* @returns {Promise<Collection<string, Message>>}
* @returns {Promise<Collection<Snowflake, Message>>}
* @example
* // get messages
* channel.fetchMessages({limit: 10})
@@ -209,7 +209,7 @@ class TextBasedChannel {
/**
* Fetches the pinned messages of this channel and returns a collection of them.
* @returns {Promise<Collection<string, Message>>}
* @returns {Promise<Collection<Snowflake, Message>>}
*/
fetchPinnedMessages() {
return this.client.rest.methods.getChannelPinnedMessages(this).then(data => {
@@ -336,7 +336,7 @@ class TextBasedChannel {
* filter.
* @param {CollectorFilterFunction} filter The filter function to use
* @param {AwaitMessagesOptions} [options={}] Optional options to pass to the internal collector
* @returns {Promise<Collection<string, Message>>}
* @returns {Promise<Collection<Snowflake, Message>>}
* @example
* // await !vote messages
* const filter = m => m.content.startsWith('!vote');
@@ -361,9 +361,9 @@ class TextBasedChannel {
/**
* Bulk delete given messages that are newer than two weeks
* <warn>This is only available when using a bot account.</warn>
* @param {Collection<string, Message>|Message[]|number} messages Messages to delete, or number of messages to delete
* @param {Collection<Snowflake, Message>|Message[]|number} messages Messages or number of messages to delete
* @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically
* @returns {Promise<Collection<string, Message>>} Deleted messages
* @returns {Promise<Collection<Snowflake, Message>>} Deleted messages
*/
bulkDelete(messages, filterOld = false) {
if (!isNaN(messages)) return this.fetchMessages({ limit: messages }).then(msgs => this.bulkDelete(msgs));