From de5fe927a35e145bd60afa702e5fa5d614b7a0c9 Mon Sep 17 00:00:00 2001
From: March 7th <71698422+aiko-chan-ai@users.noreply.github.com>
Date: Tue, 9 Aug 2022 10:42:30 +0700
Subject: [PATCH] fix(User): Profile data (API) change
- Add GuildMember bio, banner, ...
---
src/structures/GuildMember.js | 44 +++++++++++++++++++++++++++++++++++
src/structures/User.js | 43 +++++++++++++++++++++++++++++-----
src/util/Constants.js | 4 ++++
typings/index.d.ts | 2 +-
4 files changed, 86 insertions(+), 7 deletions(-)
diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js
index 57cd041..0db6cc9 100644
--- a/src/structures/GuildMember.js
+++ b/src/structures/GuildMember.js
@@ -97,6 +97,33 @@ class GuildMember extends Base {
}
}
+ _ProfilePatch(data) {
+ if ('accent_color' in data) {
+ /**
+ * The member's accent color
+ * The user must be force fetched for this property to be present or be updated
+ * @type {?number}
+ */
+ this.accentColor = data.accent_color;
+ }
+ if ('banner' in data) {
+ /**
+ * The member's banner hash
+ * The user must be force fetched for this property to be present or be updated
+ * @type {?string}
+ */
+ this.banner = data.banner;
+ }
+ if ('bio' in data) {
+ /**
+ * The member's biography (About me)
+ * The user must be force fetched for this property to be present or be updated
+ * @type {?string}
+ */
+ this.bio = data.bio;
+ }
+ }
+
_clone() {
const clone = super._clone();
clone._roles = this._roles.slice();
@@ -170,6 +197,21 @@ class GuildMember extends Base {
return this.client.rest.cdn.GuildMemberAvatar(this.guild.id, this.id, this.avatar, format, size, dynamic);
}
+ /**
+ * A link to the user's banner.
+ * This method will throw an error if called before the user is force fetched Profile.
+ * See {@link GuildMember#banner} for more info
+ * @param {ImageURLOptions} [options={}] Options for the Image URL
+ * @returns {?string}
+ */
+ bannerURL({ format, size, dynamic } = {}) {
+ if (typeof this.banner === 'undefined') {
+ throw new Error('USER_BANNER_NOT_FETCHED');
+ }
+ if (!this.banner) return null;
+ return this.client.rest.cdn.GuildMemberBanner(this.guild.id, this.id, this.banner, format, size, dynamic);
+ }
+
/**
* A link to the member's guild avatar if they have one.
* Otherwise, a link to their {@link User#displayAvatarURL} will be returned.
@@ -489,6 +531,8 @@ class GuildMember extends Base {
this.joinedTimestamp === member.joinedTimestamp &&
this.nickname === member.nickname &&
this.avatar === member.avatar &&
+ this.accentColor === member.accentColor &&
+ this.bio === member.bio &&
this.pending === member.pending &&
this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp &&
(this._roles === member._roles ||
diff --git a/src/structures/User.js b/src/structures/User.js
index aa74261..9786d5a 100644
--- a/src/structures/User.js
+++ b/src/structures/User.js
@@ -6,7 +6,7 @@ const ClientApplication = require('./ClientApplication');
const VoiceState = require('./VoiceState');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { Error } = require('../errors');
-const { RelationshipTypes } = require('../util/Constants');
+const { RelationshipTypes, NitroType } = require('../util/Constants');
const SnowflakeUtil = require('../util/SnowflakeUtil');
const UserFlags = require('../util/UserFlags');
@@ -41,11 +41,13 @@ class User extends Base {
/**
* Accounts connected to this user
+ * The user must be force fetched for this property to be present or be updated
* @type {?ConnectionAccount[]}
*/
this.connectedAccounts = [];
/**
* Time that User has nitro (Unix Timestamp)
+ * The user must be force fetched for this property to be present or be updated
* @type {?number}
* @readonly
*/
@@ -58,12 +60,14 @@ class User extends Base {
this.premiumGuildSince = null;
/**
* About me (User)
+ * The user must be force fetched for this property to be present or be updated
* @type {?string}
* @readonly
*/
this.bio = null;
/**
* This user is on the same servers as Client User
+ * The user must be force fetched for this property to be present or be updated
* @type {Collection}
* @readonly
*/
@@ -216,8 +220,23 @@ class User extends Base {
this.premiumGuildSince = date.getTime();
}
- if ('bio' in data.user) {
- this.bio = data.user.bio;
+ if ('bio' in data.user_profile || 'bio' in data.user) {
+ this.bio = data.user_profile || data.user.bio;
+ }
+
+ if ('premium_type' in data) {
+ const nitro = NitroType[data.premium_type];
+ /**
+ * Nitro type of the user.
+ * @type {NitroType}
+ */
+ this.nitroType = nitro ?? `UNKNOWN_${data.premium_type}`;
+ }
+
+ if ('guild_member_profile' in data && 'guild_member' in data) {
+ const guild = this.client.guilds.cache.get(data.guild_member_profile.guild_id);
+ const member = guild?.members._add(data.guild_member);
+ member._ProfilePatch(data.guild_member_profile);
}
this.mutualGuilds = new Collection(data.mutual_guilds.map(obj => [obj.id, obj]));
@@ -226,11 +245,22 @@ class User extends Base {
/**
* Get profile from Discord, if client is in a server with the target.
* @type {User}
+ * @param {Snowflake | null} guildId The guild id to get the profile from
* @returns {Promise}
*/
- async getProfile() {
+ async getProfile(guildId) {
if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
- const data = await this.client.api.users(this.id).profile.get();
+ const query = guildId
+ ? {
+ with_mutual_guilds: true,
+ guild_id: guildId,
+ }
+ : {
+ with_mutual_guilds: true,
+ };
+ const data = await this.client.api.users(this.id).profile.get({
+ query,
+ });
this._ProfilePatch(data);
return this;
}
@@ -436,7 +466,8 @@ class User extends Base {
this.avatar === user.avatar &&
this.flags?.bitfield === user.flags?.bitfield &&
this.banner === user.banner &&
- this.accentColor === user.accentColor
+ this.accentColor === user.accentColor &&
+ this.bio === user.bio
);
}
diff --git a/src/util/Constants.js b/src/util/Constants.js
index 792468f..e16d74f 100644
--- a/src/util/Constants.js
+++ b/src/util/Constants.js
@@ -169,6 +169,10 @@ exports.Endpoints = {
if (dynamic && hash.startsWith('a_')) format = 'gif';
return makeImageUrl(`${root}/guilds/${guildId}/users/${memberId}/avatars/${hash}`, { format, size });
},
+ GuildMemberBanner: (guildId, memberId, hash, format = 'webp', size, dynamic = false) => {
+ if (dynamic && hash.startsWith('a_')) format = 'gif';
+ return makeImageUrl(`${root}/guilds/${guildId}/users/${memberId}/banners/${hash}`, { format, size });
+ },
Banner: (id, hash, format, size, dynamic = false) => {
if (dynamic && hash.startsWith('a_')) format = 'gif';
return makeImageUrl(`${root}/banners/${id}/${hash}`, { format, size });
diff --git a/typings/index.d.ts b/typings/index.d.ts
index 07e462c..bf60474 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -2938,7 +2938,7 @@ export class User extends PartialTextBasedChannel(Base) {
public unFriend(): Promise;
public unBlock(): Promise;
public setNote(note?: any): Promise;
- public getProfile(): Promise;
+ public getProfile(guildId?: Snowflake): Promise;
public toString(): UserMention;
public ring(): Promise;
}