diff --git a/bot.ts b/bot.ts index 0aa6de58b..3be8da661 100644 --- a/bot.ts +++ b/bot.ts @@ -8,11 +8,13 @@ import { Message, Role, ScheduledEvent, + Template, transformChannel, transformGuild, transformMember, transformMessage, transformRole, + transformTemplate, transformUser, transformVoiceState, User, @@ -67,6 +69,7 @@ import { DiscordInteractionDataOption, DiscordReady, DiscordStickerPack, + DiscordTemplate, } from "./types/discord.ts"; import { Errors, GatewayDispatchEventNames, GatewayIntents } from "./types/shared.ts"; @@ -407,6 +410,7 @@ export interface Transformers { stageInstance: (bot: Bot, payload: DiscordStageInstance) => StageInstance; sticker: (bot: Bot, payload: DiscordSticker) => Sticker; stickerPack: (bot: Bot, payload: DiscordStickerPack) => StickerPack; + template: (bot: Bot, payload: DiscordTemplate) => Template; } export function createTransformers(options: Partial) { @@ -447,6 +451,7 @@ export function createTransformers(options: Partial) { sticker: options.sticker || transformSticker, stickerPack: options.stickerPack || transformStickerPack, gatewayBot: options.gatewayBot || transformGatewayBot, + template: options.template || transformTemplate, }; } diff --git a/helpers/templates/createGuildTemplate.ts b/helpers/templates/createGuildTemplate.ts index 21d04b091..dbc8770a0 100644 --- a/helpers/templates/createGuildTemplate.ts +++ b/helpers/templates/createGuildTemplate.ts @@ -1,10 +1,8 @@ import type { Bot } from "../../bot.ts"; -import { Guild } from "../../transformers/guild.ts"; -import { User } from "../../transformers/member.ts"; import { DiscordTemplate } from "../../types/discord.ts"; /** Creates a template for the guild. Requires the `MANAGE_GUILD` permission. */ -export async function createGuildTemplate(bot: Bot, guildId: bigint, data: Template) { +export async function createGuildTemplate(bot: Bot, guildId: bigint, data: CreateTemplate) { if (data.name.length < 1 || data.name.length > 100) { throw new Error("The name can only be in between 1-100 characters."); } @@ -13,42 +11,17 @@ export async function createGuildTemplate(bot: Bot, guildId: bigint, data: Templ throw new Error("The description can only be in between 0-120 characters."); } - return await bot.rest.runMethod(bot.rest, "post", bot.constants.endpoints.GUILD_TEMPLATES(guildId), { - code: data.code, - name: data.name, - description: data.description, - usage_count: data.usageCount, - creator_id: data.creatorId, - creator: data.creator, - created_at: data.createdAt, - updated_at: data.updatedAt, - source_guild_id: data.sourceGuildId, - serialized_source_guild: data.serializedSourceGuild, - is_dirty: data.isDirty, - }); + return await bot.rest.runMethod( + bot.rest, + "post", + bot.constants.endpoints.GUILD_TEMPLATES(guildId), + data, + ); } -export interface Template { - /** The template code (unique Id) */ - code: string; - /** Template name */ +export interface CreateTemplate { + /** Name which the template should have */ name: string; - /** The description for the template */ - description: string; - /** Number of times this template has been used */ - usageCount: number; - /** The Id of the user who created the template */ - creatorId: string; - /** The user who created the template */ - creator: User; - /** When this template was created */ - createdAt: string; - /** When this template was last synced to the source guild */ - updatedAt: string; - /** The Id of the guild this template is based on */ - sourceGuildId: string; - /** The guild snapshot this template contains */ - serializedSourceGuild: Partial; - /** Whether the template has unsynced changes */ - isDirty: boolean; + /** Description of the template */ + description?: string; } diff --git a/helpers/templates/getGuildTemplates.ts b/helpers/templates/getGuildTemplates.ts index cde995bdd..da086f687 100644 --- a/helpers/templates/getGuildTemplates.ts +++ b/helpers/templates/getGuildTemplates.ts @@ -10,5 +10,5 @@ export async function getGuildTemplates(bot: Bot, guildId: bigint) { bot.constants.endpoints.GUILD_TEMPLATES(guildId), ); - return new Collection(templates.map((template) => [template.code, template])); + return new Collection(templates.map((template) => [template.code, bot.transformers.template(bot, template)])); } diff --git a/helpers/templates/getTemplate.ts b/helpers/templates/getTemplate.ts index 785fefc9c..1389fbb67 100644 --- a/helpers/templates/getTemplate.ts +++ b/helpers/templates/getTemplate.ts @@ -3,9 +3,11 @@ import { DiscordTemplate } from "../../types/discord.ts"; /** Returns the guild template if it exists */ export async function getTemplate(bot: Bot, templateCode: string) { - return await bot.rest.runMethod( + const result = await bot.rest.runMethod( bot.rest, "get", bot.constants.endpoints.GUILD_TEMPLATE(templateCode), ); + + return bot.transformers.template(bot, result); } diff --git a/transformers/mod.ts b/transformers/mod.ts index 38c514967..fd52050d9 100644 --- a/transformers/mod.ts +++ b/transformers/mod.ts @@ -30,3 +30,4 @@ export * from "./voiceState.ts"; export * from "./webhook.ts"; export * from "./welcomeScreen.ts"; export * from "./widget.ts"; +export * from "./template.ts"; diff --git a/transformers/template.ts b/transformers/template.ts new file mode 100644 index 000000000..af76569b1 --- /dev/null +++ b/transformers/template.ts @@ -0,0 +1,23 @@ +import { Bot } from "../bot.ts"; +import { DiscordTemplate } from "../types/discord.ts"; +import { Optionalize } from "../types/shared.ts"; + +export function transformTemplate(bot: Bot, payload: DiscordTemplate) { + const template = { + code: payload.code, + name: payload.name, + description: payload.description, + usageCount: payload.usage_count, + creatorId: bot.transformers.snowflake(payload.creator_id), + creator: bot.transformers.user(bot, payload.creator), + createdAt: Date.parse(payload.created_at), + updatedAt: Date.parse(payload.updated_at), + sourceGuildId: bot.transformers.snowflake(payload.source_guild_id), + serializedSourceGuild: payload.serialized_source_guild, + isDirty: payload.is_dirty ?? undefined, + }; + + return template as Optionalize; +} + +export interface Template extends ReturnType {} diff --git a/types/discord.ts b/types/discord.ts index 89a899ff6..b8a65445f 100644 --- a/types/discord.ts +++ b/types/discord.ts @@ -21,6 +21,7 @@ import { MessageTypes, MfaLevels, OverwriteTypes, + PickPartial, PremiumTiers, PremiumTypes, ScheduledEventEntityType, @@ -2000,7 +2001,36 @@ export interface DiscordTemplate { /** The Id of the guild this template is based on */ source_guild_id: string; /** The guild snapshot this template contains */ - serialized_source_guild: Partial; + serialized_source_guild: + & Omit< + PickPartial< + DiscordGuild, + | "name" + | "description" + | "verification_level" + | "default_message_notifications" + | "explicit_content_filter" + | "preferred_locale" + | "afk_timeout" + | "channels" + | "afk_channel_id" + | "system_channel_id" + | "system_channel_flags" + >, + "roles" + > + & { + roles: ( + & Omit< + PickPartial< + DiscordRole, + "name" | "color" | "hoist" | "mentionable" | "permissions" | "icon" | "unicode_emoji" + >, + "id" + > + & { id: number } + )[]; + }; /** Whether the template has unsynced changes */ is_dirty: boolean | null; } diff --git a/types/shared.ts b/types/shared.ts index 522d5bea5..e3c331d56 100644 --- a/types/shared.ts +++ b/types/shared.ts @@ -1335,3 +1335,9 @@ export type Optionalize = } > : T; + +export type PickPartial = + & { + [P in keyof T]?: T[P] | undefined; + } + & { [P in K]: T[P] };