Skip to content

Commit 9b821e5

Browse files
authored
feat(GuildMemberManager): Add new modify self fields (#11112)
* feat(GuildMemberManager): Add new modify self fields (#11089) * fix: use correct route * fix: add deprecation * fix: rewrite message
1 parent a041723 commit 9b821e5

File tree

3 files changed

+71
-7
lines changed

3 files changed

+71
-7
lines changed

packages/discord.js/src/managers/GuildMemberManager.js

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
const { process } = require('node:process');
34
const { setTimeout, clearTimeout } = require('node:timers');
45
const { Collection } = require('@discordjs/collection');
56
const { makeURLSearchParams } = require('@discordjs/rest');
@@ -10,10 +11,13 @@ const { DiscordjsError, DiscordjsTypeError, DiscordjsRangeError, ErrorCodes } =
1011
const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel');
1112
const { GuildMember } = require('../structures/GuildMember');
1213
const { Role } = require('../structures/Role');
14+
const { resolveImage } = require('../util/DataResolver');
1315
const Events = require('../util/Events');
1416
const { GuildMemberFlagsBitField } = require('../util/GuildMemberFlagsBitField');
1517
const Partials = require('../util/Partials');
1618

19+
let deprecatedEmittedForEditSoleNickname = false;
20+
1721
/**
1822
* Manages API methods for GuildMembers and stores their cache.
1923
* @extends {CachedManager}
@@ -336,8 +340,8 @@ class GuildMemberManager extends CachedManager {
336340
*/
337341

338342
/**
339-
* Edits a member of the guild.
340-
* <info>The user must be a member of the guild</info>
343+
* Edits a member of a guild.
344+
*
341345
* @param {UserResolvable} user The member to edit
342346
* @param {GuildMemberEditOptions} options The options to provide
343347
* @returns {Promise<GuildMember>}
@@ -372,20 +376,69 @@ class GuildMemberManager extends CachedManager {
372376
}
373377

374378
let endpoint;
379+
375380
if (id === this.client.user.id) {
376381
const keys = Object.keys(options);
377-
if (keys.length === 1 && keys[0] === 'nick') endpoint = Routes.guildMember(this.guild.id);
378-
else endpoint = Routes.guildMember(this.guild.id, id);
379-
} else {
380-
endpoint = Routes.guildMember(this.guild.id, id);
382+
383+
if (keys.length === 1 && keys[0] === 'nick') {
384+
// For modifying the current application's nickname only, we use the /guilds/{guild.id}/members/@me endpoint.
385+
// This endpoint only requires the CHANGE_NICKNAME permission.
386+
// The other endpoint would require the MANAGE_NICKNAMES permission.
387+
// In v15, this will be split out, so emit a deprecation.
388+
endpoint = Routes.guildMember(this.guild.id, '@me');
389+
390+
if (!deprecatedEmittedForEditSoleNickname) {
391+
process.emitWarning(
392+
// eslint-disable-next-line max-len
393+
"You should use GuildMemberManager#editMe() when changing your nickname. Due to Discord's API changes, GuildMemberManager#edit() will end up requiring MANAGE_NICKNAMES in v15.",
394+
'DeprecationWarning',
395+
);
396+
397+
deprecatedEmittedForEditSoleNickname = true;
398+
}
399+
}
381400
}
401+
402+
endpoint ??= Routes.guildMember(this.guild.id, id);
382403
const d = await this.client.rest.patch(endpoint, { body: options, reason });
383404

384405
const clone = this.cache.get(id)?._clone();
385406
clone?._patch(d);
386407
return clone ?? this._add(d, false);
387408
}
388409

410+
/**
411+
* The data for editing the current application's guild member.
412+
*
413+
* @typedef {Object} GuildMemberEditMeOptions
414+
* @property {?string} [nick] The nickname to set
415+
* @property {?(BufferResolvable|Base64Resolvable)} [banner] The banner to set
416+
* @property {?(BufferResolvable|Base64Resolvable)} [avatar] The avatar to set
417+
* @property {?string} [bio] The bio to set
418+
* @property {string} [reason] The reason to use
419+
*/
420+
421+
/**
422+
* Edits the current application's guild member in a guild.
423+
*
424+
* @param {GuildMemberEditMeOptions} options The options to provide
425+
* @returns {Promise<GuildMember>}
426+
*/
427+
async editMe({ reason, ...options }) {
428+
const data = await this.client.rest.patch(Routes.guildMember(this.guild.id, '@me'), {
429+
body: {
430+
...options,
431+
banner: options.banner && (await resolveImage(options.banner)),
432+
avatar: options.avatar && (await resolveImage(options.avatar)),
433+
},
434+
reason,
435+
});
436+
437+
const clone = this.me?._clone();
438+
clone?._patch(data);
439+
return clone ?? this._add(data, false);
440+
}
441+
389442
/**
390443
* Options used for pruning guild members.
391444
* <info>It's recommended to set {@link GuildPruneMembersOptions#count options.count}

packages/discord.js/src/structures/GuildMember.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,9 @@ class GuildMember extends Base {
422422
* .catch(console.error);
423423
*/
424424
setNickname(nick, reason) {
425-
return this.edit({ nick, reason });
425+
return this.user.id === this.client.user.id
426+
? this.guild.members.editMe({ nick, reason })
427+
: this.edit({ nick, reason });
426428
}
427429

428430
/**

packages/discord.js/typings/index.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5017,6 +5017,7 @@ export class GuildMemberManager extends CachedManager<Snowflake, GuildMember, Gu
50175017
options?: BulkBanOptions,
50185018
): Promise<BulkBanResult>;
50195019
public edit(user: UserResolvable, options: GuildMemberEditOptions): Promise<GuildMember>;
5020+
public editMe(options: GuildMemberEditMeOptions): Promise<GuildMember>;
50205021
public fetch(
50215022
options: UserResolvable | FetchMemberOptions | (FetchMembersOptions & { user: UserResolvable }),
50225023
): Promise<GuildMember>;
@@ -6875,6 +6876,14 @@ export interface GuildMemberEditOptions {
68756876

68766877
export type GuildMemberResolvable = GuildMember | UserResolvable;
68776878

6879+
export interface GuildMemberEditMeOptions {
6880+
avatar?: Base64Resolvable | BufferResolvable | null;
6881+
banner?: Base64Resolvable | BufferResolvable | null;
6882+
bio?: string | null;
6883+
nick?: string | null;
6884+
reason?: string;
6885+
}
6886+
68786887
export type GuildResolvable = Guild | NonThreadGuildBasedChannel | GuildMember | GuildEmoji | Invite | Role | Snowflake;
68796888

68806889
export interface GuildPruneMembersOptions {

0 commit comments

Comments
 (0)