From 84b288d4695bb58804117f172a4428e160ba8663 Mon Sep 17 00:00:00 2001 From: Yuzu Date: Thu, 23 Jun 2022 20:56:15 -0500 Subject: [PATCH 1/2] feat: better guild structure --- structures/AnonymousGuild.ts | 31 ++++++++++++++++++++++++++++ structures/BaseGuild.ts | 40 ++++++++++++++++++++++++++++++++++++ structures/Guild.ts | 17 +++++++-------- 3 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 structures/AnonymousGuild.ts create mode 100644 structures/BaseGuild.ts diff --git a/structures/AnonymousGuild.ts b/structures/AnonymousGuild.ts new file mode 100644 index 0000000..649809b --- /dev/null +++ b/structures/AnonymousGuild.ts @@ -0,0 +1,31 @@ +import type { Model } from "./Base.ts"; +import type { Session } from "../session/Session.ts"; +import type { DiscordGuild, GuildNsfwLevel, VerificationLevels } from "../vendor/external.ts"; +import { iconHashToBigInt } from "../util/hash.ts"; +import { BaseGuild } from "./BaseGuild.ts"; + +export abstract class AnonymousGuild extends BaseGuild implements Model { + constructor(session: Session, data: DiscordGuild) { + super(session, data); + + this.splashHash = data.splash ? iconHashToBigInt(data.splash) : undefined; + this.bannerHash = data.banner ? iconHashToBigInt(data.banner) : undefined; + + this.verificationLevel = data.verification_level; + this.vanityUrlCode = data.vanity_url_code ? data.vanity_url_code : undefined; + this.nsfwLevel = data.nsfw_level; + this.description = data.description ? data.description : undefined; + this.premiumSubscriptionCount = data.premium_subscription_count; + } + + splashHash?: bigint; + bannerHash?: bigint; + + verificationLevel: VerificationLevels; + vanityUrlCode?: string; + nsfwLevel: GuildNsfwLevel; + description?: string; + premiumSubscriptionCount?: number; + + // TODO: bannerUrl and splashUrl +} diff --git a/structures/BaseGuild.ts b/structures/BaseGuild.ts new file mode 100644 index 0000000..4c1d24b --- /dev/null +++ b/structures/BaseGuild.ts @@ -0,0 +1,40 @@ +import type { Model } from "./Base.ts"; +import type { Session } from "../session/Session.ts"; +import type { DiscordGuild, GuildFeatures } from "../vendor/external.ts"; +import { Snowflake } from "../util/Snowflake.ts"; +import { iconHashToBigInt } from "../util/hash.ts"; + +/** + * Class for {@link Guild} and {@link AnonymousGuild} + * */ +export abstract class BaseGuild implements Model { + constructor(session: Session, data: DiscordGuild) { + this.session = session; + this.id = data.id; + + this.name = data.name; + this.iconHash = data.icon ? iconHashToBigInt(data.icon) : undefined; + + this.features = data.features; + } + + readonly session: Session; + readonly id: Snowflake; + + name: string; + iconHash?: bigint; + features: GuildFeatures[]; + + get createdTimestamp() { + return Snowflake.snowflakeToTimestamp(this.id); + } + + get createdAt() { + return new Date(this.createdTimestamp); + } + + toString() { + return this.name; + } +} + diff --git a/structures/Guild.ts b/structures/Guild.ts index 803a69d..98de437 100644 --- a/structures/Guild.ts +++ b/structures/Guild.ts @@ -5,14 +5,16 @@ import type { DiscordGuild, DiscordMember, MakeRequired } from "../vendor/extern import { DefaultMessageNotificationLevels, ExplicitContentFilterLevels, VerificationLevels } from "../vendor/external.ts"; import { iconHashToBigInt, iconBigintToHash as _iconBigintToHash } from "../util/hash.ts"; import { Member } from "./Member.ts"; +import { BaseGuild } from "./BaseGuild.ts"; -export class Guild implements Model { +/** + * Represents a guild + * @link https://discord.com/developers/docs/resources/guild#guild-object + * */ +export class Guild extends BaseGuild implements Model { constructor(session: Session, data: DiscordGuild) { - this.session = session; - this.id = data.id; + super(session, data); - this.name = data.name; - this.iconHash = data.icon ? iconHashToBigInt(data.icon) : undefined; this.splashHash = data.splash ? iconHashToBigInt(data.splash) : undefined; this.discoverySplashHash = data.discovery_splash ? iconHashToBigInt(data.discovery_splash) : undefined; this.ownerId = data.owner_id; @@ -24,11 +26,6 @@ export class Guild implements Model { this.members = data.members?.map((member) => new Member(session, member as MakeRequired)) ?? []; } - readonly session: Session; - readonly id: Snowflake; - - name: string; - iconHash?: bigint; splashHash?: bigint; discoverySplashHash?: bigint; ownerId: Snowflake; From 9e0d1570035c79b4b0de20ac772fc01ba61d723a Mon Sep 17 00:00:00 2001 From: Yuzu Date: Fri, 24 Jun 2022 20:11:35 -0500 Subject: [PATCH 2/2] feat: role struct --- structures/Guild.ts | 52 ++++++++++++++++++++++++++++++++++--- structures/Role.ts | 62 +++++++++++++++++++++++++++++++++++++++++++++ util/Routes.ts | 8 ++++++ 3 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 structures/Role.ts diff --git a/structures/Guild.ts b/structures/Guild.ts index 98de437..2f88322 100644 --- a/structures/Guild.ts +++ b/structures/Guild.ts @@ -1,11 +1,22 @@ import type { Model } from "./Base.ts"; import type { Snowflake } from "../util/Snowflake.ts"; import type { Session } from "../session/Session.ts"; -import type { DiscordGuild, DiscordMember, MakeRequired } from "../vendor/external.ts"; +import type { DiscordGuild, DiscordRole } from "../vendor/external.ts"; import { DefaultMessageNotificationLevels, ExplicitContentFilterLevels, VerificationLevels } from "../vendor/external.ts"; -import { iconHashToBigInt, iconBigintToHash as _iconBigintToHash } from "../util/hash.ts"; +import { iconHashToBigInt, iconBigintToHash } from "../util/hash.ts"; import { Member } from "./Member.ts"; import { BaseGuild } from "./BaseGuild.ts"; +import { Role } from "./Role.ts"; +import { Routes } from "../util/mod.ts"; + +export interface CreateRole { + name?: string; + color?: number; + iconHash?: string | bigint; + unicodeEmoji?: string; + hoist?: boolean; + mentionable?: boolean; +} /** * Represents a guild @@ -23,7 +34,8 @@ export class Guild extends BaseGuild implements Model { this.vefificationLevel = data.verification_level; this.defaultMessageNotificationLevel = data.default_message_notifications; this.explicitContentFilterLevel = data.explicit_content_filter; - this.members = data.members?.map((member) => new Member(session, member as MakeRequired)) ?? []; + this.members = data.members?.map((member) => new Member(session, { ...member, user: member.user! })) ?? []; + this.roles = data.roles.map((role) => new Role(session, this, role)); } splashHash?: bigint; @@ -35,4 +47,38 @@ export class Guild extends BaseGuild implements Model { defaultMessageNotificationLevel: DefaultMessageNotificationLevels; explicitContentFilterLevel: ExplicitContentFilterLevels; members: Member[]; + roles: Role[]; + + async createRole(options: CreateRole) { + let icon: string | undefined; + + if (options.iconHash) { + if (typeof options.iconHash === "string") { + icon = options.iconHash; + } + else { + icon = iconBigintToHash(options.iconHash); + } + } + + const role = await this.session.rest.runMethod( + this.session.rest, + "PUT", + Routes.GUILD_ROLES(this.id), + { + name: options.name, + color: options.color, + icon, + unicode_emoji: options.unicodeEmoji, + hoist: options.hoist, + mentionable: options.mentionable, + } + ); + + return new Role(this.session, this, role); + } + + async deleteRole(roleId: Snowflake): Promise { + await this.session.rest.runMethod(this.session.rest, "DELETE", Routes.GUILD_ROLE(this.id, roleId)); + } } diff --git a/structures/Role.ts b/structures/Role.ts new file mode 100644 index 0000000..fd754f7 --- /dev/null +++ b/structures/Role.ts @@ -0,0 +1,62 @@ +import type { Model } from "./Base.ts"; +import type { Session } from "../session/Session.ts"; +import type { DiscordRole } from "../vendor/external.ts"; +import { Snowflake } from "../util/Snowflake.ts"; +import { iconHashToBigInt } from "../util/hash.ts"; +import { Guild } from "./Guild.ts"; + +export class Role implements Model { + constructor(session: Session, guild: Guild, data: DiscordRole) { + this.session = session; + this.id = data.id; + this.guild = guild; + this.hoist = data.hoist; + this.iconHash = data.icon ? iconHashToBigInt(data.icon) : undefined; + this.color = data.color; + this.name = data.name; + this.unicodeEmoji = data.unicode_emoji; + this.mentionable = data.mentionable; + this.managed = data.managed; + } + + session: Session; + id: Snowflake; + guild: Guild; + hoist: boolean; + iconHash?: bigint; + color: number; + name: string; + unicodeEmoji?: string; + mentionable: boolean; + managed: boolean; + + get createdTimestamp() { + return Snowflake.snowflakeToTimestamp(this.id); + } + + get createdAt() { + return new Date(this.createdTimestamp); + } + + get hexColor() { + return `#${this.color.toString(16).padStart(6, '0')}`; + } + + /* + * delete() { + * return.this.guild.deleteRole(this.id); + * } + * edit() { + * return this.guild.editRole(this.id); + * } + * */ + + toString() { + switch (this.id) { + case this.guild.id: + return "@everyone"; + default: + return `<@&${this.id}>`; + } + } +} diff --git a/util/Routes.ts b/util/Routes.ts index a6adec0..b2f6f2c 100644 --- a/util/Routes.ts +++ b/util/Routes.ts @@ -73,3 +73,11 @@ export function GUILD_BANS(guildId: Snowflake, options?: GetBans) { return url; } + +export function GUILD_ROLE(guildId: Snowflake, roleId: Snowflake) { + return `/guilds/${guildId}/roles/${roleId}`; +} + +export function GUILD_ROLES(guildId: Snowflake) { + return `/guilds/${guildId}/roles`; +}