Merge branch 'master' into voice-rewrite

This commit is contained in:
Amish Shah
2018-01-13 12:47:56 +00:00
41 changed files with 372 additions and 365 deletions

View File

@@ -97,7 +97,7 @@ class ClientApplication extends Base {
* The owner of this OAuth application
* @type {?User}
*/
this.owner = this.client.users.create(data.owner);
this.owner = this.client.users.add(data.owner);
}
}

View File

@@ -2,7 +2,6 @@ const Structures = require('../util/Structures');
const Collection = require('../util/Collection');
const ClientUserSettings = require('./ClientUserSettings');
const ClientUserGuildSettings = require('./ClientUserGuildSettings');
const { Events } = require('../util/Constants');
const Util = require('../util/Util');
const DataResolver = require('../util/DataResolver');
const Guild = require('./Guild');
@@ -260,45 +259,7 @@ class ClientUser extends Structures.get('User') {
Util.mergeDefault({ limit: 25, roles: true, everyone: true, guild: null }, options);
return this.client.api.users('@me').mentions.get({ query: options })
.then(data => data.map(m => this.client.channels.get(m.channel_id).messages.create(m, false)));
}
/**
* Creates a guild.
* <warn>This is only available when using a user account.</warn>
* @param {string} name The name of the guild
* @param {Object} [options] Options for the creating
* @param {string} [options.region] The region for the server, defaults to the closest one available
* @param {BufferResolvable|Base64Resolvable} [options.icon=null] The icon for the guild
* @returns {Promise<Guild>} The guild that was created
*/
createGuild(name, { region, icon = null } = {}) {
if (!icon || (typeof icon === 'string' && icon.startsWith('data:'))) {
return new Promise((resolve, reject) =>
this.client.api.guilds.post({ data: { name, region, icon } })
.then(data => {
if (this.client.guilds.has(data.id)) return resolve(this.client.guilds.get(data.id));
const handleGuild = guild => {
if (guild.id === data.id) {
this.client.removeListener(Events.GUILD_CREATE, handleGuild);
this.client.clearTimeout(timeout);
resolve(guild);
}
};
this.client.on(Events.GUILD_CREATE, handleGuild);
const timeout = this.client.setTimeout(() => {
this.client.removeListener(Events.GUILD_CREATE, handleGuild);
resolve(this.client.guilds.create(data));
}, 10000);
return undefined;
}, reject)
);
}
return DataResolver.resolveImage(icon)
.then(data => this.createGuild(name, { region, icon: data || null }));
.then(data => data.map(m => this.client.channels.get(m.channel_id).messages.add(m, false)));
}
/**
@@ -326,7 +287,7 @@ class ClientUser extends Structures.get('User') {
}, {}),
} : { recipients: recipients.map(u => this.client.users.resolveID(u.user || u.id)) };
return this.client.api.users('@me').channels.post({ data })
.then(res => this.client.channels.create(res));
.then(res => this.client.channels.add(res));
}
}

View File

@@ -21,7 +21,7 @@ class DMChannel extends Channel {
* The recipient on the other end of the DM
* @type {User}
*/
this.recipient = this.client.users.create(data.recipients[0]);
this.recipient = this.client.users.add(data.recipients[0]);
this.lastMessageID = data.last_message_id;
}

View File

@@ -89,7 +89,7 @@ class GroupDMChannel extends Channel {
if (data.recipients) {
for (const recipient of data.recipients) {
const user = this.client.users.create(recipient);
const user = this.client.users.add(recipient);
this.recipients.set(user.id, user);
}
}

View File

@@ -1,14 +1,12 @@
const Invite = require('./Invite');
const GuildAuditLogs = require('./GuildAuditLogs');
const Webhook = require('./Webhook');
const GuildMember = require('./GuildMember');
const VoiceRegion = require('./VoiceRegion');
const { ChannelTypes, Events, browser } = require('../util/Constants');
const Collection = require('../util/Collection');
const Util = require('../util/Util');
const DataResolver = require('../util/DataResolver');
const Snowflake = require('../util/Snowflake');
const Permissions = require('../util/Permissions');
const Shared = require('./shared');
const GuildMemberStore = require('../stores/GuildMemberStore');
const RoleStore = require('../stores/RoleStore');
@@ -183,7 +181,7 @@ class Guild extends Base {
if (data.members) {
this.members.clear();
for (const guildUser of data.members) this.members.create(guildUser);
for (const guildUser of data.members) this.members.add(guildUser);
}
if (data.owner_id) {
@@ -197,18 +195,18 @@ class Guild extends Base {
if (data.channels) {
this.channels.clear();
for (const rawChannel of data.channels) {
this.client.channels.create(rawChannel, this);
this.client.channels.add(rawChannel, this);
}
}
if (data.roles) {
this.roles.clear();
for (const role of data.roles) this.roles.create(role);
for (const role of data.roles) this.roles.add(role);
}
if (data.presences) {
for (const presence of data.presences) {
this.presences.create(presence);
this.presences.add(presence);
}
}
@@ -223,7 +221,7 @@ class Guild extends Base {
* @type {EmojiStore<Snowflake, Emoji>}
*/
this.emojis = new EmojiStore(this);
if (data.emojis) for (const emoji of data.emojis) this.emojis.create(emoji);
if (data.emojis) for (const emoji of data.emojis) this.emojis.add(emoji);
} else {
this.client.actions.GuildEmojisUpdate.handle({
guild_id: this.id,
@@ -457,7 +455,7 @@ class Guild extends Base {
bans.reduce((collection, ban) => {
collection.set(ban.user.id, {
reason: ban.reason,
user: this.client.users.create(ban.user),
user: this.client.users.add(ban.user),
});
return collection;
}, new Collection())
@@ -565,7 +563,7 @@ class Guild extends Base {
}
}
return this.client.api.guilds(this.id).members(user).put({ data: options })
.then(data => this.members.create(data));
.then(data => this.members.add(data));
}
/**
@@ -823,79 +821,6 @@ class Guild extends Base {
else return settings.addRestrictedGuild(this);
}
/**
* Bans a user from the guild.
* @param {UserResolvable} user The user to ban
* @param {Object} [options] Options for the ban
* @param {number} [options.days=0] Number of days of messages to delete
* @param {string} [options.reason] Reason for banning
* @returns {Promise<GuildMember|User|Snowflake>} Result object will be resolved as specifically as possible.
* If the GuildMember cannot be resolved, the User will instead be attempted to be resolved. If that also cannot
* be resolved, the user ID will be the result.
* @example
* // Ban a user by ID (or with a user/guild member object)
* guild.ban('some user ID')
* .then(user => console.log(`Banned ${user.username || user.id || user} from ${guild.name}`))
* .catch(console.error);
*/
ban(user, options = { days: 0 }) {
if (options.days) options['delete-message-days'] = options.days;
const id = this.client.users.resolveID(user);
if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID', true));
return this.client.api.guilds(this.id).bans[id].put({ query: options })
.then(() => {
if (user instanceof GuildMember) return user;
const _user = this.client.users.resolve(id);
if (_user) {
const member = this.members.resolve(_user);
return member || _user;
}
return id;
});
}
/**
* Unbans a user from the guild.
* @param {UserResolvable} user The user to unban
* @param {string} [reason] Reason for unbanning user
* @returns {Promise<User>}
* @example
* // Unban a user by ID (or with a user/guild member object)
* guild.unban('some user ID')
* .then(user => console.log(`Unbanned ${user.username} from ${guild.name}`))
* .catch(console.error);
*/
unban(user, reason) {
const id = this.client.users.resolveID(user);
if (!id) throw new Error('BAN_RESOLVE_ID');
return this.client.api.guilds(this.id).bans[id].delete({ reason })
.then(() => user);
}
/**
* Prunes members from the guild based on how long they have been inactive.
* @param {Object} [options] Prune options
* @param {number} [options.days=7] Number of days of inactivity required to kick
* @param {boolean} [options.dry=false] Get number of users that will be kicked, without actually kicking them
* @param {string} [options.reason] Reason for this prune
* @returns {Promise<number>} The number of members that were/will be kicked
* @example
* // See how many members will be pruned
* guild.pruneMembers({ dry: true })
* .then(pruned => console.log(`This will prune ${pruned} people!`))
* .catch(console.error);
* @example
* // Actually prune the members
* guild.pruneMembers({ days: 1, reason: 'too many people!' })
* .then(pruned => console.log(`I just pruned ${pruned} people!`))
* .catch(console.error);
*/
pruneMembers({ days = 7, dry = false, reason } = {}) {
if (typeof days !== 'number') throw new TypeError('PRUNE_DAYS_TYPE');
return this.client.api.guilds(this.id).prune[dry ? 'get' : 'post']({ query: { days }, reason })
.then(data => data.pruned);
}
/**
* Syncs this guild (already done automatically every 30 seconds).
* <warn>This is only available when using a user account.</warn>
@@ -904,73 +829,6 @@ class Guild extends Base {
if (!this.client.user.bot) this.client.syncGuilds([this]);
}
/**
* Can be used to overwrite permissions when creating a channel.
* @typedef {Object} ChannelCreationOverwrites
* @property {PermissionResolvable[]|number} [allow] The permissions to allow
* @property {PermissionResolvable[]|number} [deny] The permissions to deny
* @property {RoleResolvable|UserResolvable} id ID of the role or member this overwrite is for
*/
/**
* Creates a new channel in the guild.
* @param {string} name The name of the new channel
* @param {Object} [options] Options
* @param {string} [options.type='text'] The type of the new channel, either `text`, `voice`, or `category`
* @param {boolean} [options.nsfw] Whether the new channel is nsfw
* @param {number} [options.bitrate] Bitrate of the new channel in bits (only voice)
* @param {number} [options.userLimit] Maximum amount of users allowed in the new channel (only voice)
* @param {ChannelResolvable} [options.parent] Parent of the new channel
* @param {Array<PermissionOverwrites|ChannelCreationOverwrites>} [options.overwrites] Permission overwrites
* @param {string} [options.reason] Reason for creating the channel
* @returns {Promise<GuildChannel>}
* @example
* // Create a new text channel
* guild.createChannel('new-general', { reason: 'Cool new channel' })
* .then(console.log)
* .catch(console.error);
*/
createChannel(name, { type, nsfw, bitrate, userLimit, parent, overwrites, reason } = {}) {
if (overwrites instanceof Collection || overwrites instanceof Array) {
overwrites = overwrites.map(overwrite => {
let allow = overwrite.allow || (overwrite.allowed ? overwrite.allowed.bitfield : 0);
let deny = overwrite.deny || (overwrite.denied ? overwrite.denied.bitfield : 0);
if (allow instanceof Array) allow = Permissions.resolve(allow);
if (deny instanceof Array) deny = Permissions.resolve(deny);
const role = this.roles.resolve(overwrite.id);
if (role) {
overwrite.id = role.id;
overwrite.type = 'role';
} else {
overwrite.id = this.client.users.resolveID(overwrite.id);
overwrite.type = 'member';
}
return {
allow,
deny,
type: overwrite.type,
id: overwrite.id,
};
});
}
if (parent) parent = this.client.channels.resolveID(parent);
return this.client.api.guilds(this.id).channels.post({
data: {
name,
type: type ? ChannelTypes[type.toUpperCase()] : 'text',
nsfw,
bitrate,
user_limit: userLimit,
parent_id: parent,
permission_overwrites: overwrites,
},
reason,
}).then(data => this.client.actions.ChannelCreate.handle(data).channel);
}
/**
* The data needed for updating a channel's position.
* @typedef {Object} ChannelPosition
@@ -1001,85 +859,6 @@ class Guild extends Base {
);
}
/**
* Creates a new role in the guild with given information.
* <warn>The position will silently reset to 1 if an invalid one is provided, or none.</warn>
* @param {Object} [options] Options
* @param {RoleData} [options.data] The data to update the role with
* @param {string} [options.reason] Reason for creating this role
* @returns {Promise<Role>}
* @example
* // Create a new role
* guild.createRole()
* .then(role => console.log(`Created role ${role}`))
* .catch(console.error);
* @example
* // Create a new role with data and a reason
* guild.createRole({
* data: {
* name: 'Super Cool People',
* color: 'BLUE',
* },
* reason: 'we needed a role for Super Cool People',
* })
* .then(role => console.log(`Created role ${role}`))
* .catch(console.error);
*/
createRole({ data = {}, reason } = {}) {
if (data.color) data.color = Util.resolveColor(data.color);
if (data.permissions) data.permissions = Permissions.resolve(data.permissions);
return this.client.api.guilds(this.id).roles.post({ data, reason }).then(r => {
const { role } = this.client.actions.GuildRoleCreate.handle({
guild_id: this.id,
role: r,
});
if (data.position) return role.setPosition(data.position, reason);
return role;
});
}
/**
* Creates a new custom emoji in the guild.
* @param {BufferResolvable|Base64Resolvable} attachment The image for the emoji
* @param {string} name The name for the emoji
* @param {Object} [options] Options
* @param {Collection<Snowflake, Role>|RoleResolvable[]} [options.roles] Roles to limit the emoji to
* @param {string} [options.reason] Reason for creating the emoji
* @returns {Promise<Emoji>} The created emoji
* @example
* // Create a new emoji from a url
* guild.createEmoji('https://i.imgur.com/w3duR07.png', 'rip')
* .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))
* .catch(console.error);
* @example
* // Create a new emoji from a file on your computer
* guild.createEmoji('./memes/banana.png', 'banana')
* .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`))
* .catch(console.error);
*/
createEmoji(attachment, name, { roles, reason } = {}) {
if (typeof attachment === 'string' && attachment.startsWith('data:')) {
const data = { image: attachment, name };
if (roles) {
data.roles = [];
for (let role of roles instanceof Collection ? roles.values() : roles) {
role = this.roles.resolve(role);
if (!role) {
return Promise.reject(new TypeError('INVALID_TYPE', 'options.roles',
'Array or Collection of Roles or Snowflakes', true));
}
data.roles.push(role.id);
}
}
return this.client.api.guilds(this.id).emojis.post({ data, reason })
.then(emoji => this.client.actions.GuildEmojiCreate.handle(this, emoji).emoji);
}
return DataResolver.resolveImage(attachment).then(image => this.createEmoji(image, name, { roles, reason }));
}
/**
* Leaves the guild.
* @returns {Promise<Guild>}

View File

@@ -106,7 +106,7 @@ const Actions = {
*/
class GuildAuditLogs {
constructor(guild, data) {
if (data.users) for (const user of data.users) guild.client.users.create(user);
if (data.users) for (const user of data.users) guild.client.users.add(user);
/**
* Cached webhooks
* @type {Collection<Snowflake, Webhook>}

View File

@@ -411,8 +411,8 @@ class GuildChannel extends Channel {
* @returns {Promise<GuildChannel>}
*/
clone({ name = this.name, withPermissions = true, withTopic = true, reason } = {}) {
const options = { overwrites: withPermissions ? this.permissionOverwrites : [], reason };
return this.guild.createChannel(name, this.type, options)
const options = { overwrites: withPermissions ? this.permissionOverwrites : [], reason, type: this.type };
return this.guild.channels.create(name, options)
.then(channel => withTopic ? channel.setTopic(this.topic) : channel);
}

View File

@@ -66,7 +66,7 @@ class GuildMember extends Base {
*/
if (data.joined_at) this.joinedTimestamp = new Date(data.joined_at).getTime();
this.user = this.guild.client.users.create(data.user);
this.user = this.guild.client.users.add(data.user);
if (data.roles) this._roles = data.roles;
}
@@ -543,7 +543,7 @@ class GuildMember extends Base {
* .catch(console.error);
*/
ban(options) {
return this.guild.ban(this, options);
return this.guild.members.ban(this, options);
}
/**

View File

@@ -17,7 +17,7 @@ class Invite extends Base {
* The guild the invite is for
* @type {Guild}
*/
this.guild = this.client.guilds.create(data.guild, false);
this.guild = this.client.guilds.add(data.guild, false);
/**
* The code for this invite
@@ -78,14 +78,14 @@ class Invite extends Base {
* The user who created this invite
* @type {User}
*/
this.inviter = this.client.users.create(data.inviter);
this.inviter = this.client.users.add(data.inviter);
}
/**
* The channel the invite is for
* @type {GuildChannel}
*/
this.channel = this.client.channels.create(data.channel, this.guild, false);
this.channel = this.client.channels.add(data.channel, this.guild, false);
/**
* The timestamp the invite was created at

View File

@@ -52,7 +52,7 @@ class Message extends Base {
* The author of the message
* @type {User}
*/
this.author = this.client.users.create(data.author, !data.webhook_id);
this.author = this.client.users.add(data.author, !data.webhook_id);
/**
* Represents the author of the message as a guild member.
@@ -121,7 +121,7 @@ class Message extends Base {
this.reactions = new ReactionStore(this);
if (data.reactions && data.reactions.length > 0) {
for (const reaction of data.reactions) {
this.reactions.create(reaction);
this.reactions.add(reaction);
}
}
@@ -429,15 +429,6 @@ class Message extends Base {
}).reaction);
}
/**
* Removes all reactions from a message.
* @returns {Promise<Message>}
*/
clearReactions() {
return this.client.api.channels(this.channel.id).messages(this.id).reactions.delete()
.then(() => this);
}
/**
* Deletes the message.
* @param {Object} [options] Options

View File

@@ -22,7 +22,7 @@ class MessageMentions {
} else {
this.users = new Collection();
for (const mention of users) {
let user = message.client.users.create(mention);
let user = message.client.users.add(mention);
this.users.set(user.id, user);
}
}

View File

@@ -1,7 +1,6 @@
const Emoji = require('./Emoji');
const ReactionEmoji = require('./ReactionEmoji');
const ReactionUserStore = require('../stores/ReactionUserStore');
const { Error } = require('../errors');
/**
* Represents a reaction to a message.
@@ -56,27 +55,6 @@ class MessageReaction {
return this._emoji;
}
/**
* Removes a user from this reaction.
* @param {UserResolvable} [user=this.message.client.user] The user to remove the reaction of
* @returns {Promise<MessageReaction>}
*/
remove(user = this.message.client.user) {
const userID = this.message.client.users.resolveID(user);
if (!userID) return Promise.reject(new Error('REACTION_RESOLVE_USER'));
return this.message.client.api.channels[this.message.channel.id].messages[this.message.id]
.reactions[this.emoji.identifier][userID === this.message.client.user.id ? '@me' : userID]
.delete()
.then(() =>
this.message.client.actions.MessageReactionRemove.handle({
user_id: userID,
message_id: this.message.id,
emoji: this.emoji,
channel_id: this.message.channel.id,
}).reaction
);
}
_add(user) {
if (!this.users.has(user.id)) {
this.users.set(user.id, user);

View File

@@ -35,7 +35,7 @@ class TextChannel extends GuildChannel {
this.lastMessageID = data.last_message_id;
if (data.messages) for (const message of data.messages) this.messages.create(message);
if (data.messages) for (const message of data.messages) this.messages.add(message);
}
/**

View File

@@ -124,7 +124,7 @@ class Webhook {
auth: false,
}).then(d => {
if (!this.client.channels) return d;
return this.client.channels.get(d.channel_id).messages.create(d, false);
return this.client.channels.get(d.channel_id).messages.add(d, false);
});
}
@@ -152,7 +152,7 @@ class Webhook {
data: body,
}).then(data => {
if (!this.client.channels) return data;
return this.client.channels.get(data.channel_id).messages.create(data, false);
return this.client.channels.get(data.channel_id).messages.add(data, false);
});
}

View File

@@ -90,7 +90,7 @@ module.exports = function search(target, options) {
let endpoint = target.client.api[target instanceof Channel ? 'channels' : 'guilds'](target.id).messages().search;
return endpoint.get({ query: options }).then(body => {
const results = body.messages.map(x =>
x.map(m => target.client.channels.get(m.channel_id).messages.create(m, false))
x.map(m => target.client.channels.get(m.channel_id).messages.add(m, false))
);
return {
total: body.total_results,