'use strict'; const CachedManager = require('./CachedManager'); const { Error } = require('../errors'); const { GuildMember } = require('../structures/GuildMember'); const { Message } = require('../structures/Message'); const ThreadMember = require('../structures/ThreadMember'); const User = require('../structures/User'); /** * Manages API methods for users and stores their cache. * @extends {CachedManager} */ class UserManager extends CachedManager { constructor(client, iterable) { super(client, User, iterable); } /** * The cache of this manager * @type {Collection} * @name UserManager#cache */ /** * Data that resolves to give a User object. This can be: * * A User object * * A Snowflake * * A Message object (resolves to the message author) * * A GuildMember object * * A ThreadMember object * @typedef {User|Snowflake|Message|GuildMember|ThreadMember} UserResolvable */ /** * The DM between the client's user and a user * @param {Snowflake} userId The user id * @returns {?DMChannel} * @private */ dmChannel(userId) { return this.client.channels.cache.find(c => c.type === 'DM' && c.recipient.id === userId) ?? null; } /** * Creates a {@link DMChannel} between the client and a user. * @param {UserResolvable} user The UserResolvable to identify * @param {BaseFetchOptions} [options] Additional options for this fetch * @returns {Promise} */ async createDM(user, { cache = true, force = false } = {}) { const id = this.resolveId(user); if (!force) { const dmChannel = this.dmChannel(id); if (dmChannel && !dmChannel.partial) return dmChannel; } const data = await this.client.api.users(this.client.user.id).channels.post({ data: { recipients: [id], }, headers: { 'X-Context-Properties': 'e30=', // {} }, }); const dm_channel = await this.client.channels._add(data, null, { cache }); await dm_channel.sync(); return dm_channel; } /** * Deletes a {@link DMChannel} (if one exists) between the client and a user. Resolves with the channel if successful. * @param {UserResolvable} user The UserResolvable to identify * @returns {Promise} */ async deleteDM(user) { const id = this.resolveId(user); const dmChannel = this.dmChannel(id); if (!dmChannel) throw new Error('USER_NO_DM_CHANNEL'); await this.client.api.channels(dmChannel.id).delete(); this.client.channels._remove(dmChannel.id); return dmChannel; } /** * Obtains a user from Discord, or the user cache if it's already available. * @param {UserResolvable} user The user to fetch * @param {BaseFetchOptions} [options] Additional options for this fetch * @param {?Snowflake} [options.guildId] The guild ID to fetch the member for * @returns {Promise} */ async fetch(user, { cache = true, force = false, guildId = null } = {}) { const id = this.resolveId(user); if (!force) { const existing = this.cache.get(id); if (existing && !existing.partial) return existing; } const data = await this.client.api.users(id).get(); const userObject = this._add(data, cache); await userObject.getProfile(guildId ?? null).catch(() => {}); return userObject; } /** * Fetches a user's flags. * @param {UserResolvable} user The UserResolvable to identify * @param {BaseFetchOptions} [options] Additional options for this fetch * @returns {Promise} */ async fetchFlags(user, options) { return (await this.fetch(user, options)).flags; } /** * Sends a message to a user. * @param {UserResolvable} user The UserResolvable to identify * @param {string|MessagePayload|MessageOptions} options The options to provide * @returns {Promise} */ async send(user, options) { return (await this.createDM(user)).send(options); } /** * Resolves a {@link UserResolvable} to a {@link User} object. * @param {UserResolvable} user The UserResolvable to identify * @returns {?User} */ resolve(user) { if (user instanceof GuildMember || user instanceof ThreadMember) return user.user; if (user instanceof Message) return user.author; return super.resolve(user); } /** * Resolves a {@link UserResolvable} to a {@link User} id. * @param {UserResolvable} user The UserResolvable to identify * @returns {?Snowflake} */ resolveId(user) { if (user instanceof ThreadMember) return user.id; if (user instanceof GuildMember) return user.user.id; if (user instanceof Message) return user.author.id; return super.resolveId(user); } } module.exports = UserManager;