Skip to content

Commit 9ff0482

Browse files
feat: support user guilds (#10962)
* feat: support user guilds * chore: add cdn test * chore: suggested changes * refactor: move to user primary guild to its own class * docs: update description of `badgeHash` parameter * chore: export UserPrimaryGuild * refactor: revert to no `UserPrimaryGuild` * fix: use key in data * fix: both `in` and is truthy check * docs: remove `-` Co-authored-by: Jiralite <[email protected]> --------- Co-authored-by: Jiralite <[email protected]>
1 parent d03cacb commit 9ff0482

File tree

4 files changed

+95
-20
lines changed

4 files changed

+95
-20
lines changed

packages/discord.js/src/structures/User.js

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -139,18 +139,22 @@ class User extends Base {
139139
* @property {Snowflake} skuId The id of the avatar decoration's SKU
140140
*/
141141

142-
if (data.avatar_decoration_data) {
143-
/**
144-
* The user avatar decoration's data
145-
*
146-
* @type {?AvatarDecorationData}
147-
*/
148-
this.avatarDecorationData = {
149-
asset: data.avatar_decoration_data.asset,
150-
skuId: data.avatar_decoration_data.sku_id,
151-
};
142+
if ('avatar_decoration_data' in data) {
143+
if (data.avatar_decoration_data) {
144+
/**
145+
* The user avatar decoration's data
146+
*
147+
* @type {?AvatarDecorationData}
148+
*/
149+
this.avatarDecorationData = {
150+
asset: data.avatar_decoration_data.asset,
151+
skuId: data.avatar_decoration_data.sku_id,
152+
};
153+
} else {
154+
this.avatarDecorationData = null;
155+
}
152156
} else {
153-
this.avatarDecorationData = null;
157+
this.avatarDecorationData ??= null;
154158
}
155159

156160
/**
@@ -176,6 +180,34 @@ class User extends Base {
176180
} else {
177181
this.collectibles = null;
178182
}
183+
184+
/**
185+
* @typedef {Object} UserPrimaryGuild
186+
* @property {?Snowflake} identityGuildId The id of the user's primary guild
187+
* @property {?boolean} identityEnabled Whether the user is displaying the primary guild's tag
188+
* @property {?string} tag The user's guild tag. Limited to 4 characters
189+
* @property {?string} badge The guild tag badge hash
190+
*/
191+
192+
if ('primary_guild' in data) {
193+
if (data.primary_guild) {
194+
/**
195+
* The primary guild of the user
196+
*
197+
* @type {?UserPrimaryGuild}
198+
*/
199+
this.primaryGuild = {
200+
identityGuildId: data.primary_guild.identity_guild_id,
201+
identityEnabled: data.primary_guild.identity_enabled,
202+
tag: data.primary_guild.tag,
203+
badge: data.primary_guild.badge,
204+
};
205+
} else {
206+
this.primaryGuild = null;
207+
}
208+
} else {
209+
this.primaryGuild ??= null;
210+
}
179211
}
180212

181213
/**
@@ -271,6 +303,18 @@ class User extends Base {
271303
return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options);
272304
}
273305

306+
/**
307+
* A link to the user's guild tag badge.
308+
*
309+
* @param {ImageURLOptions} [options={}] Options for the image URL
310+
* @returns {?string}
311+
*/
312+
guildTagBadgeURL(options = {}) {
313+
return this.primaryGuild?.badge
314+
? this.client.rest.cdn.guildTagBadge(this.primaryGuild.identityGuildId, this.primaryGuild.badge, options)
315+
: null;
316+
}
317+
274318
/**
275319
* The tag of this user
276320
* <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)
@@ -367,7 +411,11 @@ class User extends Base {
367411
this.collectibles?.nameplate?.skuId === user.collectibles?.nameplate?.skuId &&
368412
this.collectibles?.nameplate?.asset === user.collectibles?.nameplate?.asset &&
369413
this.collectibles?.nameplate?.label === user.collectibles?.nameplate?.label &&
370-
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette
414+
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette &&
415+
this.primaryGuild?.identityGuildId === user.primaryGuild?.identityGuildId &&
416+
this.primaryGuild?.identityEnabled === user.primaryGuild?.identityEnabled &&
417+
this.primaryGuild?.tag === user.primaryGuild?.tag &&
418+
this.primaryGuild?.badge === user.primaryGuild?.badge
371419
);
372420
}
373421

@@ -398,6 +446,12 @@ class User extends Base {
398446
this.collectibles?.nameplate?.asset === user.collectibles?.nameplate?.asset &&
399447
this.collectibles?.nameplate?.label === user.collectibles?.nameplate?.label &&
400448
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette
449+
: true) &&
450+
('primary_guild' in user
451+
? this.primaryGuild?.identityGuildId === user.primary_guild?.identity_guild_id &&
452+
this.primaryGuild?.identityEnabled === user.primary_guild?.identity_enabled &&
453+
this.primaryGuild?.tag === user.primary_guild?.tag &&
454+
this.primaryGuild?.badge === user.primary_guild?.badge
401455
: true)
402456
);
403457
}
@@ -437,6 +491,7 @@ class User extends Base {
437491
json.avatarURL = this.avatarURL();
438492
json.displayAvatarURL = this.displayAvatarURL();
439493
json.bannerURL = this.banner ? this.bannerURL() : this.banner;
494+
json.guildTagBadgeURL = this.guildTagBadgeURL();
440495
return json;
441496
}
442497
}

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ import {
3131
APIComponentInModalActionRow,
3232
APIContainerComponent,
3333
APIEmbed,
34-
APIEmbedAuthor,
3534
APIEmbedField,
36-
APIEmbedFooter,
37-
APIEmbedImage,
3835
APIEmbedProvider,
3936
APIEmoji,
4037
APIEntitlement,
@@ -3510,17 +3507,24 @@ export interface AvatarDecorationData {
35103507
skuId: Snowflake;
35113508
}
35123509

3510+
export interface Collectibles {
3511+
nameplate: NameplateData | null;
3512+
}
3513+
3514+
export interface UserPrimaryGuild {
3515+
badge: string | null;
3516+
identityEnabled: boolean | null;
3517+
identityGuildId: Snowflake | null;
3518+
tag: string | null;
3519+
}
3520+
35133521
export interface NameplateData {
35143522
asset: string;
35153523
label: string;
35163524
palette: NameplatePalette;
35173525
skuId: Snowflake;
35183526
}
35193527

3520-
export interface Collectibles {
3521-
nameplate: NameplateData | null;
3522-
}
3523-
35243528
export interface UnfurledMediaItemData {
35253529
url: string;
35263530
}
@@ -3553,12 +3557,14 @@ export class User extends Base {
35533557
public get hexAccentColor(): HexColorString | null | undefined;
35543558
public id: Snowflake;
35553559
public get partial(): false;
3560+
public primaryGuild: UserPrimaryGuild | null;
35563561
public system: boolean;
35573562
public get tag(): string;
35583563
public username: string;
35593564
public avatarURL(options?: ImageURLOptions): string | null;
35603565
public avatarDecorationURL(): string | null;
35613566
public bannerURL(options?: ImageURLOptions): string | null | undefined;
3567+
public guildTagBadgeURL(options?: ImageURLOptions): string | null;
35623568
public createDM(force?: boolean): Promise<DMChannel>;
35633569
public deleteDM(): Promise<DMChannel>;
35643570
public displayAvatarURL(options?: ImageURLOptions): string;

packages/rest/__tests__/CDN.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,11 @@ test('soundboardSound', () => {
134134
expect(cdn.soundboardSound(id)).toEqual(`${baseCDN}/soundboard-sounds/${id}`);
135135
});
136136

137+
test('guildTagBadge', () => {
138+
expect(cdn.guildTagBadge(id, hash)).toEqual(`${baseCDN}/guild-tag-badges/${id}/${hash}.webp`);
139+
});
140+
137141
test('makeURL throws on invalid size', () => {
138-
// @ts-expect-error: Invalid size
139142
expect(() => cdn.avatar(id, animatedHash, { size: 5 })).toThrow(RangeError);
140143
});
141144

packages/rest/src/lib/CDN.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,17 @@ export class CDN {
340340
return `${this.cdn}${CDNRoutes.soundboardSound(soundId)}`;
341341
}
342342

343+
/**
344+
* Generates a URL for a guild tag badge.
345+
*
346+
* @param guildId - The guild id
347+
* @param badgeHash - The hash of the badge
348+
* @param options - Optional options for the badge
349+
*/
350+
public guildTagBadge(guildId: string, badgeHash: string, options?: Readonly<BaseImageURLOptions>): string {
351+
return this.makeURL(`/guild-tag-badges/${guildId}/${badgeHash}`, options);
352+
}
353+
343354
/**
344355
* Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.
345356
*

0 commit comments

Comments
 (0)