mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-14 18:43:31 +01:00
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
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<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.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 }));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<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.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
|
||||
|
||||
@@ -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<number>} 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<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.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<User>}
|
||||
* @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 } = {}) {
|
||||
|
||||
@@ -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.
|
||||
* <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
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<Message>}
|
||||
*/
|
||||
removeAll() {
|
||||
return this.client.api.channels(this.message.channel.id).messages(this.message.id).reactions.delete()
|
||||
.then(() => this.message);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReactionStore;
|
||||
|
||||
@@ -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<MessageReaction>}
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -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.
|
||||
* <warn>The position will silently reset to 1 if an invalid one is provided, or none.</warn>
|
||||
* @param {RoleData} [data] The data to update the role with
|
||||
* @param {string} [reason] Reason for creating this role
|
||||
* @returns {Promise<Role>}
|
||||
* @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;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user