From 68f89bb5890dc8d8df2b8ef4c73d90ac3cef9e4f Mon Sep 17 00:00:00 2001 From: Yuzu Date: Mon, 27 Jun 2022 22:47:05 -0500 Subject: [PATCH] feat: new guild methods --- structures/AnonymousGuild.ts | 25 +++++++++++++-- structures/Channel.ts | 1 + structures/Emoji.ts | 1 + structures/Guild.ts | 3 +- structures/GuildChannel.ts | 3 +- structures/GuildEmoji.ts | 4 ++- structures/InviteGuild.ts | 3 +- structures/Message.ts | 60 ++++++++++++++++++++++++++---------- structures/ThreadChannel.ts | 3 +- structures/User.ts | 3 +- util/Cdn.ts | 8 +++++ util/shared/images.ts | 5 +++ 12 files changed, 94 insertions(+), 25 deletions(-) diff --git a/structures/AnonymousGuild.ts b/structures/AnonymousGuild.ts index 6e92ae3..e851e57 100644 --- a/structures/AnonymousGuild.ts +++ b/structures/AnonymousGuild.ts @@ -1,8 +1,11 @@ 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 type { ImageFormat, ImageSize } from "../util/shared/images.ts"; +import { iconBigintToHash, iconHashToBigInt } from "../util/hash.ts"; +import { formatImageUrl } from "../util/shared/images.ts"; import BaseGuild from "./BaseGuild.ts"; +import * as Routes from "../util/Routes.ts"; export class AnonymousGuild extends BaseGuild implements Model { constructor(session: Session, data: Partial); // TODO: Improve this type (name and id are required) @@ -28,7 +31,25 @@ export class AnonymousGuild extends BaseGuild implements Model { description?: string; premiumSubscriptionCount?: number; - // TODO: bannerUrl and splashUrl + splashUrl(options: { size?: ImageSize, format?: ImageFormat } = { size: 128 }) { + if (this.splashHash) { + return formatImageUrl( + Routes.GUILD_SPLASH(this.id, iconBigintToHash(this.splashHash)), + options.size, + options.format + ); + } + } + + bannerUrl(options: { size?: ImageSize, format?: ImageFormat } = { size: 128 }) { + if (this.bannerHash) { + return formatImageUrl( + Routes.GUILD_BANNER(this.id, iconBigintToHash(this.bannerHash)), + options.size, + options.format + ); + } + } } export default AnonymousGuild; diff --git a/structures/Channel.ts b/structures/Channel.ts index a0f3d50..daf18ac 100644 --- a/structures/Channel.ts +++ b/structures/Channel.ts @@ -12,6 +12,7 @@ export abstract class Channel implements Model { } readonly id: Snowflake; readonly session: Session; + name?: string; type: ChannelTypes; diff --git a/structures/Emoji.ts b/structures/Emoji.ts index fe3a321..93dfc92 100644 --- a/structures/Emoji.ts +++ b/structures/Emoji.ts @@ -13,6 +13,7 @@ export class Emoji { } readonly id?: Snowflake; readonly session: Session; + name?: string; animated: boolean; available: boolean; diff --git a/structures/Guild.ts b/structures/Guild.ts index 448b6b6..4df0058 100644 --- a/structures/Guild.ts +++ b/structures/Guild.ts @@ -1,3 +1,4 @@ +import type { Model } from "./Base.ts"; import type { Snowflake } from "../util/Snowflake.ts"; import type { Session } from "../session/Session.ts"; import type { DiscordEmoji, DiscordGuild, DiscordInviteMetadata, DiscordRole } from "../vendor/external.ts"; @@ -41,7 +42,7 @@ export interface ModifyGuildEmoji { * Represents a guild * @link https://discord.com/developers/docs/resources/guild#guild-object */ -export class Guild extends BaseGuild { +export class Guild extends BaseGuild implements Model { constructor(session: Session, data: DiscordGuild) { super(session, data); diff --git a/structures/GuildChannel.ts b/structures/GuildChannel.ts index e101f82..2d60291 100644 --- a/structures/GuildChannel.ts +++ b/structures/GuildChannel.ts @@ -1,10 +1,11 @@ +import type { Model } from "./Base.ts"; import type { Snowflake } from "../util/Snowflake.ts"; import type { Session } from "../session/Session.ts"; import type { DiscordChannel } from "../vendor/external.ts"; import Channel from "./Channel.ts"; import * as Routes from "../util/Routes.ts"; -export abstract class GuildChannel extends Channel { +export abstract class GuildChannel extends Channel implements Model { constructor(session: Session, data: DiscordChannel, guildId: Snowflake) { super(session, data); this.guildId = guildId; diff --git a/structures/GuildEmoji.ts b/structures/GuildEmoji.ts index 3466319..0de968d 100644 --- a/structures/GuildEmoji.ts +++ b/structures/GuildEmoji.ts @@ -1,3 +1,4 @@ +import type { Model } from "./Base.ts"; import type { Snowflake } from "../util/Snowflake.ts"; import type { Session } from "../session/Session.ts"; import type { DiscordEmoji } from "../vendor/external.ts"; @@ -7,7 +8,7 @@ import Emoji from "./Emoji.ts"; import User from "./User.ts"; import * as Routes from "../util/Routes.ts"; -export class GuildEmoji extends Emoji { +export class GuildEmoji extends Emoji implements Model { constructor(session: Session, data: DiscordEmoji, guildId: Snowflake) { super(session, data); this.guildId = guildId; @@ -20,6 +21,7 @@ export class GuildEmoji extends Emoji { roles?: Snowflake[]; user?: User; managed?: boolean; + // id cannot be null in a GuildEmoji override id: Snowflake; diff --git a/structures/InviteGuild.ts b/structures/InviteGuild.ts index d120c93..0465165 100644 --- a/structures/InviteGuild.ts +++ b/structures/InviteGuild.ts @@ -1,9 +1,10 @@ +import type { Model } from "./Base.ts"; import type { Session } from "../session/Session.ts"; import type { DiscordGuild } from "../vendor/external.ts"; import AnonymousGuild from "./AnonymousGuild.ts"; import WelcomeScreen from "./WelcomeScreen.ts"; -export class InviteGuild extends AnonymousGuild { +export class InviteGuild extends AnonymousGuild implements Model { constructor(session: Session, data: Partial) { super(session, data); diff --git a/structures/Message.ts b/structures/Message.ts index 9b000c3..61d81ee 100644 --- a/structures/Message.ts +++ b/structures/Message.ts @@ -1,7 +1,7 @@ import type { Model } from "./Base.ts"; import type { Snowflake } from "../util/Snowflake.ts"; import type { Session } from "../session/Session.ts"; -import type { AllowedMentionsTypes, DiscordMessage } from "../vendor/external.ts"; +import type { AllowedMentionsTypes, DiscordMessage, FileContent } from "../vendor/external.ts"; import { MessageFlags } from "../util/shared/flags.ts"; import User from "./User.ts"; import Member from "./Member.ts"; @@ -18,21 +18,40 @@ export interface AllowedMentions { users?: Snowflake[]; } -/** - * @link https://discord.com/developers/docs/resources/channel#edit-message-json-params - */ -export interface EditMessage { - content?: string; - allowedMentions?: AllowedMentions; - flags?: MessageFlags; +export interface CreateMessageReference { + messageId: Snowflake; + channelId?: Snowflake; + guildId?: Snowflake; + failIfNotExists?: boolean; } /** * @link https://discord.com/developers/docs/resources/channel#create-message-json-params */ export interface CreateMessage { - content?: string; + content: string; allowedMentions?: AllowedMentions; + messageReference?: CreateMessageReference; +} + +export interface CreateMessage { + allowedMentions?: AllowedMentions; + files: FileContent[]; + messageReference?: CreateMessageReference; +} + +export interface CreateMessage { + content: string; + allowedMentions?: AllowedMentions; + files: FileContent[]; + messageReference?: CreateMessageReference; +} + +/** + * @link https://discord.com/developers/docs/resources/channel#edit-message-json-params + */ +export interface EditMessage extends Partial { + flags?: MessageFlags; } /** @@ -127,23 +146,30 @@ export class Message implements Model { } /** Replies directly in the channel the message was sent */ - async reply({ content, allowedMentions }: CreateMessage): Promise { - const message = await this.session.rest.runMethod( + async reply(options: CreateMessage): Promise { + const message = await this.session.rest.runMethod( this.session.rest, "POST", Routes.CHANNEL_MESSAGES(this.channelId), { - content, + content: options.content, + file: options.files, allowed_mentions: { - parse: allowedMentions?.parse, - roles: allowedMentions?.roles, - users: allowedMentions?.users, - replied_user: allowedMentions?.repliedUser, + parse: options.allowedMentions?.parse, + roles: options.allowedMentions?.roles, + users: options.allowedMentions?.users, + replied_user: options.allowedMentions?.repliedUser, }, + message_reference: options.messageReference ? { + message_id: options.messageReference.messageId, + channel_id: options.messageReference.channelId, + guild_id: options.messageReference.guildId, + fail_if_not_exists: options.messageReference.failIfNotExists ?? true, + } : undefined, }, ); - return message; + return new Message(this.session, message); } inGuild(): this is { guildId: Snowflake } & Message { diff --git a/structures/ThreadChannel.ts b/structures/ThreadChannel.ts index deaa23a..b846f93 100644 --- a/structures/ThreadChannel.ts +++ b/structures/ThreadChannel.ts @@ -1,9 +1,10 @@ +import type { Model } from "./Base.ts"; import type { Snowflake } from "../util/Snowflake.ts"; import type { Session } from "../session/Session.ts"; import type { DiscordChannel } from "../vendor/external.ts"; import GuildChannel from "./GuildChannel.ts"; -export class ThreadChannel extends GuildChannel { +export class ThreadChannel extends GuildChannel implements Model { constructor(session: Session, data: DiscordChannel, guildId: Snowflake) { super(session, data, guildId); this.archived = !!data.thread_metadata?.archived; diff --git a/structures/User.ts b/structures/User.ts index 551d58f..abd6c22 100644 --- a/structures/User.ts +++ b/structures/User.ts @@ -4,6 +4,7 @@ import type { Session } from "../session/Session.ts"; import type { DiscordUser } from "../vendor/external.ts"; import type { ImageFormat, ImageSize } from "../util/shared/images.ts"; import { iconBigintToHash, iconHashToBigInt } from "../util/hash.ts"; +import { formatImageUrl } from "../util/shared/images.ts"; import * as Routes from "../util/Routes.ts"; /** @@ -50,7 +51,7 @@ export class User implements Model { url = Routes.USER_AVATAR(this.id, iconBigintToHash(this.avatarHash)); } - return `${url}.${options.format ?? (url.includes("/a_") ? "gif" : "jpg")}?size=${options.size}`; + return formatImageUrl(url, options.size, options.format); } toString() { diff --git a/util/Cdn.ts b/util/Cdn.ts index 3debf56..c290ea2 100644 --- a/util/Cdn.ts +++ b/util/Cdn.ts @@ -15,3 +15,11 @@ export function USER_DEFAULT_AVATAR( ) { return `${Endpoints.CDN_URL}/embed/avatars/${altIcon}.png`; } + +export function GUILD_BANNER(guildId: Snowflake, icon: string) { + return `${Endpoints.CDN_URL}/banners/${guildId}/${icon}`; +} + +export function GUILD_SPLASH(guildId: Snowflake, icon: string) { + return `${Endpoints.CDN_URL}/splashes/${guildId}/${icon}`; +} diff --git a/util/shared/images.ts b/util/shared/images.ts index 9c8f86d..06ba7aa 100644 --- a/util/shared/images.ts +++ b/util/shared/images.ts @@ -7,3 +7,8 @@ export type ImageFormat = "jpg" | "jpeg" | "png" | "webp" | "gif" | "json"; * @link https://discord.com/developers/docs/reference#image-formatting */ export type ImageSize = 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096; + +/** Help format an image url */ +export function formatImageUrl(url: string, size: ImageSize = 128, format?: ImageFormat) { + return `${url}.${format || (url.includes("/a_") ? "gif" : "jpg")}?size=${size}`; +}