feat: add support for role icons (#6633)

This commit is contained in:
Shubham Parihar
2021-10-03 22:25:29 +05:30
committed by GitHub
parent a8c21cd754
commit 7129965423
5 changed files with 91 additions and 3 deletions

View File

@@ -4,6 +4,7 @@ const { Collection } = require('@discordjs/collection');
const CachedManager = require('./CachedManager'); const CachedManager = require('./CachedManager');
const { TypeError } = require('../errors'); const { TypeError } = require('../errors');
const Role = require('../structures/Role'); const Role = require('../structures/Role');
const DataResolver = require('../util/DataResolver');
const Permissions = require('../util/Permissions'); const Permissions = require('../util/Permissions');
const { resolveColor, setPosition } = require('../util/Util'); const { resolveColor, setPosition } = require('../util/Util');
@@ -104,6 +105,10 @@ class RoleManager extends CachedManager {
* @property {PermissionResolvable} [permissions] The permissions for the new role * @property {PermissionResolvable} [permissions] The permissions for the new role
* @property {number} [position] The position of the new role * @property {number} [position] The position of the new role
* @property {boolean} [mentionable] Whether or not the new role should be mentionable * @property {boolean} [mentionable] Whether or not the new role should be mentionable
* @property {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} [icon] The icon for the role
* <warn>The `EmojiResolvable` should belong to the same guild as the role.
* If not, pass the emoji's URL directly</warn>
* @property {?string} [unicodeEmoji] The unicode emoji for the role
* @property {string} [reason] The reason for creating this role * @property {string} [reason] The reason for creating this role
*/ */
@@ -128,9 +133,14 @@ class RoleManager extends CachedManager {
* .catch(console.error); * .catch(console.error);
*/ */
async create(options = {}) { async create(options = {}) {
let { name, color, hoist, permissions, position, mentionable, reason } = options; let { name, color, hoist, permissions, position, mentionable, reason, icon, unicodeEmoji } = options;
color &&= resolveColor(color); color &&= resolveColor(color);
if (typeof permissions !== 'undefined') permissions = new Permissions(permissions); if (typeof permissions !== 'undefined') permissions = new Permissions(permissions);
if (icon) {
const guildEmojiURL = this.guild.emojis.resolve(icon)?.url;
icon = guildEmojiURL ? await DataResolver.resolveImage(guildEmojiURL) : await DataResolver.resolveImage(icon);
if (typeof icon !== 'string') icon = undefined;
}
const data = await this.client.api.guilds(this.guild.id).roles.post({ const data = await this.client.api.guilds(this.guild.id).roles.post({
data: { data: {
@@ -139,6 +149,8 @@ class RoleManager extends CachedManager {
hoist, hoist,
permissions, permissions,
mentionable, mentionable,
icon,
unicode_emoji: unicodeEmoji,
}, },
reason, reason,
}); });
@@ -182,12 +194,21 @@ class RoleManager extends CachedManager {
}); });
} }
let icon = data.icon;
if (icon) {
const guildEmojiURL = this.guild.emojis.resolve(icon)?.url;
icon = guildEmojiURL ? await DataResolver.resolveImage(guildEmojiURL) : await DataResolver.resolveImage(icon);
if (typeof icon !== 'string') icon = undefined;
}
const _data = { const _data = {
name: data.name, name: data.name,
color: typeof data.color === 'undefined' ? undefined : resolveColor(data.color), color: typeof data.color === 'undefined' ? undefined : resolveColor(data.color),
hoist: data.hoist, hoist: data.hoist,
permissions: typeof data.permissions === 'undefined' ? undefined : new Permissions(data.permissions), permissions: typeof data.permissions === 'undefined' ? undefined : new Permissions(data.permissions),
mentionable: data.mentionable, mentionable: data.mentionable,
icon,
unicode_emoji: data.unicodeEmoji,
}; };
const d = await this.client.api.guilds(this.guild.id).roles(role.id).patch({ data: _data, reason }); const d = await this.client.api.guilds(this.guild.id).roles(role.id).patch({ data: _data, reason });

View File

@@ -186,6 +186,7 @@ class Guild extends AnonymousGuild {
* * THREE_DAY_THREAD_ARCHIVE * * THREE_DAY_THREAD_ARCHIVE
* * SEVEN_DAY_THREAD_ARCHIVE * * SEVEN_DAY_THREAD_ARCHIVE
* * PRIVATE_THREADS * * PRIVATE_THREADS
* * ROLE_ICONS
* @typedef {string} Features * @typedef {string} Features
* @see {@link https://discord.com/developers/docs/resources/guild#guild-object-guild-features} * @see {@link https://discord.com/developers/docs/resources/guild#guild-object-guild-features}
*/ */

View File

@@ -91,6 +91,18 @@ class Role extends Base {
*/ */
this.deleted = false; this.deleted = false;
/**
* The icon hash of the role
* @type {?string}
*/
this.icon = data.icon;
/**
* The unicode emoji for the role
* @type {?string}
*/
this.unicodeEmoji = data.unicode_emoji;
/** /**
* The tags this role has * The tags this role has
* @type {?Object} * @type {?Object}
@@ -191,6 +203,10 @@ class Role extends Base {
* @property {number} [position] The position of the role * @property {number} [position] The position of the role
* @property {PermissionResolvable} [permissions] The permissions of the role * @property {PermissionResolvable} [permissions] The permissions of the role
* @property {boolean} [mentionable] Whether or not the role should be mentionable * @property {boolean} [mentionable] Whether or not the role should be mentionable
* @property {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} [icon] The icon for the role
* <warn>The `EmojiResolvable` should belong to the same guild as the role.
* If not, pass the emoji's URL directly</warn>
* @property {?string} [unicodeEmoji] The unicode emoji for the role
*/ */
/** /**
@@ -300,6 +316,33 @@ class Role extends Base {
return this.edit({ mentionable }, reason); return this.edit({ mentionable }, reason);
} }
/**
* Sets a new icon for the role.
* @param {?(BufferResolvable|Base64Resolvable|EmojiResolvable)} icon The icon for the role
* <warn>The `EmojiResolvable` should belong to the same guild as the role.
* If not, pass the emoji's URL directly</warn>
* @param {string} [reason] Reason for changing the role's icon
* @returns {Promise<Role>}
*/
setIcon(icon, reason) {
return this.edit({ icon }, reason);
}
/**
* Sets a new unicode emoji for the role.
* @param {?string} unicodeEmoji The new unicode emoji for the role
* @param {string} [reason] Reason for changing the role's unicode emoji
* @returns {Promise<Role>}
* @example
* // Set a new unicode emoji for the role
* role.setUnicodeEmoji('🤖')
* .then(updated => console.log(`Set unicode emoji for the role to ${updated.unicodeEmoji}`))
* .catch(console.error);
*/
setUnicodeEmoji(unicodeEmoji, reason) {
return this.edit({ unicodeEmoji }, reason);
}
/** /**
* Options used to set position of a role. * Options used to set position of a role.
* @typedef {Object} SetRolePositionOptions * @typedef {Object} SetRolePositionOptions
@@ -350,6 +393,16 @@ class Role extends Base {
return this; return this;
} }
/**
* A link to the role's icon
* @param {StaticImageURLOptions} [options={}] Options for the image URL
* @returns {?string}
*/
iconURL({ format, size } = {}) {
if (!this.icon) return null;
return this.client.rest.cdn.RoleIcon(this.id, this.icon, format, size);
}
/** /**
* Whether this role equals another role. It compares all properties, so for most operations * Whether this role equals another role. It compares all properties, so for most operations
* it is advisable to just compare `role.id === role2.id` as it is much faster and is often * it is advisable to just compare `role.id === role2.id` as it is much faster and is often
@@ -366,7 +419,9 @@ class Role extends Base {
this.hoist === role.hoist && this.hoist === role.hoist &&
this.position === role.position && this.position === role.position &&
this.permissions.bitfield === role.permissions.bitfield && this.permissions.bitfield === role.permissions.bitfield &&
this.managed === role.managed this.managed === role.managed &&
this.icon === role.icon &&
this.unicodeEmoji === role.unicodeEmoji
); );
} }

View File

@@ -73,6 +73,8 @@ exports.Endpoints = {
TeamIcon: (teamId, hash, options) => makeImageUrl(`${root}/team-icons/${teamId}/${hash}`, options), TeamIcon: (teamId, hash, options) => makeImageUrl(`${root}/team-icons/${teamId}/${hash}`, options),
Sticker: (stickerId, stickerFormat) => Sticker: (stickerId, stickerFormat) =>
`${root}/stickers/${stickerId}.${stickerFormat === 'LOTTIE' ? 'json' : 'png'}`, `${root}/stickers/${stickerId}.${stickerFormat === 'LOTTIE' ? 'json' : 'png'}`,
RoleIcon: (roleId, hash, format = 'webp', size) =>
makeImageUrl(`${root}/role-icons/${roleId}/${hash}`, { size, format }),
}; };
}, },
invite: (root, code) => `${root}/${code}`, invite: (root, code) => `${root}/${code}`,

11
typings/index.d.ts vendored
View File

@@ -1647,16 +1647,21 @@ export class Role extends Base {
public rawPosition: number; public rawPosition: number;
public tags: RoleTagData | null; public tags: RoleTagData | null;
public comparePositionTo(role: RoleResolvable): number; public comparePositionTo(role: RoleResolvable): number;
public icon: string | null;
public unicodeEmoji: string | null;
public delete(reason?: string): Promise<Role>; public delete(reason?: string): Promise<Role>;
public edit(data: RoleData, reason?: string): Promise<Role>; public edit(data: RoleData, reason?: string): Promise<Role>;
public equals(role: Role): boolean; public equals(role: Role): boolean;
public iconURL(options?: StaticImageURLOptions): string | null;
public permissionsIn(channel: GuildChannel | Snowflake): Readonly<Permissions>; public permissionsIn(channel: GuildChannel | Snowflake): Readonly<Permissions>;
public setColor(color: ColorResolvable, reason?: string): Promise<Role>; public setColor(color: ColorResolvable, reason?: string): Promise<Role>;
public setHoist(hoist?: boolean, reason?: string): Promise<Role>; public setHoist(hoist?: boolean, reason?: string): Promise<Role>;
public setMentionable(mentionable?: boolean, reason?: string): Promise<Role>; public setMentionable(mentionable?: boolean, reason?: string): Promise<Role>;
public setName(name: string, reason?: string): Promise<Role>; public setName(name: string, reason?: string): Promise<Role>;
public setPermissions(permissions: PermissionResolvable, reason?: string): Promise<Role>; public setPermissions(permissions: PermissionResolvable, reason?: string): Promise<Role>;
public setIcon(icon: BufferResolvable | Base64Resolvable | EmojiResolvable | null, reason?: string): Promise<Role>;
public setPosition(position: number, options?: SetRolePositionOptions): Promise<Role>; public setPosition(position: number, options?: SetRolePositionOptions): Promise<Role>;
public setUnicodeEmoji(unicodeEmoji: string | null, reason?: string): Promise<Role>;
public toJSON(): unknown; public toJSON(): unknown;
public toString(): RoleMention; public toString(): RoleMention;
@@ -2362,6 +2367,7 @@ export const Constants: {
{ format, size }: { format: AllowedImageFormat; size: AllowedImageSize }, { format, size }: { format: AllowedImageFormat; size: AllowedImageSize },
) => string; ) => string;
Sticker: (stickerId: Snowflake, stickerFormat: StickerFormatType) => string; Sticker: (stickerId: Snowflake, stickerFormat: StickerFormatType) => string;
RoleIcon: (roleId: Snowflake, hash: string, format: AllowedImageFormat, size: AllowedImageSize) => string;
}; };
}; };
WSCodes: { WSCodes: {
@@ -4069,7 +4075,8 @@ export type GuildFeatures =
| 'MORE_STICKERS' | 'MORE_STICKERS'
| 'THREE_DAY_THREAD_ARCHIVE' | 'THREE_DAY_THREAD_ARCHIVE'
| 'SEVEN_DAY_THREAD_ARCHIVE' | 'SEVEN_DAY_THREAD_ARCHIVE'
| 'PRIVATE_THREADS'; | 'PRIVATE_THREADS'
| 'ROLE_ICONS';
export interface GuildMemberEditData { export interface GuildMemberEditData {
nick?: string | null; nick?: string | null;
@@ -4740,6 +4747,8 @@ export interface RoleData {
position?: number; position?: number;
permissions?: PermissionResolvable; permissions?: PermissionResolvable;
mentionable?: boolean; mentionable?: boolean;
icon?: BufferResolvable | Base64Resolvable | EmojiResolvable | null;
unicodeEmoji?: string | null;
} }
export type RoleMention = '@everyone' | `<@&${Snowflake}>`; export type RoleMention = '@everyone' | `<@&${Snowflake}>`;