Skip to content

Commit baa08b8

Browse files
authored
feat: support user guilds (#10995)
1 parent f469f74 commit baa08b8

File tree

4 files changed

+95
-16
lines changed

4 files changed

+95
-16
lines changed

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

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,22 @@ class User extends Base {
141141
* @property {string} asset The avatar decoration hash
142142
* @property {Snowflake} skuId The id of the avatar decoration's SKU
143143
*/
144-
145-
if (data.avatar_decoration_data) {
146-
/**
147-
* The user avatar decoration's data
148-
* @type {?AvatarDecorationData}
149-
*/
150-
this.avatarDecorationData = {
151-
asset: data.avatar_decoration_data.asset,
152-
skuId: data.avatar_decoration_data.sku_id,
153-
};
144+
if ('avatar_decoration_data' in data) {
145+
if (data.avatar_decoration_data) {
146+
/**
147+
* The user avatar decoration's data
148+
*
149+
* @type {?AvatarDecorationData}
150+
*/
151+
this.avatarDecorationData = {
152+
asset: data.avatar_decoration_data.asset,
153+
skuId: data.avatar_decoration_data.sku_id,
154+
};
155+
} else {
156+
this.avatarDecorationData = null;
157+
}
154158
} else {
155-
this.avatarDecorationData = null;
159+
this.avatarDecorationData ??= null;
156160
}
157161

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

183215
/**
@@ -269,6 +301,18 @@ class User extends Base {
269301
return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options);
270302
}
271303

304+
/**
305+
* A link to the user's guild tag badge.
306+
*
307+
* @param {ImageURLOptions} [options={}] Options for the image URL
308+
* @returns {?string}
309+
*/
310+
guildTagBadgeURL(options = {}) {
311+
return this.primaryGuild?.badge
312+
? this.client.rest.cdn.guildTagBadge(this.primaryGuild.identityGuildId, this.primaryGuild.badge, options)
313+
: null;
314+
}
315+
272316
/**
273317
* The tag of this user
274318
* <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)
@@ -343,7 +387,11 @@ class User extends Base {
343387
this.collectibles?.nameplate?.skuId === user.collectibles?.nameplate?.skuId &&
344388
this.collectibles?.nameplate?.asset === user.collectibles?.nameplate?.asset &&
345389
this.collectibles?.nameplate?.label === user.collectibles?.nameplate?.label &&
346-
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette
390+
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette &&
391+
this.primaryGuild?.identityGuildId === user.primaryGuild?.identityGuildId &&
392+
this.primaryGuild?.identityEnabled === user.primaryGuild?.identityEnabled &&
393+
this.primaryGuild?.tag === user.primaryGuild?.tag &&
394+
this.primaryGuild?.badge === user.primaryGuild?.badge
347395
);
348396
}
349397

@@ -374,6 +422,12 @@ class User extends Base {
374422
this.collectibles?.nameplate?.asset === user.collectibles?.nameplate?.asset &&
375423
this.collectibles?.nameplate?.label === user.collectibles?.nameplate?.label &&
376424
this.collectibles?.nameplate?.palette === user.collectibles?.nameplate?.palette
425+
: true) &&
426+
('primary_guild' in user
427+
? this.primaryGuild?.identityGuildId === user.primary_guild?.identity_guild_id &&
428+
this.primaryGuild?.identityEnabled === user.primary_guild?.identity_enabled &&
429+
this.primaryGuild?.tag === user.primary_guild?.tag &&
430+
this.primaryGuild?.badge === user.primary_guild?.badge
377431
: true)
378432
);
379433
}
@@ -423,6 +477,7 @@ class User extends Base {
423477
json.avatarURL = this.avatarURL();
424478
json.displayAvatarURL = this.displayAvatarURL();
425479
json.bannerURL = this.banner ? this.bannerURL() : this.banner;
480+
json.guildTagBadgeURL = this.guildTagBadgeURL();
426481
return json;
427482
}
428483
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3803,17 +3803,24 @@ export interface AvatarDecorationData {
38033803
skuId: Snowflake;
38043804
}
38053805

3806+
export interface Collectibles {
3807+
nameplate: NameplateData | null;
3808+
}
3809+
3810+
export interface UserPrimaryGuild {
3811+
badge: string | null;
3812+
identityEnabled: boolean | null;
3813+
identityGuildId: Snowflake | null;
3814+
tag: string | null;
3815+
}
3816+
38063817
export interface NameplateData {
38073818
asset: string;
38083819
label: string;
38093820
palette: NameplatePalette;
38103821
skuId: Snowflake;
38113822
}
38123823

3813-
export interface Collectibles {
3814-
nameplate: NameplateData | null;
3815-
}
3816-
38173824
export interface UnfurledMediaItemData {
38183825
url: string;
38193826
}
@@ -3849,12 +3856,14 @@ export class User extends Base {
38493856
public get hexAccentColor(): HexColorString | null | undefined;
38503857
public id: Snowflake;
38513858
public get partial(): false;
3859+
public primaryGuild: UserPrimaryGuild | null;
38523860
public system: boolean;
38533861
public get tag(): string;
38543862
public username: string;
38553863
public avatarURL(options?: ImageURLOptions): string | null;
38563864
public avatarDecorationURL(options?: BaseImageURLOptions): string | null;
38573865
public bannerURL(options?: ImageURLOptions): string | null | undefined;
3866+
public guildTagBadgeURL(options?: ImageURLOptions): string | null;
38583867
public createDM(force?: boolean): Promise<DMChannel>;
38593868
public deleteDM(): Promise<DMChannel>;
38603869
public displayAvatarURL(options?: ImageURLOptions): string;

packages/rest/__tests__/CDN.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ test('soundboardSound', () => {
142142
expect(cdn.soundboardSound(id)).toEqual(`${baseCDN}/soundboard-sounds/${id}`);
143143
});
144144

145+
test('guildTagBadge', () => {
146+
expect(cdn.guildTagBadge(id, hash)).toEqual(`${baseCDN}/guild-tag-badges/${id}/${hash}.webp`);
147+
});
148+
145149
test('makeURL throws on invalid size', () => {
146150
expect(() => cdn.avatar(id, animatedHash, { size: 5 })).toThrow(RangeError);
147151
});

packages/rest/src/lib/CDN.ts

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

377+
/**
378+
* Generates a URL for a guild tag badge.
379+
*
380+
* @param guildId - The guild id
381+
* @param badgeHash - The hash of the badge
382+
* @param options - Optional options for the badge
383+
*/
384+
public guildTagBadge(guildId: string, badgeHash: string, options?: Readonly<BaseImageURLOptions>): string {
385+
return this.makeURL(`/guild-tag-badges/${guildId}/${badgeHash}`, options);
386+
}
387+
377388
/**
378389
* Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.
379390
*

0 commit comments

Comments
 (0)