From 9eac19d9d8bfb81dc0079e3bff073a20b9c9768f Mon Sep 17 00:00:00 2001 From: Isabella Date: Thu, 11 Jan 2018 10:33:30 -0600 Subject: [PATCH] refactor: more oop with stores (#2216) * refactor: more oop with stores * forgot bulk delete * Revert "forgot bulk delete" This reverts commit 1b4fb999ee07b358ee6e1af9efb8981b84f83af1. * appease linter * missed some shh * fail --- src/client/actions/ChannelCreate.js | 2 +- src/client/actions/GuildBanRemove.js | 2 +- src/client/actions/GuildEmojiCreate.js | 2 +- src/client/actions/GuildRoleCreate.js | 2 +- src/client/actions/GuildSync.js | 4 +- src/client/actions/MessageCreate.js | 2 +- src/client/actions/MessageReactionAdd.js | 2 +- .../websocket/packets/handlers/GuildCreate.js | 2 +- .../packets/handlers/GuildMemberAdd.js | 2 +- .../packets/handlers/GuildMembersChunk.js | 2 +- .../packets/handlers/PresenceUpdate.js | 10 +- .../websocket/packets/handlers/Ready.js | 10 +- src/stores/ChannelStore.js | 2 +- src/stores/DataStore.js | 4 +- src/stores/EmojiStore.js | 47 +++- src/stores/GuildChannelStore.js | 74 +++++- src/stores/GuildMemberStore.js | 80 +++++- src/stores/GuildStore.js | 40 +++ src/stores/MessageStore.js | 10 +- src/stores/PresenceStore.js | 4 +- src/stores/ReactionStore.js | 13 +- src/stores/ReactionUserStore.js | 24 +- src/stores/RoleStore.js | 42 +++- src/stores/UserStore.js | 2 +- src/structures/ClientApplication.js | 2 +- src/structures/ClientUser.js | 43 +--- src/structures/DMChannel.js | 2 +- src/structures/GroupDMChannel.js | 2 +- src/structures/Guild.js | 235 +----------------- src/structures/GuildAuditLogs.js | 2 +- src/structures/GuildMember.js | 2 +- src/structures/Invite.js | 6 +- src/structures/Message.js | 13 +- src/structures/MessageMentions.js | 2 +- src/structures/MessageReaction.js | 22 -- src/structures/TextChannel.js | 2 +- src/structures/Webhook.js | 4 +- src/structures/shared/Search.js | 2 +- 38 files changed, 364 insertions(+), 359 deletions(-) diff --git a/src/client/actions/ChannelCreate.js b/src/client/actions/ChannelCreate.js index 1195d7345..09e74f0f3 100644 --- a/src/client/actions/ChannelCreate.js +++ b/src/client/actions/ChannelCreate.js @@ -5,7 +5,7 @@ class ChannelCreateAction extends Action { handle(data) { const client = this.client; const existing = client.channels.has(data.id); - const channel = client.channels.create(data); + const channel = client.channels.add(data); if (!existing && channel) { client.emit(Events.CHANNEL_CREATE, channel); } diff --git a/src/client/actions/GuildBanRemove.js b/src/client/actions/GuildBanRemove.js index fe15f17f7..782b5fe2a 100644 --- a/src/client/actions/GuildBanRemove.js +++ b/src/client/actions/GuildBanRemove.js @@ -5,7 +5,7 @@ class GuildBanRemove extends Action { handle(data) { const client = this.client; const guild = client.guilds.get(data.guild_id); - const user = client.users.create(data.user); + const user = client.users.add(data.user); if (guild && user) client.emit(Events.GUILD_BAN_REMOVE, guild, user); } } diff --git a/src/client/actions/GuildEmojiCreate.js b/src/client/actions/GuildEmojiCreate.js index cac3d8c4d..4b5b913c8 100644 --- a/src/client/actions/GuildEmojiCreate.js +++ b/src/client/actions/GuildEmojiCreate.js @@ -3,7 +3,7 @@ const { Events } = require('../../util/Constants'); class GuildEmojiCreateAction extends Action { handle(guild, createdEmoji) { - const emoji = guild.emojis.create(createdEmoji); + const emoji = guild.emojis.add(createdEmoji); this.client.emit(Events.GUILD_EMOJI_CREATE, emoji); return { emoji }; } diff --git a/src/client/actions/GuildRoleCreate.js b/src/client/actions/GuildRoleCreate.js index 7f5bbb485..b4930399d 100644 --- a/src/client/actions/GuildRoleCreate.js +++ b/src/client/actions/GuildRoleCreate.js @@ -8,7 +8,7 @@ class GuildRoleCreate extends Action { let role; if (guild) { const already = guild.roles.has(data.role.id); - role = guild.roles.create(data.role); + role = guild.roles.add(data.role); if (!already) client.emit(Events.GUILD_ROLE_CREATE, role); } return { role }; diff --git a/src/client/actions/GuildSync.js b/src/client/actions/GuildSync.js index 2019c5d22..f7dbde6ad 100644 --- a/src/client/actions/GuildSync.js +++ b/src/client/actions/GuildSync.js @@ -7,7 +7,7 @@ class GuildSync extends Action { const guild = client.guilds.get(data.id); if (guild) { if (data.presences) { - for (const presence of data.presences) guild.presences.create(presence); + for (const presence of data.presences) guild.presences.add(presence); } if (data.members) { @@ -16,7 +16,7 @@ class GuildSync extends Action { if (member) { member._patch(syncMember); } else { - guild.members.create(syncMember, false); + guild.members.add(syncMember, false); } } } diff --git a/src/client/actions/MessageCreate.js b/src/client/actions/MessageCreate.js index 1755cec71..e76c6071d 100644 --- a/src/client/actions/MessageCreate.js +++ b/src/client/actions/MessageCreate.js @@ -8,7 +8,7 @@ class MessageCreateAction extends Action { if (channel) { const existing = channel.messages.get(data.id); if (existing) return { message: existing }; - const message = channel.messages.create(data); + const message = channel.messages.add(data); const user = message.author; const member = channel.guild ? channel.guild.member(user) : null; channel.lastMessageID = data.id; diff --git a/src/client/actions/MessageReactionAdd.js b/src/client/actions/MessageReactionAdd.js index b26ad5949..073ba05a7 100644 --- a/src/client/actions/MessageReactionAdd.js +++ b/src/client/actions/MessageReactionAdd.js @@ -19,7 +19,7 @@ class MessageReactionAdd extends Action { if (!message) return false; if (!data.emoji) return false; // Verify reaction - const reaction = message.reactions.create({ + const reaction = message.reactions.add({ emoji: data.emoji, count: 0, me: user.id === this.client.user.id, diff --git a/src/client/websocket/packets/handlers/GuildCreate.js b/src/client/websocket/packets/handlers/GuildCreate.js index a920b02cf..96c5ae987 100644 --- a/src/client/websocket/packets/handlers/GuildCreate.js +++ b/src/client/websocket/packets/handlers/GuildCreate.js @@ -15,7 +15,7 @@ class GuildCreateHandler extends AbstractHandler { } } else { // A new guild - guild = client.guilds.create(data); + guild = client.guilds.add(data); const emitEvent = client.ws.connection.status === Status.READY; if (emitEvent) { /** diff --git a/src/client/websocket/packets/handlers/GuildMemberAdd.js b/src/client/websocket/packets/handlers/GuildMemberAdd.js index de244ed63..15201b825 100644 --- a/src/client/websocket/packets/handlers/GuildMemberAdd.js +++ b/src/client/websocket/packets/handlers/GuildMemberAdd.js @@ -10,7 +10,7 @@ class GuildMemberAddHandler extends AbstractHandler { const guild = client.guilds.get(data.guild_id); if (guild) { guild.memberCount++; - const member = guild.members.create(data); + const member = guild.members.add(data); if (client.ws.connection.status === Status.READY) { client.emit(Events.GUILD_MEMBER_ADD, member); } diff --git a/src/client/websocket/packets/handlers/GuildMembersChunk.js b/src/client/websocket/packets/handlers/GuildMembersChunk.js index 5985a9e42..4e821f5cc 100644 --- a/src/client/websocket/packets/handlers/GuildMembersChunk.js +++ b/src/client/websocket/packets/handlers/GuildMembersChunk.js @@ -10,7 +10,7 @@ class GuildMembersChunkHandler extends AbstractHandler { if (!guild) return; const members = new Collection(); - for (const member of data.members) members.set(member.user.id, guild.members.create(member)); + for (const member of data.members) members.set(member.user.id, guild.members.add(member)); client.emit(Events.GUILD_MEMBERS_CHUNK, members, guild); diff --git a/src/client/websocket/packets/handlers/PresenceUpdate.js b/src/client/websocket/packets/handlers/PresenceUpdate.js index 4da269513..87732b8ce 100644 --- a/src/client/websocket/packets/handlers/PresenceUpdate.js +++ b/src/client/websocket/packets/handlers/PresenceUpdate.js @@ -11,7 +11,7 @@ class PresenceUpdateHandler extends AbstractHandler { // Step 1 if (!user) { if (data.user.username) { - user = client.users.create(data.user); + user = client.users.add(data.user); } else { return; } @@ -25,7 +25,7 @@ class PresenceUpdateHandler extends AbstractHandler { if (guild) { let member = guild.members.get(user.id); if (!member && data.status !== 'offline') { - member = guild.members.create({ + member = guild.members.add({ user, roles: data.roles, deaf: false, @@ -35,17 +35,17 @@ class PresenceUpdateHandler extends AbstractHandler { } if (member) { if (client.listenerCount(Events.PRESENCE_UPDATE) === 0) { - guild.presences.create(data); + guild.presences.add(data); return; } const oldMember = member._clone(); if (member.presence) { oldMember.frozenPresence = member.presence._clone(); } - guild.presences.create(data); + guild.presences.add(data); client.emit(Events.PRESENCE_UPDATE, oldMember, member); } else { - guild.presences.create(data); + guild.presences.add(data); } } } diff --git a/src/client/websocket/packets/handlers/Ready.js b/src/client/websocket/packets/handlers/Ready.js index b1a833d5f..367406ba0 100644 --- a/src/client/websocket/packets/handlers/Ready.js +++ b/src/client/websocket/packets/handlers/Ready.js @@ -18,11 +18,11 @@ class ReadyHandler extends AbstractHandler { client.readyAt = new Date(); client.users.set(clientUser.id, clientUser); - for (const guild of data.guilds) client.guilds.create(guild); - for (const privateDM of data.private_channels) client.channels.create(privateDM); + for (const guild of data.guilds) client.guilds.add(guild); + for (const privateDM of data.private_channels) client.channels.add(privateDM); for (const relation of data.relationships) { - const user = client.users.create(relation.user); + const user = client.users.add(relation.user); if (relation.type === 1) { client.user.friends.set(user.id, user); } else if (relation.type === 2) { @@ -30,7 +30,7 @@ class ReadyHandler extends AbstractHandler { } } - for (const presence of data.presences || []) client.presences.create(presence); + for (const presence of data.presences || []) client.presences.add(presence); if (data.notes) { for (const user in data.notes) { @@ -42,7 +42,7 @@ class ReadyHandler extends AbstractHandler { } if (!client.users.has('1')) { - client.users.create({ + client.users.add({ id: '1', username: 'Clyde', discriminator: '0000', diff --git a/src/stores/ChannelStore.js b/src/stores/ChannelStore.js index 2ceee8000..53a81358c 100644 --- a/src/stores/ChannelStore.js +++ b/src/stores/ChannelStore.js @@ -51,7 +51,7 @@ class ChannelStore extends DataStore { return super.delete(key); } - create(data, guild, cache = true) { + add(data, guild, cache = true) { const existing = this.get(data.id); if (existing) return existing; diff --git a/src/stores/DataStore.js b/src/stores/DataStore.js index c4256dfe2..72f86028e 100644 --- a/src/stores/DataStore.js +++ b/src/stores/DataStore.js @@ -11,10 +11,10 @@ class DataStore extends Collection { if (!Structures) Structures = require('../util/Structures'); Object.defineProperty(this, 'client', { value: client }); Object.defineProperty(this, 'holds', { value: Structures.get(holds.name) || holds }); - if (iterable) for (const item of iterable) this.create(item); + if (iterable) for (const item of iterable) this.add(item); } - create(data, cache = true, { id, extras = [] } = {}) { + add(data, cache = true, { id, extras = [] } = {}) { const existing = this.get(id || data.id); if (existing) return existing; diff --git a/src/stores/EmojiStore.js b/src/stores/EmojiStore.js index 035cc3d4d..1e50c07f4 100644 --- a/src/stores/EmojiStore.js +++ b/src/stores/EmojiStore.js @@ -1,6 +1,8 @@ +const Collection = require('../util/Collection'); const DataStore = require('./DataStore'); const Emoji = require('../structures/Emoji'); const ReactionEmoji = require('../structures/ReactionEmoji'); +const DataResolver = require('../util/DataResolver'); /** * Stores emojis. @@ -13,8 +15,49 @@ class EmojiStore extends DataStore { this.guild = guild; } - create(data, cache) { - return super.create(data, cache, { extras: [this.guild] }); + add(data, cache) { + return super.add(data, cache, { extras: [this.guild] }); + } + + /** + * 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|RoleResolvable[]} [options.roles] Roles to limit the emoji to + * @param {string} [options.reason] Reason for creating the emoji + * @returns {Promise} The created emoji + * @example + * // Create a new emoji from a url + * guild.emojis.create('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.emojis.create('./memes/banana.png', 'banana') + * .then(emoji => console.log(`Created new emoji with name ${emoji.name}!`)) + * .catch(console.error); + */ + create(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.guild.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.guild.id).emojis.post({ data, reason }) + .then(emoji => this.client.actions.GuildEmojiCreate.handle(this.guild, emoji).emoji); + } + + return DataResolver.resolveImage(attachment).then(image => this.create(image, name, { roles, reason })); } /** diff --git a/src/stores/GuildChannelStore.js b/src/stores/GuildChannelStore.js index 0bc3e8c4e..ee9e8f013 100644 --- a/src/stores/GuildChannelStore.js +++ b/src/stores/GuildChannelStore.js @@ -1,6 +1,9 @@ -const DataStore = require('./DataStore'); +const Collection = require('../util/Collection'); const Channel = require('../structures/Channel'); +const { ChannelTypes } = require('../util/Constants'); +const DataStore = require('./DataStore'); const GuildChannel = require('../structures/GuildChannel'); +const { resolve } = require('../util/Permissions'); /** * Stores guild channels. @@ -13,13 +16,80 @@ class GuildChannelStore extends DataStore { this.guild = guild; } - create(data) { + add(data) { const existing = this.get(data.id); if (existing) return existing; return Channel.create(this.client, data, this.guild); } + /** + * 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} [options.overwrites] Permission overwrites + * @param {string} [options.reason] Reason for creating the channel + * @returns {Promise} + * @example + * // Create a new text channel + * guild.channels.create('new-general', { reason: 'Needed a cool new channel' }) + * .then(console.log) + * .catch(console.error); + */ + create(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 = resolve(allow); + if (deny instanceof Array) deny = resolve(deny); + + const role = this.guild.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.guild.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); + } + /** * Data that can be resolved to give a Guild Channel object. This can be: * * A GuildChannel object diff --git a/src/stores/GuildMemberStore.js b/src/stores/GuildMemberStore.js index 692d72784..8cdd7611e 100644 --- a/src/stores/GuildMemberStore.js +++ b/src/stores/GuildMemberStore.js @@ -14,8 +14,8 @@ class GuildMemberStore extends DataStore { this.guild = guild; } - create(data, cache) { - return super.create(data, cache, { extras: [this.guild] }); + add(data, cache) { + return super.add(data, cache, { extras: [this.guild] }); } /** @@ -100,11 +100,85 @@ class GuildMemberStore extends DataStore { return this._fetchMany(options); } + /** + * 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} The number of members that were/will be kicked + * @example + * // See how many members will be pruned + * guild.members.prune({ dry: true }) + * .then(pruned => console.log(`This will prune ${pruned} people!`)) + * .catch(console.error); + * @example + * // Actually prune the members + * guild.members.prune({ days: 1, reason: 'too many people!' }) + * .then(pruned => console.log(`I just pruned ${pruned} people!`)) + * .catch(console.error); + */ + prune({ days = 7, dry = false, reason } = {}) { + if (typeof days !== 'number') throw new TypeError('PRUNE_DAYS_TYPE'); + return this.client.api.guilds(this.guild.id).prune[dry ? 'get' : 'post']({ query: { days }, reason }) + .then(data => data.pruned); + } + + /** + * 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} 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.members.ban('84484653687267328') + * .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.guild.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.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} + * @example + * // Unban a user by ID (or with a user/guild member object) + * guild.members.unban('84484653687267328') + * .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.guild.id).bans[id].delete({ reason }) + .then(() => user); + } + + _fetchSingle({ user, cache }) { const existing = this.get(user); if (existing) return Promise.resolve(existing); return this.client.api.guilds(this.guild.id).members(user).get() - .then(data => this.create(data, cache)); + .then(data => this.add(data, cache)); } _fetchMany({ query = '', limit = 0 } = {}) { diff --git a/src/stores/GuildStore.js b/src/stores/GuildStore.js index 45e9c9cfc..7b7810aee 100644 --- a/src/stores/GuildStore.js +++ b/src/stores/GuildStore.js @@ -1,4 +1,6 @@ const DataStore = require('./DataStore'); +const DataResolver = require('../util/DataResolver'); +const { Events } = require('../util/Constants'); const Guild = require('../structures/Guild'); /** @@ -35,6 +37,44 @@ class GuildStore extends DataStore { * @param {GuildResolvable} guild The guild resolvable to identify * @returns {?Snowflake} */ + + /** + * Creates a guild. + * This is only available when using a user account. + * @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} The guild that was created + */ + create(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.add(data)); + }, 10000); + return undefined; + }, reject) + ); + } + + return DataResolver.resolveImage(icon) + .then(data => this.create(name, { region, icon: data || null })); + } } module.exports = GuildStore; diff --git a/src/stores/MessageStore.js b/src/stores/MessageStore.js index cc0ff60b0..565f4c13d 100644 --- a/src/stores/MessageStore.js +++ b/src/stores/MessageStore.js @@ -13,8 +13,8 @@ class MessageStore extends DataStore { this.channel = channel; } - create(data, cache) { - return super.create(data, cache, { extras: [this.channel] }); + add(data, cache) { + return super.add(data, cache, { extras: [this.channel] }); } set(key, value) { @@ -62,7 +62,7 @@ class MessageStore extends DataStore { fetchPinned() { return this.client.api.channels[this.channel.id].pins.get().then(data => { const messages = new Collection(); - for (const message of data) messages.set(message.id, this.create(message)); + for (const message of data) messages.set(message.id, this.add(message)); return messages; }); } @@ -77,14 +77,14 @@ class MessageStore extends DataStore { }); } return this.client.api.channels[this.channel.id].messages[messageID].get() - .then(data => this.create(data)); + .then(data => this.add(data)); } _fetchMany(options = {}) { return this.client.api.channels[this.channel.id].messages.get({ query: options }) .then(data => { const messages = new Collection(); - for (const message of data) messages.set(message.id, this.create(message)); + for (const message of data) messages.set(message.id, this.add(message)); return messages; }); } diff --git a/src/stores/PresenceStore.js b/src/stores/PresenceStore.js index 8322c9c65..1b927934e 100644 --- a/src/stores/PresenceStore.js +++ b/src/stores/PresenceStore.js @@ -11,9 +11,9 @@ class PresenceStore extends DataStore { super(client, iterable, Presence); } - create(data, cache) { + add(data, cache) { const existing = this.get(data.user.id); - return existing ? existing.patch(data) : super.create(data, cache, { id: data.user.id }); + return existing ? existing.patch(data) : super.add(data, cache, { id: data.user.id }); } /** diff --git a/src/stores/ReactionStore.js b/src/stores/ReactionStore.js index c11b4e176..4a689a447 100644 --- a/src/stores/ReactionStore.js +++ b/src/stores/ReactionStore.js @@ -12,8 +12,8 @@ class ReactionStore extends DataStore { this.message = message; } - create(data, cache) { - return super.create(data, cache, { id: data.emoji.id || data.emoji.name, extras: [this.message] }); + add(data, cache) { + return super.add(data, cache, { id: data.emoji.id || data.emoji.name, extras: [this.message] }); } /** @@ -40,6 +40,15 @@ class ReactionStore extends DataStore { * @param {MessageReactionResolvable} role The role resolvable to resolve * @returns {?Snowflake} */ + + /** + * Removes all reactions from a message. + * @returns {Promise} + */ + removeAll() { + return this.client.api.channels(this.message.channel.id).messages(this.message.id).reactions.delete() + .then(() => this.message); + } } module.exports = ReactionStore; diff --git a/src/stores/ReactionUserStore.js b/src/stores/ReactionUserStore.js index b3c3ec012..d246d10b9 100644 --- a/src/stores/ReactionUserStore.js +++ b/src/stores/ReactionUserStore.js @@ -23,11 +23,33 @@ class ReactionUserStore extends DataStore { .reactions[this.reaction.emoji.identifier] .get({ query: { limit, before, after } }); for (const rawUser of users) { - const user = this.client.users.create(rawUser); + const user = this.client.users.add(rawUser); this.set(user.id, user); } return this; } + + /** + * Removes a user from this reaction. + * @param {UserResolvable} [user=this.reaction.message.client.user] The user to remove the reaction of + * @returns {Promise} + */ + remove(user = this.reaction.message.client.user) { + const message = this.reaction.message; + const userID = message.client.users.resolveID(user); + if (!userID) return Promise.reject(new Error('REACTION_RESOLVE_USER')); + return message.client.api.channels[message.channel.id].messages[message.id] + .reactions[this.reaction.emoji.identifier][userID === message.client.user.id ? '@me' : userID] + .delete() + .then(() => + message.client.actions.MessageReactionRemove.handle({ + user_id: userID, + message_id: message.id, + emoji: this.reaction.emoji, + channel_id: message.channel.id, + }).reaction + ); + } } module.exports = ReactionUserStore; diff --git a/src/stores/RoleStore.js b/src/stores/RoleStore.js index bb8cd749d..14f034337 100644 --- a/src/stores/RoleStore.js +++ b/src/stores/RoleStore.js @@ -1,5 +1,7 @@ const DataStore = require('./DataStore'); const Role = require('../structures/Role'); +const { resolveColor } = require('../util/Util'); +const { resolve } = require('../util/Permissions'); /** * Stores roles. @@ -12,8 +14,44 @@ class RoleStore extends DataStore { this.guild = guild; } - create(data, cache) { - return super.create(data, cache, { extras: [this.guild] }); + add(data, cache) { + return super.add(data, cache, { extras: [this.guild] }); + } + + /** + * Creates a new role in the guild with given information. + * The position will silently reset to 1 if an invalid one is provided, or none. + * @param {RoleData} [data] The data to update the role with + * @param {string} [reason] Reason for creating this role + * @returns {Promise} + * @example + * // Create a new role + * guild.roles.create() + * .then(console.log) + * .catch(console.error); + * @example + * // Create a new role with data and a reason + * guild.roles.create({ + * name: 'Super Cool People', + * color: 'BLUE' + * }, + * reason: 'we needed a role for Super Cool People', + * }) + * .then(console.log) + * .catch(console.error); + */ + create(data = {}, reason) { + if (data.color) data.color = resolveColor(data.color); + if (data.permissions) data.permissions = resolve(data.permissions); + + return this.guild.client.api.guilds(this.guild.id).roles.post({ data, reason }).then(r => { + const { role } = this.client.actions.GuildRoleCreate.handle({ + guild_id: this.guild.id, + role: r, + }); + if (data.position) return role.setPosition(data.position, reason); + return role; + }); } /** diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index 432a0768a..48e988405 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js @@ -54,7 +54,7 @@ class UserStore extends DataStore { const existing = this.get(id); if (existing) return Promise.resolve(existing); - return this.client.api.users(id).get().then(data => this.create(data, cache)); + return this.client.api.users(id).get().then(data => this.add(data, cache)); } } diff --git a/src/structures/ClientApplication.js b/src/structures/ClientApplication.js index 073fce7ba..749f635ed 100644 --- a/src/structures/ClientApplication.js +++ b/src/structures/ClientApplication.js @@ -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); } } diff --git a/src/structures/ClientUser.js b/src/structures/ClientUser.js index b0b3452d4..42556ae2c 100644 --- a/src/structures/ClientUser.js +++ b/src/structures/ClientUser.js @@ -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. - * This is only available when using a user account. - * @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} 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)); } } diff --git a/src/structures/DMChannel.js b/src/structures/DMChannel.js index fe6ba57c6..0567b98d4 100644 --- a/src/structures/DMChannel.js +++ b/src/structures/DMChannel.js @@ -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; } diff --git a/src/structures/GroupDMChannel.js b/src/structures/GroupDMChannel.js index 2ade06b06..4868fbbb9 100644 --- a/src/structures/GroupDMChannel.js +++ b/src/structures/GroupDMChannel.js @@ -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); } } diff --git a/src/structures/Guild.js b/src/structures/Guild.js index c47fd74f5..977e7b463 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -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} */ 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} 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} - * @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} 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). * This is only available when using a user account. @@ -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} [options.overwrites] Permission overwrites - * @param {string} [options.reason] Reason for creating the channel - * @returns {Promise} - * @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. - * The position will silently reset to 1 if an invalid one is provided, or none. - * @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} - * @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|RoleResolvable[]} [options.roles] Roles to limit the emoji to - * @param {string} [options.reason] Reason for creating the emoji - * @returns {Promise} 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} diff --git a/src/structures/GuildAuditLogs.js b/src/structures/GuildAuditLogs.js index d43a48b29..148e199a9 100644 --- a/src/structures/GuildAuditLogs.js +++ b/src/structures/GuildAuditLogs.js @@ -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} diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 8a22c0e4d..182f9cb12 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -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; } diff --git a/src/structures/Invite.js b/src/structures/Invite.js index 89d5c9c99..1f02d11b7 100644 --- a/src/structures/Invite.js +++ b/src/structures/Invite.js @@ -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 diff --git a/src/structures/Message.js b/src/structures/Message.js index 050adae9f..8fb9688fa 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -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} - */ - clearReactions() { - return this.client.api.channels(this.channel.id).messages(this.id).reactions.delete() - .then(() => this); - } - /** * Deletes the message. * @param {Object} [options] Options diff --git a/src/structures/MessageMentions.js b/src/structures/MessageMentions.js index ee4a0e69d..102e63aaa 100644 --- a/src/structures/MessageMentions.js +++ b/src/structures/MessageMentions.js @@ -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); } } diff --git a/src/structures/MessageReaction.js b/src/structures/MessageReaction.js index 28a320a63..b65721134 100644 --- a/src/structures/MessageReaction.js +++ b/src/structures/MessageReaction.js @@ -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} - */ - 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); diff --git a/src/structures/TextChannel.js b/src/structures/TextChannel.js index 5679f841a..2c512dcee 100644 --- a/src/structures/TextChannel.js +++ b/src/structures/TextChannel.js @@ -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); } /** diff --git a/src/structures/Webhook.js b/src/structures/Webhook.js index 7ee44745e..ba56ebdd3 100644 --- a/src/structures/Webhook.js +++ b/src/structures/Webhook.js @@ -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); }); } diff --git a/src/structures/shared/Search.js b/src/structures/shared/Search.js index 3adca7fcc..db30b572c 100644 --- a/src/structures/shared/Search.js +++ b/src/structures/shared/Search.js @@ -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,