Add files via upload
This commit is contained in:
parent
6af816d457
commit
f1fc882d35
@ -1,223 +1,223 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const ApplicationCommandPermissionsManager = require('./ApplicationCommandPermissionsManager');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { TypeError } = require('../errors');
|
||||
const ApplicationCommand = require('../structures/ApplicationCommand');
|
||||
const { ApplicationCommandTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Manages API methods for application commands and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class ApplicationCommandManager extends CachedManager {
|
||||
constructor(client, iterable, user) {
|
||||
super(client, ApplicationCommand, iterable);
|
||||
|
||||
/**
|
||||
* The manager for permissions of arbitrary commands on arbitrary guilds
|
||||
* @type {ApplicationCommandPermissionsManager}
|
||||
*/
|
||||
this.permissions = new ApplicationCommandPermissionsManager(this, user);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of this manager
|
||||
* @type {Collection<Snowflake, ApplicationCommand>}
|
||||
* @name ApplicationCommandManager#cache
|
||||
*/
|
||||
|
||||
_add(data, cache, guildId) {
|
||||
return super._add(data, cache, { extras: [this.guild, guildId] });
|
||||
}
|
||||
|
||||
/**
|
||||
* The APIRouter path to the commands
|
||||
* @param {Snowflake} [options.id] The application command's id
|
||||
* @param {Snowflake} [options.guildId] The guild's id to use in the path,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
commandPath({ id, guildId } = {}) {
|
||||
let path = this.client.api.applications(this.user.id);
|
||||
if (this.guild ?? guildId) path = path.guilds(this.guild?.id ?? guildId);
|
||||
return id ? path.commands(id) : path.commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that resolves to give an ApplicationCommand object. This can be:
|
||||
* * An ApplicationCommand object
|
||||
* * A Snowflake
|
||||
* @typedef {ApplicationCommand|Snowflake} ApplicationCommandResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to fetch data from Discord
|
||||
* @typedef {Object} BaseFetchOptions
|
||||
* @property {boolean} [cache=true] Whether to cache the fetched data if it wasn't already
|
||||
* @property {boolean} [force=false] Whether to skip the cache check and request the API
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to fetch Application Commands from Discord
|
||||
* @typedef {BaseFetchOptions} FetchApplicationCommandOptions
|
||||
* @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtains one or multiple application commands from Discord, or the cache if it's already available.
|
||||
* @param {Snowflake} [id] The application command's id
|
||||
* @param {FetchApplicationCommandOptions} [options] Additional options for this fetch
|
||||
* @returns {Promise<ApplicationCommand|Collection<Snowflake, ApplicationCommand>>}
|
||||
* @example
|
||||
* // Fetch a single command
|
||||
* client.application.commands.fetch('123456789012345678')
|
||||
* .then(command => console.log(`Fetched command ${command.name}`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch all commands
|
||||
* guild.commands.fetch()
|
||||
* .then(commands => console.log(`Fetched ${commands.size} commands`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetch(id, { guildId, cache = true, force = false } = {}) {
|
||||
await this.user.createDM().catch(() => {});
|
||||
if (typeof id === 'object') {
|
||||
({ guildId, cache = true } = id);
|
||||
} else if (id) {
|
||||
if (!force) {
|
||||
const existing = this.cache.get(id);
|
||||
if (existing) return existing;
|
||||
}
|
||||
const command = await this.commandPath({ id, guildId }).get();
|
||||
return this._add(command, cache);
|
||||
}
|
||||
|
||||
const data = await this.commandPath({ guildId }).get();
|
||||
return data.reduce((coll, command) => coll.set(command.id, this._add(command, cache, guildId)), new Collection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an application command.
|
||||
* @param {ApplicationCommandData|APIApplicationCommand} command The command
|
||||
* @param {Snowflake} [guildId] The guild's id to create this command in,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<ApplicationCommand>}
|
||||
* @example
|
||||
* // Create a new command
|
||||
* client.application.commands.create({
|
||||
* name: 'test',
|
||||
* description: 'A test command',
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create(command, guildId) {
|
||||
if(!this.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const data = await this.commandPath({ guildId }).post({
|
||||
data: this.constructor.transformCommand(command),
|
||||
});
|
||||
return this._add(data, true, guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all the commands for this application or guild.
|
||||
* @param {ApplicationCommandData[]|APIApplicationCommand[]} commands The commands
|
||||
* @param {Snowflake} [guildId] The guild's id to create the commands in,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<Collection<Snowflake, ApplicationCommand>>}
|
||||
* @example
|
||||
* // Set all commands to just this one
|
||||
* client.application.commands.set([
|
||||
* {
|
||||
* name: 'test',
|
||||
* description: 'A test command',
|
||||
* },
|
||||
* ])
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Remove all commands
|
||||
* guild.commands.set([])
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async set(commands, guildId) {
|
||||
if(!this.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const data = await this.commandPath({ guildId }).put({
|
||||
data: commands.map(c => this.constructor.transformCommand(c)),
|
||||
});
|
||||
return data.reduce((coll, command) => coll.set(command.id, this._add(command, true, guildId)), new Collection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits an application command.
|
||||
* @param {ApplicationCommandResolvable} command The command to edit
|
||||
* @param {ApplicationCommandData|APIApplicationCommand} data The data to update the command with
|
||||
* @param {Snowflake} [guildId] The guild's id where the command registered,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<ApplicationCommand>}
|
||||
* @example
|
||||
* // Edit an existing command
|
||||
* client.application.commands.edit('123456789012345678', {
|
||||
* description: 'New description',
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async edit(command, data, guildId) {
|
||||
if(!this.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const id = this.resolveId(command);
|
||||
if (!id) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
|
||||
const patched = await this.commandPath({ id, guildId }).patch({
|
||||
data: this.constructor.transformCommand(data),
|
||||
});
|
||||
return this._add(patched, true, guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an application command.
|
||||
* @param {ApplicationCommandResolvable} command The command to delete
|
||||
* @param {Snowflake} [guildId] The guild's id where the command is registered,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<?ApplicationCommand>}
|
||||
* @example
|
||||
* // Delete a command
|
||||
* guild.commands.delete('123456789012345678')
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async delete(command, guildId) {
|
||||
if(!this.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const id = this.resolveId(command);
|
||||
if (!id) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
|
||||
await this.commandPath({ id, guildId }).delete();
|
||||
|
||||
const cached = this.cache.get(id);
|
||||
this.cache.delete(id);
|
||||
return cached ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an {@link ApplicationCommandData} object into something that can be used with the API.
|
||||
* @param {ApplicationCommandData|APIApplicationCommand} command The command to transform
|
||||
* @returns {APIApplicationCommand}
|
||||
* @private
|
||||
*/
|
||||
static transformCommand(command) {
|
||||
return {
|
||||
name: command.name,
|
||||
description: command.description,
|
||||
type: typeof command.type === 'number' ? command.type : ApplicationCommandTypes[command.type],
|
||||
options: command.options?.map(o => ApplicationCommand.transformOption(o)),
|
||||
default_permission: command.defaultPermission ?? command.default_permission,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ApplicationCommandManager;
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const ApplicationCommandPermissionsManager = require('./ApplicationCommandPermissionsManager');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { TypeError } = require('../errors');
|
||||
const ApplicationCommand = require('../structures/ApplicationCommand');
|
||||
const { ApplicationCommandTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Manages API methods for application commands and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class ApplicationCommandManager extends CachedManager {
|
||||
constructor(client, iterable, user) {
|
||||
super(client, ApplicationCommand, iterable);
|
||||
|
||||
/**
|
||||
* The manager for permissions of arbitrary commands on arbitrary guilds
|
||||
* @type {ApplicationCommandPermissionsManager}
|
||||
*/
|
||||
this.permissions = new ApplicationCommandPermissionsManager(this, user);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of this manager
|
||||
* @type {Collection<Snowflake, ApplicationCommand>}
|
||||
* @name ApplicationCommandManager#cache
|
||||
*/
|
||||
|
||||
_add(data, cache, guildId) {
|
||||
return super._add(data, cache, { extras: [this.guild, guildId] });
|
||||
}
|
||||
|
||||
/**
|
||||
* The APIRouter path to the commands
|
||||
* @param {Snowflake} [options.id] The application command's id
|
||||
* @param {Snowflake} [options.guildId] The guild's id to use in the path,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
commandPath({ id, guildId } = {}) {
|
||||
let path = this.client.api.applications(this.user.id);
|
||||
if (this.guild ?? guildId) path = path.guilds(this.guild?.id ?? guildId);
|
||||
return id ? path.commands(id) : path.commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that resolves to give an ApplicationCommand object. This can be:
|
||||
* * An ApplicationCommand object
|
||||
* * A Snowflake
|
||||
* @typedef {ApplicationCommand|Snowflake} ApplicationCommandResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to fetch data from Discord
|
||||
* @typedef {Object} BaseFetchOptions
|
||||
* @property {boolean} [cache=true] Whether to cache the fetched data if it wasn't already
|
||||
* @property {boolean} [force=false] Whether to skip the cache check and request the API
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to fetch Application Commands from Discord
|
||||
* @typedef {BaseFetchOptions} FetchApplicationCommandOptions
|
||||
* @property {Snowflake} [guildId] The guild's id to fetch commands for, for when the guild is not cached
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtains one or multiple application commands from Discord, or the cache if it's already available.
|
||||
* @param {Snowflake} [id] The application command's id
|
||||
* @param {FetchApplicationCommandOptions} [options] Additional options for this fetch
|
||||
* @returns {Promise<ApplicationCommand|Collection<Snowflake, ApplicationCommand>>}
|
||||
* @example
|
||||
* // Fetch a single command
|
||||
* client.application.commands.fetch('123456789012345678')
|
||||
* .then(command => console.log(`Fetched command ${command.name}`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch all commands
|
||||
* guild.commands.fetch()
|
||||
* .then(commands => console.log(`Fetched ${commands.size} commands`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetch(id, { guildId, cache = true, force = false } = {}) {
|
||||
await this.user.createDM().catch(() => {});
|
||||
if (typeof id === 'object') {
|
||||
({ guildId, cache = true } = id);
|
||||
} else if (id) {
|
||||
if (!force) {
|
||||
const existing = this.cache.get(id);
|
||||
if (existing) return existing;
|
||||
}
|
||||
const command = await this.commandPath({ id, guildId }).get();
|
||||
return this._add(command, cache);
|
||||
}
|
||||
|
||||
const data = await this.commandPath({ guildId }).get();
|
||||
return data.reduce((coll, command) => coll.set(command.id, this._add(command, cache, guildId)), new Collection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an application command.
|
||||
* @param {ApplicationCommandData|APIApplicationCommand} command The command
|
||||
* @param {Snowflake} [guildId] The guild's id to create this command in,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<ApplicationCommand>}
|
||||
* @example
|
||||
* // Create a new command
|
||||
* client.application.commands.create({
|
||||
* name: 'test',
|
||||
* description: 'A test command',
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async create(command, guildId) {
|
||||
if(!this.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const data = await this.commandPath({ guildId }).post({
|
||||
data: this.constructor.transformCommand(command),
|
||||
});
|
||||
return this._add(data, true, guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all the commands for this application or guild.
|
||||
* @param {ApplicationCommandData[]|APIApplicationCommand[]} commands The commands
|
||||
* @param {Snowflake} [guildId] The guild's id to create the commands in,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<Collection<Snowflake, ApplicationCommand>>}
|
||||
* @example
|
||||
* // Set all commands to just this one
|
||||
* client.application.commands.set([
|
||||
* {
|
||||
* name: 'test',
|
||||
* description: 'A test command',
|
||||
* },
|
||||
* ])
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Remove all commands
|
||||
* guild.commands.set([])
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async set(commands, guildId) {
|
||||
if(!this.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const data = await this.commandPath({ guildId }).put({
|
||||
data: commands.map(c => this.constructor.transformCommand(c)),
|
||||
});
|
||||
return data.reduce((coll, command) => coll.set(command.id, this._add(command, true, guildId)), new Collection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits an application command.
|
||||
* @param {ApplicationCommandResolvable} command The command to edit
|
||||
* @param {ApplicationCommandData|APIApplicationCommand} data The data to update the command with
|
||||
* @param {Snowflake} [guildId] The guild's id where the command registered,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<ApplicationCommand>}
|
||||
* @example
|
||||
* // Edit an existing command
|
||||
* client.application.commands.edit('123456789012345678', {
|
||||
* description: 'New description',
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async edit(command, data, guildId) {
|
||||
if(!this.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const id = this.resolveId(command);
|
||||
if (!id) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
|
||||
const patched = await this.commandPath({ id, guildId }).patch({
|
||||
data: this.constructor.transformCommand(data),
|
||||
});
|
||||
return this._add(patched, true, guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an application command.
|
||||
* @param {ApplicationCommandResolvable} command The command to delete
|
||||
* @param {Snowflake} [guildId] The guild's id where the command is registered,
|
||||
* ignored when using a {@link GuildApplicationCommandManager}
|
||||
* @returns {Promise<?ApplicationCommand>}
|
||||
* @example
|
||||
* // Delete a command
|
||||
* guild.commands.delete('123456789012345678')
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async delete(command, guildId) {
|
||||
if(!this.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const id = this.resolveId(command);
|
||||
if (!id) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
|
||||
await this.commandPath({ id, guildId }).delete();
|
||||
|
||||
const cached = this.cache.get(id);
|
||||
this.cache.delete(id);
|
||||
return cached ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an {@link ApplicationCommandData} object into something that can be used with the API.
|
||||
* @param {ApplicationCommandData|APIApplicationCommand} command The command to transform
|
||||
* @returns {APIApplicationCommand}
|
||||
* @private
|
||||
*/
|
||||
static transformCommand(command) {
|
||||
return {
|
||||
name: command.name,
|
||||
description: command.description,
|
||||
type: typeof command.type === 'number' ? command.type : ApplicationCommandTypes[command.type],
|
||||
options: command.options?.map(o => ApplicationCommand.transformOption(o)),
|
||||
default_permission: command.defaultPermission ?? command.default_permission,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ApplicationCommandManager;
|
||||
|
@ -1,422 +1,422 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const BaseManager = require('./BaseManager');
|
||||
const { Error, TypeError } = require('../errors');
|
||||
const { ApplicationCommandPermissionTypes, APIErrors } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Manages API methods for permissions of Application Commands.
|
||||
* @extends {BaseManager}
|
||||
*/
|
||||
class ApplicationCommandPermissionsManager extends BaseManager {
|
||||
constructor(manager, user) {
|
||||
super(manager.client);
|
||||
|
||||
/**
|
||||
* The manager or command that this manager belongs to
|
||||
* @type {ApplicationCommandManager|ApplicationCommand}
|
||||
* @private
|
||||
*/
|
||||
this.manager = manager;
|
||||
|
||||
/**
|
||||
* The guild that this manager acts on
|
||||
* @type {?Guild}
|
||||
*/
|
||||
this.guild = manager.guild ?? null;
|
||||
|
||||
/**
|
||||
* The id of the guild that this manager acts on
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.guildId = manager.guildId ?? manager.guild?.id ?? null;
|
||||
|
||||
/**
|
||||
* The id of the command this manager acts on
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.commandId = manager.id ?? null;
|
||||
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APIRouter path to the commands
|
||||
* @param {Snowflake} guildId The guild's id to use in the path,
|
||||
* @param {Snowflake} [commandId] The application command's id
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
permissionsPath(guildId, commandId) {
|
||||
return this.client.api.applications(typeof this.user == 'string' ? this.user : this.user.id).guilds(guildId).commands(commandId).permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for setting the permissions of an application command.
|
||||
* @typedef {Object} ApplicationCommandPermissionData
|
||||
* @property {Snowflake} id The role or user's id
|
||||
* @property {ApplicationCommandPermissionType|number} type Whether this permission is for a role or a user
|
||||
* @property {boolean} permission Whether the role or user has the permission to use this command
|
||||
*/
|
||||
|
||||
/**
|
||||
* The object returned when fetching permissions for an application command.
|
||||
* @typedef {Object} ApplicationCommandPermissions
|
||||
* @property {Snowflake} id The role or user's id
|
||||
* @property {ApplicationCommandPermissionType} type Whether this permission is for a role or a user
|
||||
* @property {boolean} permission Whether the role or user has the permission to use this command
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options for managing permissions for one or more Application Commands
|
||||
* <warn>When passing these options to a manager where `guildId` is `null`,
|
||||
* `guild` is a required parameter</warn>
|
||||
* @typedef {Object} BaseApplicationCommandPermissionsOptions
|
||||
* @property {GuildResolvable} [guild] The guild to modify / check permissions for
|
||||
* <warn>Ignored when the manager has a non-null `guildId` property</warn>
|
||||
* @property {ApplicationCommandResolvable} [command] The command to modify / check permissions for
|
||||
* <warn>Ignored when the manager has a non-null `commandId` property</warn>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetches the permissions for one or multiple commands.
|
||||
* @param {BaseApplicationCommandPermissionsOptions} [options] Options used to fetch permissions
|
||||
* @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
|
||||
* @example
|
||||
* // Fetch permissions for one command
|
||||
* guild.commands.permissions.fetch({ command: '123456789012345678' })
|
||||
* .then(perms => console.log(`Fetched permissions for ${perms.length} users`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch permissions for all commands in a guild
|
||||
* client.application.commands.permissions.fetch({ guild: '123456789012345678' })
|
||||
* .then(perms => console.log(`Fetched permissions for ${perms.size} commands`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetch({ guild, command } = {}) {
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
if (commandId) {
|
||||
const data = await this.permissionsPath(guildId, commandId).get();
|
||||
return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
|
||||
}
|
||||
|
||||
const data = await this.permissionsPath(guildId).get();
|
||||
return data.reduce(
|
||||
(coll, perm) =>
|
||||
coll.set(
|
||||
perm.id,
|
||||
perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
|
||||
),
|
||||
new Collection(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data used for overwriting the permissions for all application commands in a guild.
|
||||
* @typedef {Object} GuildApplicationCommandPermissionData
|
||||
* @property {Snowflake} id The command's id
|
||||
* @property {ApplicationCommandPermissionData[]} permissions The permissions for this command
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to set permissions for one or more Application Commands in a guild
|
||||
* <warn>One of `command` AND `permissions`, OR `fullPermissions` is required.
|
||||
* `fullPermissions` is not a valid option when passing to a manager where `commandId` is non-null</warn>
|
||||
* @typedef {BaseApplicationCommandPermissionsOptions} SetApplicationCommandPermissionsOptions
|
||||
* @property {ApplicationCommandPermissionData[]} [permissions] The new permissions for the command
|
||||
* @property {GuildApplicationCommandPermissionData[]} [fullPermissions] The new permissions for all commands
|
||||
* in a guild <warn>When this parameter is set, `permissions` and `command` are ignored</warn>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the permissions for one or more commands.
|
||||
* @param {SetApplicationCommandPermissionsOptions} options Options used to set permissions
|
||||
* @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
|
||||
* @example
|
||||
* // Set the permissions for one command
|
||||
* client.application.commands.permissions.set({ guild: '892455839386304532', command: '123456789012345678',
|
||||
* permissions: [
|
||||
* {
|
||||
* id: '876543210987654321',
|
||||
* type: 'USER',
|
||||
* permission: false,
|
||||
* },
|
||||
* ]})
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Set the permissions for all commands
|
||||
* guild.commands.permissions.set({ fullPermissions: [
|
||||
* {
|
||||
* id: '123456789012345678',
|
||||
* permissions: [{
|
||||
* id: '876543210987654321',
|
||||
* type: 'USER',
|
||||
* permission: false,
|
||||
* }],
|
||||
* },
|
||||
* ]})
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async set({ guild, command, permissions, fullPermissions } = {}) {
|
||||
if(!this.manager.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
|
||||
if (commandId) {
|
||||
if (!Array.isArray(permissions)) {
|
||||
throw new TypeError('INVALID_TYPE', 'permissions', 'Array of ApplicationCommandPermissionData', true);
|
||||
}
|
||||
const data = await this.permissionsPath(guildId, commandId).put({
|
||||
data: { permissions: permissions.map(perm => this.constructor.transformPermissions(perm)) },
|
||||
});
|
||||
return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
|
||||
}
|
||||
|
||||
if (!Array.isArray(fullPermissions)) {
|
||||
throw new TypeError('INVALID_TYPE', 'fullPermissions', 'Array of GuildApplicationCommandPermissionData', true);
|
||||
}
|
||||
|
||||
const APIPermissions = [];
|
||||
for (const perm of fullPermissions) {
|
||||
if (!Array.isArray(perm.permissions)) throw new TypeError('INVALID_ELEMENT', 'Array', 'fullPermissions', perm);
|
||||
APIPermissions.push({
|
||||
id: perm.id,
|
||||
permissions: perm.permissions.map(p => this.constructor.transformPermissions(p)),
|
||||
});
|
||||
}
|
||||
const data = await this.permissionsPath(guildId).put({
|
||||
data: APIPermissions,
|
||||
});
|
||||
return data.reduce(
|
||||
(coll, perm) =>
|
||||
coll.set(
|
||||
perm.id,
|
||||
perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
|
||||
),
|
||||
new Collection(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to add permissions to a command
|
||||
* <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
|
||||
* @typedef {BaseApplicationCommandPermissionsOptions} AddApplicationCommandPermissionsOptions
|
||||
* @property {ApplicationCommandPermissionData[]} permissions The permissions to add to the command
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add permissions to a command.
|
||||
* @param {AddApplicationCommandPermissionsOptions} options Options used to add permissions
|
||||
* @returns {Promise<ApplicationCommandPermissions[]>}
|
||||
* @example
|
||||
* // Block a role from the command permissions
|
||||
* guild.commands.permissions.add({ command: '123456789012345678', permissions: [
|
||||
* {
|
||||
* id: '876543211234567890',
|
||||
* type: 'ROLE',
|
||||
* permission: false
|
||||
* },
|
||||
* ]})
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async add({ guild, command, permissions }) {
|
||||
if(!this.manager.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
if (!Array.isArray(permissions)) {
|
||||
throw new TypeError('INVALID_TYPE', 'permissions', 'Array of ApplicationCommandPermissionData', true);
|
||||
}
|
||||
|
||||
let existing = [];
|
||||
try {
|
||||
existing = await this.fetch({ guild: guildId, command: commandId });
|
||||
} catch (error) {
|
||||
if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
|
||||
}
|
||||
|
||||
const newPermissions = permissions.slice();
|
||||
for (const perm of existing) {
|
||||
if (!newPermissions.some(x => x.id === perm.id)) {
|
||||
newPermissions.push(perm);
|
||||
}
|
||||
}
|
||||
|
||||
return this.set({ guild: guildId, command: commandId, permissions: newPermissions });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to remove permissions from a command
|
||||
* <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
|
||||
* @typedef {BaseApplicationCommandPermissionsOptions} RemoveApplicationCommandPermissionsOptions
|
||||
* @property {UserResolvable|UserResolvable[]} [users] The user(s) to remove from the command permissions
|
||||
* <warn>One of `users` or `roles` is required</warn>
|
||||
* @property {RoleResolvable|RoleResolvable[]} [roles] The role(s) to remove from the command permissions
|
||||
* <warn>One of `users` or `roles` is required</warn>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Remove permissions from a command.
|
||||
* @param {RemoveApplicationCommandPermissionsOptions} options Options used to remove permissions
|
||||
* @returns {Promise<ApplicationCommandPermissions[]>}
|
||||
* @example
|
||||
* // Remove a user permission from this command
|
||||
* guild.commands.permissions.remove({ command: '123456789012345678', users: '876543210123456789' })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Remove multiple roles from this command
|
||||
* guild.commands.permissions.remove({
|
||||
* command: '123456789012345678', roles: ['876543210123456789', '765432101234567890']
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async remove({ guild, command, users, roles }) {
|
||||
if(!this.manager.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
|
||||
if (!users && !roles) throw new TypeError('INVALID_TYPE', 'users OR roles', 'Array or Resolvable', true);
|
||||
|
||||
let resolvedIds = [];
|
||||
if (Array.isArray(users)) {
|
||||
users.forEach(user => {
|
||||
const userId = this.client.users.resolveId(user);
|
||||
if (!userId) throw new TypeError('INVALID_ELEMENT', 'Array', 'users', user);
|
||||
resolvedIds.push(userId);
|
||||
});
|
||||
} else if (users) {
|
||||
const userId = this.client.users.resolveId(users);
|
||||
if (!userId) {
|
||||
throw new TypeError('INVALID_TYPE', 'users', 'Array or UserResolvable');
|
||||
}
|
||||
resolvedIds.push(userId);
|
||||
}
|
||||
|
||||
if (Array.isArray(roles)) {
|
||||
roles.forEach(role => {
|
||||
if (typeof role === 'string') {
|
||||
resolvedIds.push(role);
|
||||
return;
|
||||
}
|
||||
if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
|
||||
const roleId = this.guild.roles.resolveId(role);
|
||||
if (!roleId) throw new TypeError('INVALID_ELEMENT', 'Array', 'users', role);
|
||||
resolvedIds.push(roleId);
|
||||
});
|
||||
} else if (roles) {
|
||||
if (typeof roles === 'string') {
|
||||
resolvedIds.push(roles);
|
||||
} else {
|
||||
if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
|
||||
const roleId = this.guild.roles.resolveId(roles);
|
||||
if (!roleId) {
|
||||
throw new TypeError('INVALID_TYPE', 'users', 'Array or RoleResolvable');
|
||||
}
|
||||
resolvedIds.push(roleId);
|
||||
}
|
||||
}
|
||||
|
||||
let existing = [];
|
||||
try {
|
||||
existing = await this.fetch({ guild: guildId, command: commandId });
|
||||
} catch (error) {
|
||||
if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
|
||||
}
|
||||
|
||||
const permissions = existing.filter(perm => !resolvedIds.includes(perm.id));
|
||||
|
||||
return this.set({ guild: guildId, command: commandId, permissions });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to check the existence of permissions on a command
|
||||
* <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
|
||||
* @typedef {BaseApplicationCommandPermissionsOptions} HasApplicationCommandPermissionsOptions
|
||||
* @property {UserResolvable|RoleResolvable} permissionId The user or role to check if a permission exists for
|
||||
* on this command.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check whether a permission exists for a user or role
|
||||
* @param {AddApplicationCommandPermissionsOptions} options Options used to check permissions
|
||||
* @returns {Promise<boolean>}
|
||||
* @example
|
||||
* // Check whether a user has permission to use a command
|
||||
* guild.commands.permissions.has({ command: '123456789012345678', permissionId: '876543210123456789' })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async has({ guild, command, permissionId }) {
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
|
||||
if (!permissionId) throw new TypeError('INVALID_TYPE', 'permissionId', 'UserResolvable or RoleResolvable');
|
||||
let resolvedId = permissionId;
|
||||
if (typeof permissionId !== 'string') {
|
||||
resolvedId = this.client.users.resolveId(permissionId);
|
||||
if (!resolvedId) {
|
||||
if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
|
||||
resolvedId = this.guild.roles.resolveId(permissionId);
|
||||
}
|
||||
if (!resolvedId) {
|
||||
throw new TypeError('INVALID_TYPE', 'permissionId', 'UserResolvable or RoleResolvable');
|
||||
}
|
||||
}
|
||||
|
||||
let existing = [];
|
||||
try {
|
||||
existing = await this.fetch({ guild: guildId, command: commandId });
|
||||
} catch (error) {
|
||||
if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
|
||||
}
|
||||
|
||||
return existing.some(perm => perm.id === resolvedId);
|
||||
}
|
||||
|
||||
_validateOptions(guild, command) {
|
||||
const guildId = this.guildId ?? this.client.guilds.resolveId(guild);
|
||||
if (!guildId) throw new Error('GLOBAL_COMMAND_PERMISSIONS');
|
||||
let commandId = this.commandId;
|
||||
if (command && !commandId) {
|
||||
commandId = this.manager.resolveId?.(command);
|
||||
if (!commandId && this.guild) {
|
||||
commandId = this.guild.commands.resolveId(command);
|
||||
}
|
||||
commandId ??= this.client.application?.commands.resolveId(command);
|
||||
if (!commandId) {
|
||||
throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable', true);
|
||||
}
|
||||
}
|
||||
return { guildId, commandId };
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an {@link ApplicationCommandPermissionData} object into something that can be used with the API.
|
||||
* @param {ApplicationCommandPermissionData} permissions The permissions to transform
|
||||
* @param {boolean} [received] Whether these permissions have been received from Discord
|
||||
* @returns {APIApplicationCommandPermissions}
|
||||
* @private
|
||||
*/
|
||||
static transformPermissions(permissions, received) {
|
||||
return {
|
||||
id: permissions.id,
|
||||
permission: permissions.permission,
|
||||
type:
|
||||
typeof permissions.type === 'number' && !received
|
||||
? permissions.type
|
||||
: ApplicationCommandPermissionTypes[permissions.type],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ApplicationCommandPermissionsManager;
|
||||
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* @external APIApplicationCommandPermissions
|
||||
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure}
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const BaseManager = require('./BaseManager');
|
||||
const { Error, TypeError } = require('../errors');
|
||||
const { ApplicationCommandPermissionTypes, APIErrors } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Manages API methods for permissions of Application Commands.
|
||||
* @extends {BaseManager}
|
||||
*/
|
||||
class ApplicationCommandPermissionsManager extends BaseManager {
|
||||
constructor(manager, user) {
|
||||
super(manager.client);
|
||||
|
||||
/**
|
||||
* The manager or command that this manager belongs to
|
||||
* @type {ApplicationCommandManager|ApplicationCommand}
|
||||
* @private
|
||||
*/
|
||||
this.manager = manager;
|
||||
|
||||
/**
|
||||
* The guild that this manager acts on
|
||||
* @type {?Guild}
|
||||
*/
|
||||
this.guild = manager.guild ?? null;
|
||||
|
||||
/**
|
||||
* The id of the guild that this manager acts on
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.guildId = manager.guildId ?? manager.guild?.id ?? null;
|
||||
|
||||
/**
|
||||
* The id of the command this manager acts on
|
||||
* @type {?Snowflake}
|
||||
*/
|
||||
this.commandId = manager.id ?? null;
|
||||
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APIRouter path to the commands
|
||||
* @param {Snowflake} guildId The guild's id to use in the path,
|
||||
* @param {Snowflake} [commandId] The application command's id
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
permissionsPath(guildId, commandId) {
|
||||
return this.client.api.applications(typeof this.user == 'string' ? this.user : this.user.id).guilds(guildId).commands(commandId).permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for setting the permissions of an application command.
|
||||
* @typedef {Object} ApplicationCommandPermissionData
|
||||
* @property {Snowflake} id The role or user's id
|
||||
* @property {ApplicationCommandPermissionType|number} type Whether this permission is for a role or a user
|
||||
* @property {boolean} permission Whether the role or user has the permission to use this command
|
||||
*/
|
||||
|
||||
/**
|
||||
* The object returned when fetching permissions for an application command.
|
||||
* @typedef {Object} ApplicationCommandPermissions
|
||||
* @property {Snowflake} id The role or user's id
|
||||
* @property {ApplicationCommandPermissionType} type Whether this permission is for a role or a user
|
||||
* @property {boolean} permission Whether the role or user has the permission to use this command
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options for managing permissions for one or more Application Commands
|
||||
* <warn>When passing these options to a manager where `guildId` is `null`,
|
||||
* `guild` is a required parameter</warn>
|
||||
* @typedef {Object} BaseApplicationCommandPermissionsOptions
|
||||
* @property {GuildResolvable} [guild] The guild to modify / check permissions for
|
||||
* <warn>Ignored when the manager has a non-null `guildId` property</warn>
|
||||
* @property {ApplicationCommandResolvable} [command] The command to modify / check permissions for
|
||||
* <warn>Ignored when the manager has a non-null `commandId` property</warn>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fetches the permissions for one or multiple commands.
|
||||
* @param {BaseApplicationCommandPermissionsOptions} [options] Options used to fetch permissions
|
||||
* @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
|
||||
* @example
|
||||
* // Fetch permissions for one command
|
||||
* guild.commands.permissions.fetch({ command: '123456789012345678' })
|
||||
* .then(perms => console.log(`Fetched permissions for ${perms.length} users`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Fetch permissions for all commands in a guild
|
||||
* client.application.commands.permissions.fetch({ guild: '123456789012345678' })
|
||||
* .then(perms => console.log(`Fetched permissions for ${perms.size} commands`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetch({ guild, command } = {}) {
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
if (commandId) {
|
||||
const data = await this.permissionsPath(guildId, commandId).get();
|
||||
return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
|
||||
}
|
||||
|
||||
const data = await this.permissionsPath(guildId).get();
|
||||
return data.reduce(
|
||||
(coll, perm) =>
|
||||
coll.set(
|
||||
perm.id,
|
||||
perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
|
||||
),
|
||||
new Collection(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data used for overwriting the permissions for all application commands in a guild.
|
||||
* @typedef {Object} GuildApplicationCommandPermissionData
|
||||
* @property {Snowflake} id The command's id
|
||||
* @property {ApplicationCommandPermissionData[]} permissions The permissions for this command
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options used to set permissions for one or more Application Commands in a guild
|
||||
* <warn>One of `command` AND `permissions`, OR `fullPermissions` is required.
|
||||
* `fullPermissions` is not a valid option when passing to a manager where `commandId` is non-null</warn>
|
||||
* @typedef {BaseApplicationCommandPermissionsOptions} SetApplicationCommandPermissionsOptions
|
||||
* @property {ApplicationCommandPermissionData[]} [permissions] The new permissions for the command
|
||||
* @property {GuildApplicationCommandPermissionData[]} [fullPermissions] The new permissions for all commands
|
||||
* in a guild <warn>When this parameter is set, `permissions` and `command` are ignored</warn>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the permissions for one or more commands.
|
||||
* @param {SetApplicationCommandPermissionsOptions} options Options used to set permissions
|
||||
* @returns {Promise<ApplicationCommandPermissions[]|Collection<Snowflake, ApplicationCommandPermissions[]>>}
|
||||
* @example
|
||||
* // Set the permissions for one command
|
||||
* client.application.commands.permissions.set({ guild: '892455839386304532', command: '123456789012345678',
|
||||
* permissions: [
|
||||
* {
|
||||
* id: '876543210987654321',
|
||||
* type: 'USER',
|
||||
* permission: false,
|
||||
* },
|
||||
* ]})
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Set the permissions for all commands
|
||||
* guild.commands.permissions.set({ fullPermissions: [
|
||||
* {
|
||||
* id: '123456789012345678',
|
||||
* permissions: [{
|
||||
* id: '876543210987654321',
|
||||
* type: 'USER',
|
||||
* permission: false,
|
||||
* }],
|
||||
* },
|
||||
* ]})
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async set({ guild, command, permissions, fullPermissions } = {}) {
|
||||
if(!this.manager.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
|
||||
if (commandId) {
|
||||
if (!Array.isArray(permissions)) {
|
||||
throw new TypeError('INVALID_TYPE', 'permissions', 'Array of ApplicationCommandPermissionData', true);
|
||||
}
|
||||
const data = await this.permissionsPath(guildId, commandId).put({
|
||||
data: { permissions: permissions.map(perm => this.constructor.transformPermissions(perm)) },
|
||||
});
|
||||
return data.permissions.map(perm => this.constructor.transformPermissions(perm, true));
|
||||
}
|
||||
|
||||
if (!Array.isArray(fullPermissions)) {
|
||||
throw new TypeError('INVALID_TYPE', 'fullPermissions', 'Array of GuildApplicationCommandPermissionData', true);
|
||||
}
|
||||
|
||||
const APIPermissions = [];
|
||||
for (const perm of fullPermissions) {
|
||||
if (!Array.isArray(perm.permissions)) throw new TypeError('INVALID_ELEMENT', 'Array', 'fullPermissions', perm);
|
||||
APIPermissions.push({
|
||||
id: perm.id,
|
||||
permissions: perm.permissions.map(p => this.constructor.transformPermissions(p)),
|
||||
});
|
||||
}
|
||||
const data = await this.permissionsPath(guildId).put({
|
||||
data: APIPermissions,
|
||||
});
|
||||
return data.reduce(
|
||||
(coll, perm) =>
|
||||
coll.set(
|
||||
perm.id,
|
||||
perm.permissions.map(p => this.constructor.transformPermissions(p, true)),
|
||||
),
|
||||
new Collection(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to add permissions to a command
|
||||
* <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
|
||||
* @typedef {BaseApplicationCommandPermissionsOptions} AddApplicationCommandPermissionsOptions
|
||||
* @property {ApplicationCommandPermissionData[]} permissions The permissions to add to the command
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add permissions to a command.
|
||||
* @param {AddApplicationCommandPermissionsOptions} options Options used to add permissions
|
||||
* @returns {Promise<ApplicationCommandPermissions[]>}
|
||||
* @example
|
||||
* // Block a role from the command permissions
|
||||
* guild.commands.permissions.add({ command: '123456789012345678', permissions: [
|
||||
* {
|
||||
* id: '876543211234567890',
|
||||
* type: 'ROLE',
|
||||
* permission: false
|
||||
* },
|
||||
* ]})
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async add({ guild, command, permissions }) {
|
||||
if(!this.manager.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
if (!Array.isArray(permissions)) {
|
||||
throw new TypeError('INVALID_TYPE', 'permissions', 'Array of ApplicationCommandPermissionData', true);
|
||||
}
|
||||
|
||||
let existing = [];
|
||||
try {
|
||||
existing = await this.fetch({ guild: guildId, command: commandId });
|
||||
} catch (error) {
|
||||
if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
|
||||
}
|
||||
|
||||
const newPermissions = permissions.slice();
|
||||
for (const perm of existing) {
|
||||
if (!newPermissions.some(x => x.id === perm.id)) {
|
||||
newPermissions.push(perm);
|
||||
}
|
||||
}
|
||||
|
||||
return this.set({ guild: guildId, command: commandId, permissions: newPermissions });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to remove permissions from a command
|
||||
* <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
|
||||
* @typedef {BaseApplicationCommandPermissionsOptions} RemoveApplicationCommandPermissionsOptions
|
||||
* @property {UserResolvable|UserResolvable[]} [users] The user(s) to remove from the command permissions
|
||||
* <warn>One of `users` or `roles` is required</warn>
|
||||
* @property {RoleResolvable|RoleResolvable[]} [roles] The role(s) to remove from the command permissions
|
||||
* <warn>One of `users` or `roles` is required</warn>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Remove permissions from a command.
|
||||
* @param {RemoveApplicationCommandPermissionsOptions} options Options used to remove permissions
|
||||
* @returns {Promise<ApplicationCommandPermissions[]>}
|
||||
* @example
|
||||
* // Remove a user permission from this command
|
||||
* guild.commands.permissions.remove({ command: '123456789012345678', users: '876543210123456789' })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Remove multiple roles from this command
|
||||
* guild.commands.permissions.remove({
|
||||
* command: '123456789012345678', roles: ['876543210123456789', '765432101234567890']
|
||||
* })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async remove({ guild, command, users, roles }) {
|
||||
if(!this.manager.client.user.bot) throw new Error("INVALID_USER_METHOD");
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
|
||||
if (!users && !roles) throw new TypeError('INVALID_TYPE', 'users OR roles', 'Array or Resolvable', true);
|
||||
|
||||
let resolvedIds = [];
|
||||
if (Array.isArray(users)) {
|
||||
users.forEach(user => {
|
||||
const userId = this.client.users.resolveId(user);
|
||||
if (!userId) throw new TypeError('INVALID_ELEMENT', 'Array', 'users', user);
|
||||
resolvedIds.push(userId);
|
||||
});
|
||||
} else if (users) {
|
||||
const userId = this.client.users.resolveId(users);
|
||||
if (!userId) {
|
||||
throw new TypeError('INVALID_TYPE', 'users', 'Array or UserResolvable');
|
||||
}
|
||||
resolvedIds.push(userId);
|
||||
}
|
||||
|
||||
if (Array.isArray(roles)) {
|
||||
roles.forEach(role => {
|
||||
if (typeof role === 'string') {
|
||||
resolvedIds.push(role);
|
||||
return;
|
||||
}
|
||||
if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
|
||||
const roleId = this.guild.roles.resolveId(role);
|
||||
if (!roleId) throw new TypeError('INVALID_ELEMENT', 'Array', 'users', role);
|
||||
resolvedIds.push(roleId);
|
||||
});
|
||||
} else if (roles) {
|
||||
if (typeof roles === 'string') {
|
||||
resolvedIds.push(roles);
|
||||
} else {
|
||||
if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
|
||||
const roleId = this.guild.roles.resolveId(roles);
|
||||
if (!roleId) {
|
||||
throw new TypeError('INVALID_TYPE', 'users', 'Array or RoleResolvable');
|
||||
}
|
||||
resolvedIds.push(roleId);
|
||||
}
|
||||
}
|
||||
|
||||
let existing = [];
|
||||
try {
|
||||
existing = await this.fetch({ guild: guildId, command: commandId });
|
||||
} catch (error) {
|
||||
if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
|
||||
}
|
||||
|
||||
const permissions = existing.filter(perm => !resolvedIds.includes(perm.id));
|
||||
|
||||
return this.set({ guild: guildId, command: commandId, permissions });
|
||||
}
|
||||
|
||||
/**
|
||||
* Options used to check the existence of permissions on a command
|
||||
* <warn>The `command` parameter is not optional when the managers `commandId` is `null`</warn>
|
||||
* @typedef {BaseApplicationCommandPermissionsOptions} HasApplicationCommandPermissionsOptions
|
||||
* @property {UserResolvable|RoleResolvable} permissionId The user or role to check if a permission exists for
|
||||
* on this command.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check whether a permission exists for a user or role
|
||||
* @param {AddApplicationCommandPermissionsOptions} options Options used to check permissions
|
||||
* @returns {Promise<boolean>}
|
||||
* @example
|
||||
* // Check whether a user has permission to use a command
|
||||
* guild.commands.permissions.has({ command: '123456789012345678', permissionId: '876543210123456789' })
|
||||
* .then(console.log)
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async has({ guild, command, permissionId }) {
|
||||
const { guildId, commandId } = this._validateOptions(guild, command);
|
||||
if (!commandId) throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable');
|
||||
|
||||
if (!permissionId) throw new TypeError('INVALID_TYPE', 'permissionId', 'UserResolvable or RoleResolvable');
|
||||
let resolvedId = permissionId;
|
||||
if (typeof permissionId !== 'string') {
|
||||
resolvedId = this.client.users.resolveId(permissionId);
|
||||
if (!resolvedId) {
|
||||
if (!this.guild) throw new Error('GUILD_UNCACHED_ROLE_RESOLVE');
|
||||
resolvedId = this.guild.roles.resolveId(permissionId);
|
||||
}
|
||||
if (!resolvedId) {
|
||||
throw new TypeError('INVALID_TYPE', 'permissionId', 'UserResolvable or RoleResolvable');
|
||||
}
|
||||
}
|
||||
|
||||
let existing = [];
|
||||
try {
|
||||
existing = await this.fetch({ guild: guildId, command: commandId });
|
||||
} catch (error) {
|
||||
if (error.code !== APIErrors.UNKNOWN_APPLICATION_COMMAND_PERMISSIONS) throw error;
|
||||
}
|
||||
|
||||
return existing.some(perm => perm.id === resolvedId);
|
||||
}
|
||||
|
||||
_validateOptions(guild, command) {
|
||||
const guildId = this.guildId ?? this.client.guilds.resolveId(guild);
|
||||
if (!guildId) throw new Error('GLOBAL_COMMAND_PERMISSIONS');
|
||||
let commandId = this.commandId;
|
||||
if (command && !commandId) {
|
||||
commandId = this.manager.resolveId?.(command);
|
||||
if (!commandId && this.guild) {
|
||||
commandId = this.guild.commands.resolveId(command);
|
||||
}
|
||||
commandId ??= this.client.application?.commands.resolveId(command);
|
||||
if (!commandId) {
|
||||
throw new TypeError('INVALID_TYPE', 'command', 'ApplicationCommandResolvable', true);
|
||||
}
|
||||
}
|
||||
return { guildId, commandId };
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an {@link ApplicationCommandPermissionData} object into something that can be used with the API.
|
||||
* @param {ApplicationCommandPermissionData} permissions The permissions to transform
|
||||
* @param {boolean} [received] Whether these permissions have been received from Discord
|
||||
* @returns {APIApplicationCommandPermissions}
|
||||
* @private
|
||||
*/
|
||||
static transformPermissions(permissions, received) {
|
||||
return {
|
||||
id: permissions.id,
|
||||
permission: permissions.permission,
|
||||
type:
|
||||
typeof permissions.type === 'number' && !received
|
||||
? permissions.type
|
||||
: ApplicationCommandPermissionTypes[permissions.type],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ApplicationCommandPermissionsManager;
|
||||
|
||||
/* eslint-disable max-len */
|
||||
/**
|
||||
* @external APIApplicationCommandPermissions
|
||||
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure}
|
||||
*/
|
||||
|
@ -1,75 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
const CachedManager = require('./CachedManager');
|
||||
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 BlockedManager extends CachedManager {
|
||||
constructor(client, iterable) {
|
||||
super(client, User, iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of this manager
|
||||
* @type {Collection<Snowflake, User>}
|
||||
* @name BlockedManager#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
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
async fetch(user, { cache = true, force = false } = {}) {
|
||||
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();
|
||||
return this._add(data, cache);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BlockedManager;
|
||||
'use strict';
|
||||
|
||||
const CachedManager = require('./CachedManager');
|
||||
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 BlockedManager extends CachedManager {
|
||||
constructor(client, iterable) {
|
||||
super(client, User, iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of this manager
|
||||
* @type {Collection<Snowflake, User>}
|
||||
* @name BlockedManager#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
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
async fetch(user, { cache = true, force = false } = {}) {
|
||||
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();
|
||||
return this._add(data, cache);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BlockedManager;
|
||||
|
@ -1,364 +1,367 @@
|
||||
'use strict';
|
||||
const { default: Collection } = require('@discordjs/collection');
|
||||
const { Error, TypeError } = require('../errors/DJSError');
|
||||
const { remove } = require('lodash');
|
||||
const { localeObject, DMScanLevel, stickerAnimationMode } = require('../util/Constants')
|
||||
/**
|
||||
* Manages API methods for users.
|
||||
*/
|
||||
class ClientUserSettingManager {
|
||||
constructor(client, iterable) {
|
||||
this.client = client;
|
||||
// Raw data
|
||||
this.rawSetting = {};
|
||||
// Language
|
||||
this.locale = null;
|
||||
// Setting => ACTIVITY SETTINGS => Activity Status => Display current activity as a status message
|
||||
this.activityDisplay = null;
|
||||
//
|
||||
this.disableDMfromServer = new Collection();
|
||||
// Allow direct messages from server members
|
||||
this.DMfromServerMode = null;
|
||||
//
|
||||
this.displayImage = null;
|
||||
//
|
||||
this.linkedImageDisplay = null;
|
||||
// Setting => APP SETTINGS => Accessibility => Automatically play GIFs when Discord is focused.
|
||||
this.autoplayGIF = null;
|
||||
// Show embeds and preview website links pasted into chat
|
||||
this.previewLink = null;
|
||||
// Setting => APP SETTINGS => Accessibility => Play Animated Emojis
|
||||
this.animatedEmojis = null;
|
||||
// Setting => APP SETTINGS => Accessibility => Text-to-speech => Allow playback
|
||||
this.allowTTS = null;
|
||||
// Setting => APP SETTINGS => Appearance => Message Display => Compact Mode [OK]
|
||||
this.compactMode = null;
|
||||
// Setting => APP SETTINGS => Text & Images => Emoji => Convert Emoticons
|
||||
this.convertEmoticons = null;
|
||||
// SAFE DIRECT MESSAGING
|
||||
this.DMScanLevel = null;
|
||||
// Setting => APP SETTINGS => Appearance => Theme [OK]
|
||||
this.theme = '';
|
||||
//
|
||||
this.developerMode = null;
|
||||
//
|
||||
this.afkTimeout = null;
|
||||
//
|
||||
this.stickerAnimationMode = null;
|
||||
// WHO CAN ADD YOU AS A FRIEND ?
|
||||
this.addFriendFrom = {
|
||||
all: null,
|
||||
mutual_friends: null,
|
||||
mutual_guilds: null,
|
||||
};
|
||||
// Setting => APP SETTINGS => Text & Images => Emoji => Show emoji reactions
|
||||
this.showEmojiReactions = null;
|
||||
// Custom Stauts [It's not working now]
|
||||
this.customStatus = null;
|
||||
// Guild folder and position
|
||||
this.guildMetadata = new Collection();
|
||||
// Todo: add new method from Discum
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {Object} data Raw Data to patch
|
||||
* @extends https://github.com/Merubokkusu/Discord-S.C.U.M/blob/master/discum/user/user.py
|
||||
* @private
|
||||
*/
|
||||
_patch(data) {
|
||||
this.rawSetting = data;
|
||||
if ('locale' in data) {
|
||||
this.locale = localeObject[data.locale];
|
||||
}
|
||||
if ('show_current_game' in data) {
|
||||
this.activityDisplay = data.show_current_game;
|
||||
}
|
||||
if ('default_guilds_restricted' in data) {
|
||||
this.DMfromServerMode = data.default_guilds_restricted;
|
||||
}
|
||||
if ('inline_attachment_media' in data) {
|
||||
this.displayImage = data.inline_attachment_media;
|
||||
}
|
||||
if ('inline_embed_media' in data) {
|
||||
this.linkedImageDisplay = data.inline_embed_media;
|
||||
}
|
||||
if ('gif_auto_play' in data) {
|
||||
this.autoplayGIF = data.gif_auto_play;
|
||||
}
|
||||
if ('render_embeds' in data) {
|
||||
this.previewLink = data.render_embeds;
|
||||
}
|
||||
if ('animate_emoji' in data) {
|
||||
this.animatedEmojis = data.animate_emoji;
|
||||
}
|
||||
if ('enable_tts_command' in data) {
|
||||
this.allowTTS = data.enable_tts_command;
|
||||
}
|
||||
if ('message_display_compact' in data) {
|
||||
this.compactMode = data.message_display_compact;
|
||||
}
|
||||
if ('convert_emoticons' in data) {
|
||||
this.convertEmoticons = data.convert_emoticons;
|
||||
}
|
||||
if ('explicit_content_filter' in data) {
|
||||
this.DMScanLevel = DMScanLevel[data.explicit_content_filter];
|
||||
}
|
||||
if ('theme' in data) {
|
||||
this.theme = data.theme;
|
||||
}
|
||||
if ('developer_mode' in data) {
|
||||
this.developerMode = data.developer_mode;
|
||||
}
|
||||
if ('afk_timeout' in data) {
|
||||
this.afkTimeout = data.afk_timeout * 1000; // second => milisecond
|
||||
}
|
||||
if ('animate_stickers' in data) {
|
||||
this.stickerAnimationMode = stickerAnimationMode[data.animate_stickers];
|
||||
}
|
||||
if ('render_reactions' in data) {
|
||||
this.showEmojiReactions = data.render_reactions;
|
||||
}
|
||||
if ('custom_status' in data) {
|
||||
this.customStatus = data.custom_status || {}; // Thanks PinkDuwc._#3443 reported this issue
|
||||
this.customStatus.status = data.status;
|
||||
}
|
||||
if ('friend_source_flags' in data) {
|
||||
this.addFriendFrom = {
|
||||
all: data.friend_source_flags.all || false,
|
||||
mutual_friends:
|
||||
data.friend_source_flags.all ? true : data.friend_source_flags.mutual_friends,
|
||||
mutual_guilds:
|
||||
data.friend_source_flags.all ? true : data.friend_source_flags.mutual_guilds,
|
||||
};
|
||||
}
|
||||
if ('guild_folders' in data) {
|
||||
const data_ = data.guild_positions.map((guildId, i) => {
|
||||
// Find folder
|
||||
const folderIndex = data.guild_folders.findIndex((obj) =>
|
||||
obj.guild_ids.includes(guildId),
|
||||
);
|
||||
const metadata = {
|
||||
guildId: guildId,
|
||||
guildIndex: i,
|
||||
folderId: data.guild_folders[folderIndex]?.id,
|
||||
folderIndex,
|
||||
folderName: data.guild_folders[folderIndex]?.name,
|
||||
folderColor: data.guild_folders[folderIndex]?.color,
|
||||
folderGuilds: data.guild_folders[folderIndex]?.guild_ids,
|
||||
};
|
||||
return [guildId, metadata];
|
||||
});
|
||||
this.guildMetadata = new Collection(data_);
|
||||
}
|
||||
if ('restricted_guilds' in data) {
|
||||
data.restricted_guilds.map((guildId) => {
|
||||
const guild = this.client.guilds.cache.get(guildId);
|
||||
if (!guild) return;
|
||||
guild.disableDM = true;
|
||||
this.disableDMfromServer.set(guildId, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
async fetch() {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
try {
|
||||
const data = await this.client.api.users('@me').settings.get();
|
||||
this._patch(data);
|
||||
return this;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Edit data
|
||||
* @param {Object} data Data to edit
|
||||
* @private
|
||||
*/
|
||||
async edit(data) {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
try {
|
||||
const res = await this.client.api.users('@me').settings.patch({ data });
|
||||
this._patch(res);
|
||||
return this;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set compact mode
|
||||
* @param {Boolean | null} value Compact mode enable or disable
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
async setDisplayCompactMode(value) {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
if (
|
||||
typeof value !== 'boolean' &&
|
||||
typeof value !== 'null' &&
|
||||
typeof value !== 'undefined'
|
||||
)
|
||||
throw new TypeError(
|
||||
'INVALID_TYPE',
|
||||
'value',
|
||||
'boolean | null | undefined',
|
||||
true,
|
||||
);
|
||||
if (!value) value = !this.compactMode;
|
||||
if (value !== this.compactMode) {
|
||||
await this.edit({ message_display_compact: value });
|
||||
}
|
||||
return this.compactMode;
|
||||
}
|
||||
/**
|
||||
* Discord Theme
|
||||
* @param {null |dark |light} value Theme to set
|
||||
* @returns {theme}
|
||||
*/
|
||||
async setTheme(value) {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
const validValues = ['dark', 'light'];
|
||||
if (
|
||||
typeof value !== 'string' &&
|
||||
typeof value !== 'null' &&
|
||||
typeof value !== 'undefined'
|
||||
)
|
||||
throw new TypeError(
|
||||
'INVALID_TYPE',
|
||||
'value',
|
||||
'string | null | undefined',
|
||||
true,
|
||||
);
|
||||
if (!validValues.includes(value)) {
|
||||
value == validValues[0]
|
||||
? (value = validValues[1])
|
||||
: (value = validValues[0]);
|
||||
}
|
||||
if (value !== this.theme) {
|
||||
await this.edit({ theme: value });
|
||||
}
|
||||
return this.theme;
|
||||
}
|
||||
/**
|
||||
* * Locale Setting, must be one of:
|
||||
* * `DANISH`
|
||||
* * `GERMAN`
|
||||
* * `ENGLISH_UK`
|
||||
* * `ENGLISH_US`
|
||||
* * `SPANISH`
|
||||
* * `FRENCH`
|
||||
* * `CROATIAN`
|
||||
* * `ITALIAN`
|
||||
* * `LITHUANIAN`
|
||||
* * `HUNGARIAN`
|
||||
* * `DUTCH`
|
||||
* * `NORWEGIAN`
|
||||
* * `POLISH`
|
||||
* * `BRAZILIAN_PORTUGUESE`
|
||||
* * `ROMANIA_ROMANIAN`
|
||||
* * `FINNISH`
|
||||
* * `SWEDISH`
|
||||
* * `VIETNAMESE`
|
||||
* * `TURKISH`
|
||||
* * `CZECH`
|
||||
* * `GREEK`
|
||||
* * `BULGARIAN`
|
||||
* * `RUSSIAN`
|
||||
* * `UKRAINIAN`
|
||||
* * `HINDI`
|
||||
* * `THAI`
|
||||
* * `CHINA_CHINESE`
|
||||
* * `JAPANESE`
|
||||
* * `TAIWAN_CHINESE`
|
||||
* * `KOREAN`
|
||||
* @param {string} value
|
||||
* @returns {locale}
|
||||
*/
|
||||
async setLocale(value) {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
if (typeof value !== 'string')
|
||||
throw new TypeError('INVALID_TYPE', 'value', 'string', true);
|
||||
if (!localeObject[value]) throw new Error('INVALID_LOCALE');
|
||||
if (localeObject[value] !== this.locale) {
|
||||
await this.edit({ locale: localeObject[value] });
|
||||
}
|
||||
return this.locale;
|
||||
}
|
||||
// TODO: Guild positions & folders
|
||||
// Change Index in Array [Hidden]
|
||||
/**
|
||||
*
|
||||
* @param {Array} array Array
|
||||
* @param {Number} from Index1
|
||||
* @param {Number} to Index2
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
_move(array, from, to) {
|
||||
array.splice(to, 0, array.splice(from, 1)[0]);
|
||||
return array;
|
||||
}
|
||||
// TODO: Move Guild
|
||||
// folder to folder
|
||||
// folder to home
|
||||
// home to home
|
||||
// home to folder
|
||||
/**
|
||||
* Change Guild Position (from * to Folder or Home)
|
||||
* @param {GuildIDResolve} guildId guild.id
|
||||
* @param {Number} newPosition Guild Position
|
||||
* * **WARNING**: Type = `FOLDER`, newPosition is the guild's index in the Folder.
|
||||
* @param {number} type Move to folder or home
|
||||
* * `FOLDER`: 1
|
||||
* * `HOME`: 2
|
||||
* @param {FolderID} folderId If you want to move to folder
|
||||
* @private
|
||||
*/
|
||||
async guildChangePosition(guildId, newPosition, type, folderId) {
|
||||
// get Guild default position
|
||||
// Escape
|
||||
const oldGuildFolderPosition = this.rawSetting.guild_folders.findIndex(
|
||||
(value) => value.guild_ids.includes(guildId),
|
||||
);
|
||||
const newGuildFolderPosition = this.rawSetting.guild_folders.findIndex(
|
||||
(value) =>
|
||||
value.guild_ids.includes(this.rawSetting.guild_positions[newPosition]),
|
||||
);
|
||||
if (type == 2 || `${type}`.toUpperCase() == 'HOME') {
|
||||
// Delete GuildID from Folder and create new Folder
|
||||
// Check it is folder
|
||||
const folder = this.rawSetting.guild_folders[oldGuildFolderPosition];
|
||||
if (folder.id) {
|
||||
this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids =
|
||||
this.rawSetting.guild_folders[
|
||||
oldGuildFolderPosition
|
||||
].guild_ids.filter((v) => v !== guildId);
|
||||
}
|
||||
this.rawSetting.guild_folders = this._move(
|
||||
this.rawSetting.guild_folders,
|
||||
oldGuildFolderPosition,
|
||||
newGuildFolderPosition,
|
||||
);
|
||||
this.rawSetting.guild_folders[newGuildFolderPosition].id = null;
|
||||
} else if (type == 1 || `${type}`.toUpperCase() == 'FOLDER') {
|
||||
// Delete GuildID from oldFolder
|
||||
this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids =
|
||||
this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids.filter(
|
||||
(v) => v !== guildId,
|
||||
);
|
||||
// Index new Folder
|
||||
const folderIndex = this.rawSetting.guild_folders.findIndex(
|
||||
(value) => value.id == folderId,
|
||||
);
|
||||
const folder = this.rawSetting.guild_folders[folderIndex];
|
||||
folder.guild_ids.push(guildId);
|
||||
folder.guild_ids = [...new Set(folder.guild_ids)];
|
||||
folder.guild_ids = this._move(
|
||||
folder.guild_ids,
|
||||
folder.guild_ids.findIndex((v) => v == guildId),
|
||||
newPosition,
|
||||
);
|
||||
}
|
||||
this.edit({ guild_folders: this.rawSetting.guild_folders });
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ClientUserSettingManager;
|
||||
'use strict';
|
||||
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { default: Collection } = require('@discordjs/collection');
|
||||
const { Error, TypeError } = require('../errors/DJSError');
|
||||
const { remove } = require('lodash');
|
||||
const { localeObject, DMScanLevel, stickerAnimationMode } = require('../util/Constants')
|
||||
/**
|
||||
* Manages API methods for users and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class ClientUserSettingManager extends CachedManager {
|
||||
constructor(client, iterable) {
|
||||
super(client);
|
||||
// Raw data
|
||||
this.rawSetting = {};
|
||||
// Language
|
||||
this.locale = null;
|
||||
// Setting => ACTIVITY SETTINGS => Activity Status => Display current activity as a status message
|
||||
this.activityDisplay = null;
|
||||
//
|
||||
this.disableDMfromServer = new Collection();
|
||||
// Allow direct messages from server members
|
||||
this.DMfromServerMode = null;
|
||||
//
|
||||
this.displayImage = null;
|
||||
//
|
||||
this.linkedImageDisplay = null;
|
||||
// Setting => APP SETTINGS => Accessibility => Automatically play GIFs when Discord is focused.
|
||||
this.autoplayGIF = null;
|
||||
// Show embeds and preview website links pasted into chat
|
||||
this.previewLink = null;
|
||||
// Setting => APP SETTINGS => Accessibility => Play Animated Emojis
|
||||
this.animatedEmojis = null;
|
||||
// Setting => APP SETTINGS => Accessibility => Text-to-speech => Allow playback
|
||||
this.allowTTS = null;
|
||||
// Setting => APP SETTINGS => Appearance => Message Display => Compact Mode [OK]
|
||||
this.compactMode = null;
|
||||
// Setting => APP SETTINGS => Text & Images => Emoji => Convert Emoticons
|
||||
this.convertEmoticons = null;
|
||||
// SAFE DIRECT MESSAGING
|
||||
this.DMScanLevel = null;
|
||||
// Setting => APP SETTINGS => Appearance => Theme [OK]
|
||||
this.theme = '';
|
||||
//
|
||||
this.developerMode = null;
|
||||
//
|
||||
this.afkTimeout = null;
|
||||
//
|
||||
this.stickerAnimationMode = null;
|
||||
// WHO CAN ADD YOU AS A FRIEND ?
|
||||
this.addFriendFrom = {
|
||||
all: null,
|
||||
mutual_friends: null,
|
||||
mutual_guilds: null,
|
||||
};
|
||||
// Setting => APP SETTINGS => Text & Images => Emoji => Show emoji reactions
|
||||
this.showEmojiReactions = null;
|
||||
// Custom Stauts [It's not working now]
|
||||
this.customStatus = null;
|
||||
// Guild folder and position
|
||||
this.guildMetadata = new Collection();
|
||||
// Todo: add new method from Discum
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {Object} data Raw Data to patch
|
||||
* @extends https://github.com/Merubokkusu/Discord-S.C.U.M/blob/master/discum/user/user.py
|
||||
* @private
|
||||
*/
|
||||
_patch(data) {
|
||||
this.rawSetting = data;
|
||||
if ('locale' in data) {
|
||||
this.locale = localeObject[data.locale];
|
||||
}
|
||||
if ('show_current_game' in data) {
|
||||
this.activityDisplay = data.show_current_game;
|
||||
}
|
||||
if ('default_guilds_restricted' in data) {
|
||||
this.DMfromServerMode = data.default_guilds_restricted;
|
||||
}
|
||||
if ('inline_attachment_media' in data) {
|
||||
this.displayImage = data.inline_attachment_media;
|
||||
}
|
||||
if ('inline_embed_media' in data) {
|
||||
this.linkedImageDisplay = data.inline_embed_media;
|
||||
}
|
||||
if ('gif_auto_play' in data) {
|
||||
this.autoplayGIF = data.gif_auto_play;
|
||||
}
|
||||
if ('render_embeds' in data) {
|
||||
this.previewLink = data.render_embeds;
|
||||
}
|
||||
if ('animate_emoji' in data) {
|
||||
this.animatedEmojis = data.animate_emoji;
|
||||
}
|
||||
if ('enable_tts_command' in data) {
|
||||
this.allowTTS = data.enable_tts_command;
|
||||
}
|
||||
if ('message_display_compact' in data) {
|
||||
this.compactMode = data.message_display_compact;
|
||||
}
|
||||
if ('convert_emoticons' in data) {
|
||||
this.convertEmoticons = data.convert_emoticons;
|
||||
}
|
||||
if ('explicit_content_filter' in data) {
|
||||
this.DMScanLevel = DMScanLevel[data.explicit_content_filter];
|
||||
}
|
||||
if ('theme' in data) {
|
||||
this.theme = data.theme;
|
||||
}
|
||||
if ('developer_mode' in data) {
|
||||
this.developerMode = data.developer_mode;
|
||||
}
|
||||
if ('afk_timeout' in data) {
|
||||
this.afkTimeout = data.afk_timeout * 1000; // second => milisecond
|
||||
}
|
||||
if ('animate_stickers' in data) {
|
||||
this.stickerAnimationMode = stickerAnimationMode[data.animate_stickers];
|
||||
}
|
||||
if ('render_reactions' in data) {
|
||||
this.showEmojiReactions = data.render_reactions;
|
||||
}
|
||||
if ('custom_status' in data) {
|
||||
this.customStatus = data.custom_status || {}; // Thanks PinkDuwc._#3443 reported this issue
|
||||
this.customStatus.status = data.status;
|
||||
}
|
||||
if ('friend_source_flags' in data) {
|
||||
this.addFriendFrom = {
|
||||
all: data.friend_source_flags.all || false,
|
||||
mutual_friends:
|
||||
data.friend_source_flags.all ? true : data.friend_source_flags.mutual_friends,
|
||||
mutual_guilds:
|
||||
data.friend_source_flags.all ? true : data.friend_source_flags.mutual_guilds,
|
||||
};
|
||||
}
|
||||
if ('guild_folders' in data) {
|
||||
const data_ = data.guild_positions.map((guildId, i) => {
|
||||
// Find folder
|
||||
const folderIndex = data.guild_folders.findIndex((obj) =>
|
||||
obj.guild_ids.includes(guildId),
|
||||
);
|
||||
const metadata = {
|
||||
guildId: guildId,
|
||||
guildIndex: i,
|
||||
folderId: data.guild_folders[folderIndex]?.id,
|
||||
folderIndex,
|
||||
folderName: data.guild_folders[folderIndex]?.name,
|
||||
folderColor: data.guild_folders[folderIndex]?.color,
|
||||
folderGuilds: data.guild_folders[folderIndex]?.guild_ids,
|
||||
};
|
||||
return [guildId, metadata];
|
||||
});
|
||||
this.guildMetadata = new Collection(data_);
|
||||
}
|
||||
if ('restricted_guilds' in data) {
|
||||
data.restricted_guilds.map((guildId) => {
|
||||
const guild = this.client.guilds.cache.get(guildId);
|
||||
if (!guild) return;
|
||||
guild.disableDM = true;
|
||||
this.disableDMfromServer.set(guildId, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
async fetch() {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
try {
|
||||
const data = await this.client.api.users('@me').settings.get();
|
||||
this._patch(data);
|
||||
return this;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Edit data
|
||||
* @param {Object} data Data to edit
|
||||
* @private
|
||||
*/
|
||||
async edit(data) {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
try {
|
||||
const res = await this.client.api.users('@me').settings.patch({ data });
|
||||
this._patch(res);
|
||||
return this;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set compact mode
|
||||
* @param {Boolean | null} value Compact mode enable or disable
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
async setDisplayCompactMode(value) {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
if (
|
||||
typeof value !== 'boolean' &&
|
||||
typeof value !== 'null' &&
|
||||
typeof value !== 'undefined'
|
||||
)
|
||||
throw new TypeError(
|
||||
'INVALID_TYPE',
|
||||
'value',
|
||||
'boolean | null | undefined',
|
||||
true,
|
||||
);
|
||||
if (!value) value = !this.compactMode;
|
||||
if (value !== this.compactMode) {
|
||||
await this.edit({ message_display_compact: value });
|
||||
}
|
||||
return this.compactMode;
|
||||
}
|
||||
/**
|
||||
* Discord Theme
|
||||
* @param {null |dark |light} value Theme to set
|
||||
* @returns {theme}
|
||||
*/
|
||||
async setTheme(value) {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
const validValues = ['dark', 'light'];
|
||||
if (
|
||||
typeof value !== 'string' &&
|
||||
typeof value !== 'null' &&
|
||||
typeof value !== 'undefined'
|
||||
)
|
||||
throw new TypeError(
|
||||
'INVALID_TYPE',
|
||||
'value',
|
||||
'string | null | undefined',
|
||||
true,
|
||||
);
|
||||
if (!validValues.includes(value)) {
|
||||
value == validValues[0]
|
||||
? (value = validValues[1])
|
||||
: (value = validValues[0]);
|
||||
}
|
||||
if (value !== this.theme) {
|
||||
await this.edit({ theme: value });
|
||||
}
|
||||
return this.theme;
|
||||
}
|
||||
/**
|
||||
* * Locale Setting, must be one of:
|
||||
* * `DANISH`
|
||||
* * `GERMAN`
|
||||
* * `ENGLISH_UK`
|
||||
* * `ENGLISH_US`
|
||||
* * `SPANISH`
|
||||
* * `FRENCH`
|
||||
* * `CROATIAN`
|
||||
* * `ITALIAN`
|
||||
* * `LITHUANIAN`
|
||||
* * `HUNGARIAN`
|
||||
* * `DUTCH`
|
||||
* * `NORWEGIAN`
|
||||
* * `POLISH`
|
||||
* * `BRAZILIAN_PORTUGUESE`
|
||||
* * `ROMANIA_ROMANIAN`
|
||||
* * `FINNISH`
|
||||
* * `SWEDISH`
|
||||
* * `VIETNAMESE`
|
||||
* * `TURKISH`
|
||||
* * `CZECH`
|
||||
* * `GREEK`
|
||||
* * `BULGARIAN`
|
||||
* * `RUSSIAN`
|
||||
* * `UKRAINIAN`
|
||||
* * `HINDI`
|
||||
* * `THAI`
|
||||
* * `CHINA_CHINESE`
|
||||
* * `JAPANESE`
|
||||
* * `TAIWAN_CHINESE`
|
||||
* * `KOREAN`
|
||||
* @param {string} value
|
||||
* @returns {locale}
|
||||
*/
|
||||
async setLocale(value) {
|
||||
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
|
||||
if (typeof value !== 'string')
|
||||
throw new TypeError('INVALID_TYPE', 'value', 'string', true);
|
||||
if (!localeObject[value]) throw new Error('INVALID_LOCALE');
|
||||
if (localeObject[value] !== this.locale) {
|
||||
await this.edit({ locale: localeObject[value] });
|
||||
}
|
||||
return this.locale;
|
||||
}
|
||||
// TODO: Guild positions & folders
|
||||
// Change Index in Array [Hidden]
|
||||
/**
|
||||
*
|
||||
* @param {Array} array Array
|
||||
* @param {Number} from Index1
|
||||
* @param {Number} to Index2
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
_move(array, from, to) {
|
||||
array.splice(to, 0, array.splice(from, 1)[0]);
|
||||
return array;
|
||||
}
|
||||
// TODO: Move Guild
|
||||
// folder to folder
|
||||
// folder to home
|
||||
// home to home
|
||||
// home to folder
|
||||
/**
|
||||
* Change Guild Position (from * to Folder or Home)
|
||||
* @param {GuildIDResolve} guildId guild.id
|
||||
* @param {Number} newPosition Guild Position
|
||||
* * **WARNING**: Type = `FOLDER`, newPosition is the guild's index in the Folder.
|
||||
* @param {number} type Move to folder or home
|
||||
* * `FOLDER`: 1
|
||||
* * `HOME`: 2
|
||||
* @param {FolderID} folderId If you want to move to folder
|
||||
* @private
|
||||
*/
|
||||
async guildChangePosition(guildId, newPosition, type, folderId) {
|
||||
// get Guild default position
|
||||
// Escape
|
||||
const oldGuildFolderPosition = this.rawSetting.guild_folders.findIndex(
|
||||
(value) => value.guild_ids.includes(guildId),
|
||||
);
|
||||
const newGuildFolderPosition = this.rawSetting.guild_folders.findIndex(
|
||||
(value) =>
|
||||
value.guild_ids.includes(this.rawSetting.guild_positions[newPosition]),
|
||||
);
|
||||
if (type == 2 || `${type}`.toUpperCase() == 'HOME') {
|
||||
// Delete GuildID from Folder and create new Folder
|
||||
// Check it is folder
|
||||
const folder = this.rawSetting.guild_folders[oldGuildFolderPosition];
|
||||
if (folder.id) {
|
||||
this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids =
|
||||
this.rawSetting.guild_folders[
|
||||
oldGuildFolderPosition
|
||||
].guild_ids.filter((v) => v !== guildId);
|
||||
}
|
||||
this.rawSetting.guild_folders = this._move(
|
||||
this.rawSetting.guild_folders,
|
||||
oldGuildFolderPosition,
|
||||
newGuildFolderPosition,
|
||||
);
|
||||
this.rawSetting.guild_folders[newGuildFolderPosition].id = null;
|
||||
} else if (type == 1 || `${type}`.toUpperCase() == 'FOLDER') {
|
||||
// Delete GuildID from oldFolder
|
||||
this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids =
|
||||
this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids.filter(
|
||||
(v) => v !== guildId,
|
||||
);
|
||||
// Index new Folder
|
||||
const folderIndex = this.rawSetting.guild_folders.findIndex(
|
||||
(value) => value.id == folderId,
|
||||
);
|
||||
const folder = this.rawSetting.guild_folders[folderIndex];
|
||||
folder.guild_ids.push(guildId);
|
||||
folder.guild_ids = [...new Set(folder.guild_ids)];
|
||||
folder.guild_ids = this._move(
|
||||
folder.guild_ids,
|
||||
folder.guild_ids.findIndex((v) => v == guildId),
|
||||
newPosition,
|
||||
);
|
||||
}
|
||||
this.edit({ guild_folders: this.rawSetting.guild_folders });
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ClientUserSettingManager;
|
||||
|
@ -1,75 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
const CachedManager = require('./CachedManager');
|
||||
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 FriendsManager extends CachedManager {
|
||||
constructor(client, iterable) {
|
||||
super(client, User, iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of this manager
|
||||
* @type {Collection<Snowflake, User>}
|
||||
* @name FriendsManager#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
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
async fetch(user, { cache = true, force = false } = {}) {
|
||||
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();
|
||||
return this._add(data, cache);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FriendsManager;
|
||||
'use strict';
|
||||
|
||||
const CachedManager = require('./CachedManager');
|
||||
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 FriendsManager extends CachedManager {
|
||||
constructor(client, iterable) {
|
||||
super(client, User, iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of this manager
|
||||
* @type {Collection<Snowflake, User>}
|
||||
* @name FriendsManager#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
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns {Promise<User>}
|
||||
*/
|
||||
async fetch(user, { cache = true, force = false } = {}) {
|
||||
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();
|
||||
return this._add(data, cache);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FriendsManager;
|
||||
|
@ -1,247 +1,247 @@
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { TypeError, Error } = require('../errors');
|
||||
const { Message } = require('../structures/Message');
|
||||
const MessagePayload = require('../structures/MessagePayload');
|
||||
const Util = require('../util/Util');
|
||||
const BigNumber = require('bignumber.js');
|
||||
|
||||
/**
|
||||
* Manages API methods for Messages and holds their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class MessageManager extends CachedManager {
|
||||
constructor(channel, iterable) {
|
||||
super(channel.client, Message, iterable);
|
||||
|
||||
/**
|
||||
* The channel that the messages belong to
|
||||
* @type {TextBasedChannels}
|
||||
*/
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of Messages
|
||||
* @type {Collection<Snowflake, Message>}
|
||||
* @name MessageManager#cache
|
||||
*/
|
||||
|
||||
_add(data, cache) {
|
||||
return super._add(data, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameters to pass in when requesting previous messages from a channel. `around`, `before` and
|
||||
* `after` are mutually exclusive. All the parameters are optional.
|
||||
* @typedef {Object} ChannelLogsQueryOptions
|
||||
* @property {number} [limit=50] Number of messages to acquire
|
||||
* @property {Snowflake} [before] The message's id to get the messages that were posted before it
|
||||
* @property {Snowflake} [after] The message's id to get the messages that were posted after it
|
||||
* @property {Snowflake} [around] The message's id to get the messages that were posted around it
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets a message, or messages, from this channel.
|
||||
* <info>The returned Collection does not contain reaction users of the messages if they were not cached.
|
||||
* Those need to be fetched separately in such a case.</info>
|
||||
* @param {Snowflake|ChannelLogsQueryOptions} [message] The id of the message to fetch, or query parameters.
|
||||
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
||||
* @returns {Promise<Message|Collection<Snowflake, Message>>}
|
||||
* @example
|
||||
* // Get message
|
||||
* channel.messages.fetch('99539446449315840')
|
||||
* .then(message => console.log(message.content))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Get messages
|
||||
* channel.messages.fetch({ limit: 10 })
|
||||
* .then(messages => console.log(`Received ${messages.size} messages`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Get messages and filter by user id
|
||||
* channel.messages.fetch()
|
||||
* .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
fetch(message, { cache = true, force = false } = {}) {
|
||||
return typeof message === 'string' ? this._fetchId(message, cache, force) : this._fetchMany(message, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the pinned messages of this channel and returns a collection of them.
|
||||
* <info>The returned Collection does not contain any reaction data of the messages.
|
||||
* Those need to be fetched separately.</info>
|
||||
* @param {boolean} [cache=true] Whether to cache the message(s)
|
||||
* @returns {Promise<Collection<Snowflake, Message>>}
|
||||
* @example
|
||||
* // Get pinned messages
|
||||
* channel.messages.fetchPinned()
|
||||
* .then(messages => console.log(`Received ${messages.size} messages`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetchPinned(cache = true) {
|
||||
const data = await this.client.api.channels[this.channel.id].pins.get();
|
||||
const messages = new Collection();
|
||||
for (const message of data) messages.set(message.id, this._add(message, cache));
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that can be resolved to a Message object. This can be:
|
||||
* * A Message
|
||||
* * A Snowflake
|
||||
* @typedef {Message|Snowflake} MessageResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a {@link MessageResolvable} to a {@link Message} object.
|
||||
* @method resolve
|
||||
* @memberof MessageManager
|
||||
* @instance
|
||||
* @param {MessageResolvable} message The message resolvable to resolve
|
||||
* @returns {?Message}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a {@link MessageResolvable} to a {@link Message} id.
|
||||
* @method resolveId
|
||||
* @memberof MessageManager
|
||||
* @instance
|
||||
* @param {MessageResolvable} message The message resolvable to resolve
|
||||
* @returns {?Snowflake}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Edits a message, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to edit
|
||||
* @param {string|MessageEditOptions|MessagePayload} options The options to edit the message
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async edit(message, options) {
|
||||
const messageId = this.resolveId(message);
|
||||
if (!messageId) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
let messagePayload;
|
||||
if (options instanceof MessagePayload) {
|
||||
messagePayload = await options.resolveData();
|
||||
} else {
|
||||
messagePayload = await MessagePayload.create(
|
||||
message instanceof Message ? message : this,
|
||||
options,
|
||||
).resolveData();
|
||||
}
|
||||
const { data, files } = await messagePayload.resolveFiles();
|
||||
const d = await this.client.api.channels[this.channel.id].messages[messageId].patch({ data, files });
|
||||
|
||||
const existing = this.cache.get(messageId);
|
||||
if (existing) {
|
||||
const clone = existing._clone();
|
||||
clone._patch(d);
|
||||
return clone;
|
||||
}
|
||||
return this._add(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes a message in an announcement channel to all channels following it, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to publish
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async crosspost(message) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
const data = await this.client.api.channels(this.channel.id).messages(message).crosspost.post();
|
||||
return this.cache.get(data.id) ?? this._add(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins a message to the channel's pinned messages, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to pin
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async pin(message) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
await this.client.api.channels(this.channel.id).pins(message).put();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins a message from the channel's pinned messages, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to unpin
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async unpin(message) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
await this.client.api.channels(this.channel.id).pins(message).delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a reaction to a message, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to react to
|
||||
* @param {EmojiIdentifierResolvable} emoji The emoji to react with
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async react(message, emoji) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
emoji = Util.resolvePartialEmoji(emoji);
|
||||
if (!emoji) throw new TypeError('EMOJI_TYPE', 'emoji', 'EmojiIdentifierResolvable');
|
||||
|
||||
const emojiId = emoji.id
|
||||
? `${emoji.animated ? 'a:' : ''}${emoji.name}:${emoji.id}`
|
||||
: encodeURIComponent(emoji.name);
|
||||
|
||||
// eslint-disable-next-line newline-per-chained-call
|
||||
await this.client.api.channels(this.channel.id).messages(message).reactions(emojiId, '@me').put();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a message, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to delete
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async delete(message) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
await this.client.api.channels(this.channel.id).messages(message).delete();
|
||||
}
|
||||
|
||||
async _fetchId(messageId, cache, force) {
|
||||
if (!force) {
|
||||
const existing = this.cache.get(messageId);
|
||||
if (existing && !existing.partial) return existing;
|
||||
}
|
||||
|
||||
// const data = await this.client.api.channels[this.channel.id].messages[messageId].get(); // Discord Block
|
||||
// https://canary.discord.com/api/v9/guilds/809133733591384155/messages/search?channel_id=840225732902518825&max_id=957254525360697375&min_id=957254525360697373
|
||||
const data = (
|
||||
await this.client.api.guilds[this.channel.guild.id].messages.search.get({
|
||||
query: {
|
||||
channel_id: this.channel.id,
|
||||
max_id: new BigNumber.BigNumber(messageId).plus(1).toString(),
|
||||
min_id: new BigNumber.BigNumber(messageId).minus(1).toString(),
|
||||
},
|
||||
})
|
||||
).messages[0]
|
||||
if (data) return this._add(data[0], cache);
|
||||
else throw new Error('MESSAGE_ID_NOT_FOUND');
|
||||
}
|
||||
|
||||
async _fetchMany(options = {}, cache) {
|
||||
const data = await this.client.api.channels[this.channel.id].messages.get({ query: options });
|
||||
const messages = new Collection();
|
||||
for (const message of data) messages.set(message.id, this._add(message, cache));
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageManager;
|
||||
'use strict';
|
||||
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { TypeError, Error } = require('../errors');
|
||||
const { Message } = require('../structures/Message');
|
||||
const MessagePayload = require('../structures/MessagePayload');
|
||||
const Util = require('../util/Util');
|
||||
const BigNumber = require('bignumber.js');
|
||||
|
||||
/**
|
||||
* Manages API methods for Messages and holds their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class MessageManager extends CachedManager {
|
||||
constructor(channel, iterable) {
|
||||
super(channel.client, Message, iterable);
|
||||
|
||||
/**
|
||||
* The channel that the messages belong to
|
||||
* @type {TextBasedChannels}
|
||||
*/
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache of Messages
|
||||
* @type {Collection<Snowflake, Message>}
|
||||
* @name MessageManager#cache
|
||||
*/
|
||||
|
||||
_add(data, cache) {
|
||||
return super._add(data, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameters to pass in when requesting previous messages from a channel. `around`, `before` and
|
||||
* `after` are mutually exclusive. All the parameters are optional.
|
||||
* @typedef {Object} ChannelLogsQueryOptions
|
||||
* @property {number} [limit=50] Number of messages to acquire
|
||||
* @property {Snowflake} [before] The message's id to get the messages that were posted before it
|
||||
* @property {Snowflake} [after] The message's id to get the messages that were posted after it
|
||||
* @property {Snowflake} [around] The message's id to get the messages that were posted around it
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets a message, or messages, from this channel.
|
||||
* <info>The returned Collection does not contain reaction users of the messages if they were not cached.
|
||||
* Those need to be fetched separately in such a case.</info>
|
||||
* @param {Snowflake|ChannelLogsQueryOptions} [message] The id of the message to fetch, or query parameters.
|
||||
* @param {BaseFetchOptions} [options] Additional options for this fetch
|
||||
* @returns {Promise<Message|Collection<Snowflake, Message>>}
|
||||
* @example
|
||||
* // Get message
|
||||
* channel.messages.fetch('99539446449315840')
|
||||
* .then(message => console.log(message.content))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Get messages
|
||||
* channel.messages.fetch({ limit: 10 })
|
||||
* .then(messages => console.log(`Received ${messages.size} messages`))
|
||||
* .catch(console.error);
|
||||
* @example
|
||||
* // Get messages and filter by user id
|
||||
* channel.messages.fetch()
|
||||
* .then(messages => console.log(`${messages.filter(m => m.author.id === '84484653687267328').size} messages`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
fetch(message, { cache = true, force = false } = {}) {
|
||||
return typeof message === 'string' ? this._fetchId(message, cache, force) : this._fetchMany(message, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the pinned messages of this channel and returns a collection of them.
|
||||
* <info>The returned Collection does not contain any reaction data of the messages.
|
||||
* Those need to be fetched separately.</info>
|
||||
* @param {boolean} [cache=true] Whether to cache the message(s)
|
||||
* @returns {Promise<Collection<Snowflake, Message>>}
|
||||
* @example
|
||||
* // Get pinned messages
|
||||
* channel.messages.fetchPinned()
|
||||
* .then(messages => console.log(`Received ${messages.size} messages`))
|
||||
* .catch(console.error);
|
||||
*/
|
||||
async fetchPinned(cache = true) {
|
||||
const data = await this.client.api.channels[this.channel.id].pins.get();
|
||||
const messages = new Collection();
|
||||
for (const message of data) messages.set(message.id, this._add(message, cache));
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that can be resolved to a Message object. This can be:
|
||||
* * A Message
|
||||
* * A Snowflake
|
||||
* @typedef {Message|Snowflake} MessageResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a {@link MessageResolvable} to a {@link Message} object.
|
||||
* @method resolve
|
||||
* @memberof MessageManager
|
||||
* @instance
|
||||
* @param {MessageResolvable} message The message resolvable to resolve
|
||||
* @returns {?Message}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a {@link MessageResolvable} to a {@link Message} id.
|
||||
* @method resolveId
|
||||
* @memberof MessageManager
|
||||
* @instance
|
||||
* @param {MessageResolvable} message The message resolvable to resolve
|
||||
* @returns {?Snowflake}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Edits a message, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to edit
|
||||
* @param {string|MessageEditOptions|MessagePayload} options The options to edit the message
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async edit(message, options) {
|
||||
const messageId = this.resolveId(message);
|
||||
if (!messageId) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
let messagePayload;
|
||||
if (options instanceof MessagePayload) {
|
||||
messagePayload = await options.resolveData();
|
||||
} else {
|
||||
messagePayload = await MessagePayload.create(
|
||||
message instanceof Message ? message : this,
|
||||
options,
|
||||
).resolveData();
|
||||
}
|
||||
const { data, files } = await messagePayload.resolveFiles();
|
||||
const d = await this.client.api.channels[this.channel.id].messages[messageId].patch({ data, files });
|
||||
|
||||
const existing = this.cache.get(messageId);
|
||||
if (existing) {
|
||||
const clone = existing._clone();
|
||||
clone._patch(d);
|
||||
return clone;
|
||||
}
|
||||
return this._add(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes a message in an announcement channel to all channels following it, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to publish
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async crosspost(message) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
const data = await this.client.api.channels(this.channel.id).messages(message).crosspost.post();
|
||||
return this.cache.get(data.id) ?? this._add(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins a message to the channel's pinned messages, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to pin
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async pin(message) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
await this.client.api.channels(this.channel.id).pins(message).put();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins a message from the channel's pinned messages, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to unpin
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async unpin(message) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
await this.client.api.channels(this.channel.id).pins(message).delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a reaction to a message, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to react to
|
||||
* @param {EmojiIdentifierResolvable} emoji The emoji to react with
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async react(message, emoji) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
emoji = Util.resolvePartialEmoji(emoji);
|
||||
if (!emoji) throw new TypeError('EMOJI_TYPE', 'emoji', 'EmojiIdentifierResolvable');
|
||||
|
||||
const emojiId = emoji.id
|
||||
? `${emoji.animated ? 'a:' : ''}${emoji.name}:${emoji.id}`
|
||||
: encodeURIComponent(emoji.name);
|
||||
|
||||
// eslint-disable-next-line newline-per-chained-call
|
||||
await this.client.api.channels(this.channel.id).messages(message).reactions(emojiId, '@me').put();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a message, even if it's not cached.
|
||||
* @param {MessageResolvable} message The message to delete
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async delete(message) {
|
||||
message = this.resolveId(message);
|
||||
if (!message) throw new TypeError('INVALID_TYPE', 'message', 'MessageResolvable');
|
||||
|
||||
await this.client.api.channels(this.channel.id).messages(message).delete();
|
||||
}
|
||||
|
||||
async _fetchId(messageId, cache, force) {
|
||||
if (!force) {
|
||||
const existing = this.cache.get(messageId);
|
||||
if (existing && !existing.partial) return existing;
|
||||
}
|
||||
|
||||
// const data = await this.client.api.channels[this.channel.id].messages[messageId].get(); // Discord Block
|
||||
// https://canary.discord.com/api/v9/guilds/809133733591384155/messages/search?channel_id=840225732902518825&max_id=957254525360697375&min_id=957254525360697373
|
||||
const data = (
|
||||
await this.client.api.guilds[this.channel.guild.id].messages.search.get({
|
||||
query: {
|
||||
channel_id: this.channel.id,
|
||||
max_id: new BigNumber.BigNumber(messageId).plus(1).toString(),
|
||||
min_id: new BigNumber.BigNumber(messageId).minus(1).toString(),
|
||||
},
|
||||
})
|
||||
).messages[0]
|
||||
if (data) return this._add(data[0], cache);
|
||||
else throw new Error('MESSAGE_ID_NOT_FOUND');
|
||||
}
|
||||
|
||||
async _fetchMany(options = {}, cache) {
|
||||
const data = await this.client.api.channels[this.channel.id].messages.get({ query: options });
|
||||
const messages = new Collection();
|
||||
for (const message of data) messages.set(message.id, this._add(message, cache));
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageManager;
|
||||
|
@ -3,14 +3,14 @@
|
||||
const { Collection } = require('@discordjs/collection');
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { Error } = require('../errors');
|
||||
const { User } = require('discord.js-selfbot-v13');
|
||||
const Discord = require("discord.js-selfbot-v13")
|
||||
/**
|
||||
* Manages API methods for users who reacted to a reaction and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class ReactionUserManager extends CachedManager {
|
||||
constructor(reaction, iterable) {
|
||||
super(reaction.client, User, iterable);
|
||||
super(reaction.client, Discord.User, iterable);
|
||||
|
||||
/**
|
||||
* The reaction that this manager belongs to
|
||||
@ -21,7 +21,7 @@ class ReactionUserManager extends CachedManager {
|
||||
|
||||
/**
|
||||
* The cache of this manager
|
||||
* @type {Collection<Snowflake, User>}
|
||||
* @type {Collection<Snowflake, Discord.User>}
|
||||
* @name ReactionUserManager#cache
|
||||
*/
|
||||
|
||||
@ -35,7 +35,7 @@ class ReactionUserManager extends CachedManager {
|
||||
/**
|
||||
* Fetches all the users that gave this reaction. Resolves with a collection of users, mapped by their ids.
|
||||
* @param {FetchReactionUsersOptions} [options] Options for fetching the users
|
||||
* @returns {Promise<Collection<Snowflake, User>>}
|
||||
* @returns {Promise<Collection<Snowflake, Discord.User>>}
|
||||
*/
|
||||
async fetch({ limit = 100, after } = {}) {
|
||||
const message = this.reaction.message;
|
||||
|
Loading…
Reference in New Issue
Block a user