mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-18 20:43:30 +01:00
refactor: move member adding to manager (#6231)
Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com> Co-authored-by: Antonio Román <kyradiscord@gmail.com> Co-authored-by: Sugden <28943913+NotSugden@users.noreply.github.com>
This commit is contained in:
@@ -66,6 +66,56 @@ class GuildMemberManager extends CachedManager {
|
|||||||
return this.cache.has(userResolvable) ? userResolvable : null;
|
return this.cache.has(userResolvable) ? userResolvable : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options used to add a user to a guild using OAuth2.
|
||||||
|
* @typedef {Object} AddGuildMemberOptions
|
||||||
|
* @property {string} accessToken An OAuth2 access token for the user with the `guilds.join` scope granted to the
|
||||||
|
* bot's application
|
||||||
|
* @property {string} [nick] The nickname to give to the member (requires `MANAGE_NICKNAMES`)
|
||||||
|
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] The roles to add to the member
|
||||||
|
* (requires `MANAGE_ROLES`)
|
||||||
|
* @property {boolean} [mute] Whether the member should be muted (requires `MUTE_MEMBERS`)
|
||||||
|
* @property {boolean} [deaf] Whether the member should be deafened (requires `DEAFEN_MEMBERS`)
|
||||||
|
* @property {boolean} [force] Whehter to skip the cache check and call the API directly
|
||||||
|
* @property {boolean} [fetchWhenExisting=true] Whether to fetch the user if not cached and already a member
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a user to the guild using OAuth2. Requires the `CREATE_INSTANT_INVITE` permission.
|
||||||
|
* @param {UserResolvable} user The user to add to the guild
|
||||||
|
* @param {AddGuildMemberOptions} options Options for adding the user to the guild
|
||||||
|
* @returns {Promise<GuildMember|null>}
|
||||||
|
*/
|
||||||
|
async add(user, options) {
|
||||||
|
const userId = this.client.users.resolveId(user);
|
||||||
|
if (!userId) throw new TypeError('INVALID_TYPE', 'user', 'UserResolvable');
|
||||||
|
if (!options.force) {
|
||||||
|
const cachedUser = this.cache.get(userId);
|
||||||
|
if (cachedUser) return cachedUser;
|
||||||
|
}
|
||||||
|
const resolvedOptions = {
|
||||||
|
access_token: options.accessToken,
|
||||||
|
nick: options.nick,
|
||||||
|
mute: options.mute,
|
||||||
|
deaf: options.deaf,
|
||||||
|
};
|
||||||
|
if (options.roles) {
|
||||||
|
if (!Array.isArray(options.roles) && !(options.roles instanceof Collection)) {
|
||||||
|
throw new TypeError('INVALID_TYPE', 'options.roles', 'Array or Collection of Roles or Snowflakes', true);
|
||||||
|
}
|
||||||
|
const resolvedRoles = [];
|
||||||
|
for (const role of options.roles.values()) {
|
||||||
|
const resolvedRole = this.guild.roles.resolveId(role);
|
||||||
|
if (!resolvedRole) throw new TypeError('INVALID_ELEMENT', 'Array or Collection', 'options.roles', role);
|
||||||
|
resolvedRoles.push(resolvedRole);
|
||||||
|
}
|
||||||
|
resolvedOptions.roles = resolvedRoles;
|
||||||
|
}
|
||||||
|
const data = await this.client.api.guilds(this.guild.id).members(userId).put({ data: resolvedOptions });
|
||||||
|
// Data is an empty buffer if the member is already part of the guild.
|
||||||
|
return data instanceof Buffer ? (options.fetchWhenExisting === false ? null : this.fetch(userId)) : this._add(data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options used to fetch a single member from a guild.
|
* Options used to fetch a single member from a guild.
|
||||||
* @typedef {BaseFetchOptions} FetchMemberOptions
|
* @typedef {BaseFetchOptions} FetchMemberOptions
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const GuildTemplate = require('./GuildTemplate');
|
|||||||
const Integration = require('./Integration');
|
const Integration = require('./Integration');
|
||||||
const Webhook = require('./Webhook');
|
const Webhook = require('./Webhook');
|
||||||
const WelcomeScreen = require('./WelcomeScreen');
|
const WelcomeScreen = require('./WelcomeScreen');
|
||||||
const { Error, TypeError } = require('../errors');
|
const { Error } = require('../errors');
|
||||||
const GuildApplicationCommandManager = require('../managers/GuildApplicationCommandManager');
|
const GuildApplicationCommandManager = require('../managers/GuildApplicationCommandManager');
|
||||||
const GuildBanManager = require('../managers/GuildBanManager');
|
const GuildBanManager = require('../managers/GuildBanManager');
|
||||||
const GuildChannelManager = require('../managers/GuildChannelManager');
|
const GuildChannelManager = require('../managers/GuildChannelManager');
|
||||||
@@ -730,46 +730,6 @@ class Guild extends AnonymousGuild {
|
|||||||
.then(data => GuildAuditLogs.build(this, data));
|
.then(data => GuildAuditLogs.build(this, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Options used to add a user to a guild using OAuth2.
|
|
||||||
* @typedef {Object} AddGuildMemberOptions
|
|
||||||
* @property {string} accessToken An OAuth2 access token for the user with the `guilds.join` scope granted to the
|
|
||||||
* bot's application
|
|
||||||
* @property {string} [nick] The nickname to give to the member (requires `MANAGE_NICKNAMES`)
|
|
||||||
* @property {Collection<Snowflake, Role>|RoleResolvable[]} [roles] The roles to add to the member
|
|
||||||
* (requires `MANAGE_ROLES`)
|
|
||||||
* @property {boolean} [mute] Whether the member should be muted (requires `MUTE_MEMBERS`)
|
|
||||||
* @property {boolean} [deaf] Whether the member should be deafened (requires `DEAFEN_MEMBERS`)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a user to the guild using OAuth2. Requires the `CREATE_INSTANT_INVITE` permission.
|
|
||||||
* @param {UserResolvable} user The user to add to the guild
|
|
||||||
* @param {AddGuildMemberOptions} options Options for adding the user to the guild
|
|
||||||
* @returns {Promise<GuildMember>}
|
|
||||||
*/
|
|
||||||
async addMember(user, options) {
|
|
||||||
user = this.client.users.resolveId(user);
|
|
||||||
if (!user) throw new TypeError('INVALID_TYPE', 'user', 'UserResolvable');
|
|
||||||
if (this.members.cache.has(user)) return this.members.cache.get(user);
|
|
||||||
options.access_token = options.accessToken;
|
|
||||||
if (options.roles) {
|
|
||||||
if (!Array.isArray(options.roles) && !(options.roles instanceof Collection)) {
|
|
||||||
throw new TypeError('INVALID_TYPE', 'options.roles', 'Array or Collection of Roles or Snowflakes', true);
|
|
||||||
}
|
|
||||||
const resolvedRoles = [];
|
|
||||||
for (const role of options.roles.values()) {
|
|
||||||
const resolvedRole = this.roles.resolveId(role);
|
|
||||||
if (!role) throw new TypeError('INVALID_ELEMENT', 'Array or Collection', 'options.roles', role);
|
|
||||||
resolvedRoles.push(resolvedRole);
|
|
||||||
}
|
|
||||||
options.roles = resolvedRoles;
|
|
||||||
}
|
|
||||||
const data = await this.client.api.guilds(this.id).members(user).put({ data: options });
|
|
||||||
// Data is an empty buffer if the member is already part of the guild.
|
|
||||||
return data instanceof Buffer ? this.members.fetch(user) : this.members._add(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data for editing a guild.
|
* The data for editing a guild.
|
||||||
* @typedef {Object} GuildEditData
|
* @typedef {Object} GuildEditData
|
||||||
|
|||||||
8
typings/index.d.ts
vendored
8
typings/index.d.ts
vendored
@@ -573,7 +573,6 @@ export class Guild extends AnonymousGuild {
|
|||||||
public readonly widgetChannel: TextChannel | null;
|
public readonly widgetChannel: TextChannel | null;
|
||||||
public widgetChannelId: Snowflake | null;
|
public widgetChannelId: Snowflake | null;
|
||||||
public widgetEnabled: boolean | null;
|
public widgetEnabled: boolean | null;
|
||||||
public addMember(user: UserResolvable, options: AddGuildMemberOptions): Promise<GuildMember>;
|
|
||||||
public createTemplate(name: string, description?: string): Promise<GuildTemplate>;
|
public createTemplate(name: string, description?: string): Promise<GuildTemplate>;
|
||||||
public delete(): Promise<Guild>;
|
public delete(): Promise<Guild>;
|
||||||
public discoverySplashURL(options?: StaticImageURLOptions): string | null;
|
public discoverySplashURL(options?: StaticImageURLOptions): string | null;
|
||||||
@@ -2341,6 +2340,11 @@ export class GuildManager extends CachedManager<Snowflake, Guild, GuildResolvabl
|
|||||||
export class GuildMemberManager extends CachedManager<Snowflake, GuildMember, GuildMemberResolvable> {
|
export class GuildMemberManager extends CachedManager<Snowflake, GuildMember, GuildMemberResolvable> {
|
||||||
public constructor(guild: Guild, iterable?: Iterable<unknown>);
|
public constructor(guild: Guild, iterable?: Iterable<unknown>);
|
||||||
public guild: Guild;
|
public guild: Guild;
|
||||||
|
public add(
|
||||||
|
user: UserResolvable,
|
||||||
|
options: AddGuildMemberOptions & { fetchWhenExisting: false },
|
||||||
|
): Promise<GuildMember | null>;
|
||||||
|
public add(user: UserResolvable, options: AddGuildMemberOptions): Promise<GuildMember>;
|
||||||
public ban(user: UserResolvable, options?: BanOptions): Promise<GuildMember | User | Snowflake>;
|
public ban(user: UserResolvable, options?: BanOptions): Promise<GuildMember | User | Snowflake>;
|
||||||
public edit(user: UserResolvable, data: GuildMemberEditData, reason?: string): Promise<void>;
|
public edit(user: UserResolvable, data: GuildMemberEditData, reason?: string): Promise<void>;
|
||||||
public fetch(
|
public fetch(
|
||||||
@@ -2609,6 +2613,8 @@ export interface AddGuildMemberOptions {
|
|||||||
roles?: Collection<Snowflake, Role> | RoleResolvable[];
|
roles?: Collection<Snowflake, Role> | RoleResolvable[];
|
||||||
mute?: boolean;
|
mute?: boolean;
|
||||||
deaf?: boolean;
|
deaf?: boolean;
|
||||||
|
force?: boolean;
|
||||||
|
fetchWhenExisting?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AllowedImageFormat = 'webp' | 'png' | 'jpg' | 'jpeg' | 'gif';
|
export type AllowedImageFormat = 'webp' | 'png' | 'jpg' | 'jpeg' | 'gif';
|
||||||
|
|||||||
@@ -404,6 +404,9 @@ client.on('ready', async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This is to check that stuff is the right type
|
||||||
|
declare const assertIsPromiseMember: (m: Promise<GuildMember>) => void;
|
||||||
|
|
||||||
client.on('guildCreate', g => {
|
client.on('guildCreate', g => {
|
||||||
const channel = g.channels.cache.random();
|
const channel = g.channels.cache.random();
|
||||||
if (!channel) return;
|
if (!channel) return;
|
||||||
@@ -411,6 +414,32 @@ client.on('guildCreate', g => {
|
|||||||
channel.setName('foo').then(updatedChannel => {
|
channel.setName('foo').then(updatedChannel => {
|
||||||
console.log(`New channel name: ${updatedChannel.name}`);
|
console.log(`New channel name: ${updatedChannel.name}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// @ts-expect-error no options
|
||||||
|
assertIsPromiseMember(g.members.add(testUserId));
|
||||||
|
|
||||||
|
// @ts-expect-error no access token
|
||||||
|
assertIsPromiseMember(g.members.add(testUserId, {}));
|
||||||
|
|
||||||
|
// @ts-expect-error invalid role resolvable
|
||||||
|
assertIsPromiseMember(g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', roles: [g.roles.cache] }));
|
||||||
|
|
||||||
|
assertType<Promise<GuildMember | null>>(
|
||||||
|
g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', fetchWhenExisting: false }),
|
||||||
|
);
|
||||||
|
|
||||||
|
assertIsPromiseMember(g.members.add(testUserId, { accessToken: 'totallyRealAccessToken' }));
|
||||||
|
|
||||||
|
assertIsPromiseMember(
|
||||||
|
g.members.add(testUserId, {
|
||||||
|
accessToken: 'totallyRealAccessToken',
|
||||||
|
mute: true,
|
||||||
|
deaf: false,
|
||||||
|
roles: [g.roles.cache.first()!],
|
||||||
|
force: true,
|
||||||
|
fetchWhenExisting: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('messageReactionRemoveAll', async message => {
|
client.on('messageReactionRemoveAll', async message => {
|
||||||
|
|||||||
Reference in New Issue
Block a user