feat(bot,rest,types): Add support for guild onboarding (#3260)

* Add types from api-docs-commit related to #2930

* Add rest from api-docs-commit related to #2930

* Add types from api-docs-commit related to #3072

* Add rest from api-docs-commit related to #3072

* Add types from api-docs-commit related to #3247

* Add transformers and helpers
This commit is contained in:
Fleny
2023-12-04 23:16:33 +01:00
committed by GitHub
parent e47242a9e0
commit fb947f5672
10 changed files with 309 additions and 2 deletions

View File

@@ -48,6 +48,7 @@ import type {
EditAutoModerationRuleOptions,
EditBotMemberOptions,
EditChannelPermissionOverridesOptions,
EditGuildOnboarding,
EditGuildRole,
EditGuildStickerOptions,
EditMessage,
@@ -99,6 +100,7 @@ import type { Integration } from './transformers/integration.js'
import type { Invite } from './transformers/invite.js'
import type { Member } from './transformers/member.js'
import type { Message } from './transformers/message.js'
import type { GuildOnboarding } from './transformers/onboarding.js'
import type { Role } from './transformers/role.js'
import type { ScheduledEvent } from './transformers/scheduledEvent.js'
import type { StageInstance } from './transformers/stageInstance.js'
@@ -678,6 +680,12 @@ export function createBotHelpers(bot: Bot): BotHelpers {
unpinMessage: async (channelId, messageId, reason) => {
return await bot.rest.unpinMessage(channelId, messageId, reason)
},
getGuildOnboarding: async (guildId) => {
return bot.transformers.guildOnboarding(bot, snakelize(await bot.rest.getGuildOnboarding(guildId)))
},
editGuildOnboarding: async (guildId, options, reason) => {
return bot.transformers.guildOnboarding(bot, snakelize(await bot.rest.editGuildOnboarding(guildId, options, reason)))
},
}
}
@@ -895,4 +903,6 @@ export interface BotHelpers {
pinMessage: (channelId: BigString, messageId: BigString, reason?: string) => Promise<void>
unbanMember: (guildId: BigString, userId: BigString, reason?: string) => Promise<void>
unpinMessage: (channelId: BigString, messageId: BigString, reason?: string) => Promise<void>
getGuildOnboarding: (guildId: BigString) => Promise<GuildOnboarding>
editGuildOnboarding: (guildId: BigString, options: EditGuildOnboarding, reason?: string) => Promise<GuildOnboarding>
}

View File

@@ -19,6 +19,7 @@ import type {
DiscordGetGatewayBot,
DiscordGuild,
DiscordGuildApplicationCommandPermissions,
DiscordGuildOnboarding,
DiscordGuildWidget,
DiscordGuildWidgetSettings,
DiscordIntegrationCreateUpdate,
@@ -80,6 +81,7 @@ import { transformInteraction, transformInteractionDataOption, type Interaction,
import { transformInvite, type Invite } from './transformers/invite.js'
import { transformMember, type Member } from './transformers/member.js'
import { transformMessage, type Message } from './transformers/message.js'
import { transformGuildOnboarding, type GuildOnboarding } from './transformers/onboarding.js'
import { transformPresence, type PresenceUpdate } from './transformers/presence.js'
import { transformAllowedMentionsToDiscordAllowedMentions } from './transformers/reverse/allowedMentions.js'
import { transformCreateApplicationCommandToDiscordCreateApplicationCommand } from './transformers/reverse/createApplicationCommand.js'
@@ -156,6 +158,7 @@ export interface Transformers {
applicationCommandOptionChoice: ApplicationCommandOptionChoice,
) => any
template: (bot: Bot, payload: DiscordTemplate, template: Template) => any
guildOnboarding: (bot: Bot, payload: DiscordGuildOnboarding, onboarding: GuildOnboarding) => any
}
desiredProperties: {
attachment: {
@@ -447,6 +450,28 @@ export interface Transformers {
sourceChannel: boolean
url: boolean
}
guildOnboarding: {
guildId: boolean
prompts: {
id: boolean
type: boolean
options: {
id: boolean
channelIds: boolean
roleIds: boolean
emoji: boolean
title: boolean
description: boolean
}
title: boolean
singleSelect: boolean
required: boolean
inOnboarding: boolean
}
defaultChannelIds: boolean
enabled: boolean
mode: boolean
}
}
reverse: {
allowedMentions: (bot: Bot, payload: AllowedMentions) => DiscordAllowedMentions
@@ -507,6 +532,7 @@ export interface Transformers {
stickerPack: (bot: Bot, payload: DiscordStickerPack) => StickerPack
applicationCommandOptionChoice: (bot: Bot, payload: DiscordApplicationCommandOptionChoice) => ApplicationCommandOptionChoice
template: (bot: Bot, payload: DiscordTemplate) => Template
guildOnboarding: (bot: Bot, payload: DiscordGuildOnboarding) => GuildOnboarding
}
export interface CreateTransformerOptions {
@@ -645,6 +671,9 @@ export function createTransformers(options: Partial<Transformers>, opts?: Create
widgetSettings(bot, payload, widgetSettings) {
return widgetSettings
},
guildOnboarding(bot, payload, onboarding) {
return onboarding
},
},
desiredProperties: {
attachment: {
@@ -936,6 +965,28 @@ export function createTransformers(options: Partial<Transformers>, opts?: Create
sourceChannel: opts?.defaultDesiredPropertiesValue ?? false,
url: opts?.defaultDesiredPropertiesValue ?? false,
},
guildOnboarding: {
defaultChannelIds: opts?.defaultDesiredPropertiesValue ?? false,
enabled: opts?.defaultDesiredPropertiesValue ?? false,
guildId: opts?.defaultDesiredPropertiesValue ?? false,
mode: opts?.defaultDesiredPropertiesValue ?? false,
prompts: {
id: opts?.defaultDesiredPropertiesValue ?? false,
inOnboarding: opts?.defaultDesiredPropertiesValue ?? false,
options: {
channelIds: opts?.defaultDesiredPropertiesValue ?? false,
description: opts?.defaultDesiredPropertiesValue ?? false,
emoji: opts?.defaultDesiredPropertiesValue ?? false,
id: opts?.defaultDesiredPropertiesValue ?? false,
roleIds: opts?.defaultDesiredPropertiesValue ?? false,
title: opts?.defaultDesiredPropertiesValue ?? false,
},
required: opts?.defaultDesiredPropertiesValue ?? false,
singleSelect: opts?.defaultDesiredPropertiesValue ?? false,
title: opts?.defaultDesiredPropertiesValue ?? false,
type: opts?.defaultDesiredPropertiesValue ?? false,
},
},
},
reverse: {
allowedMentions: options.reverse?.allowedMentions ?? transformAllowedMentionsToDiscordAllowedMentions,
@@ -996,5 +1047,6 @@ export function createTransformers(options: Partial<Transformers>, opts?: Create
gatewayBot: options.gatewayBot ?? transformGatewayBot,
applicationCommandOptionChoice: options.applicationCommandOptionChoice ?? transformApplicationCommandOptionChoice,
template: options.template ?? transformTemplate,
guildOnboarding: options.guildOnboarding ?? transformGuildOnboarding,
}
}

View File

@@ -0,0 +1,96 @@
import type {
DiscordGuildOnboarding,
DiscordGuildOnboardingMode,
DiscordGuildOnboardingPrompt,
DiscordGuildOnboardingPromptOption,
DiscordGuildOnboardingPromptType,
} from '@discordeno/types'
import { type Bot, type Emoji } from '../index.js'
export function transformGuildOnboarding(bot: Bot, payload: DiscordGuildOnboarding): GuildOnboarding {
const props = bot.transformers.desiredProperties.guildOnboarding
const guildOnboarding = {} as GuildOnboarding
if (props.guildId && payload.guild_id) guildOnboarding.guildId = bot.transformers.snowflake(payload.guild_id)
if (props.defaultChannelIds && payload.default_channel_ids)
guildOnboarding.defaultChannelIds = payload.default_channel_ids.map(bot.transformers.snowflake)
if (props.enabled) guildOnboarding.enabled = payload.enabled
if (props.mode) guildOnboarding.mode = payload.mode
if (payload.prompts) guildOnboarding.prompts = payload.prompts.map((prompt) => transformGuildOnboardingPrompt(bot, prompt))
return bot.transformers.customizers.guildOnboarding(bot, payload, guildOnboarding)
}
export function transformGuildOnboardingPrompt(bot: Bot, payload: DiscordGuildOnboardingPrompt): GuildOnboardingPrompt {
const props = bot.transformers.desiredProperties.guildOnboarding.prompts
const prompt = {} as GuildOnboardingPrompt
if (props.id && payload.id) prompt.id = bot.transformers.snowflake(prompt.id)
if (props.inOnboarding && payload.in_onboarding) prompt.inOnboarding = payload.in_onboarding
if (props.required && payload.required) prompt.required = payload.required
if (props.singleSelect && payload.single_select) prompt.singleSelect = payload.single_select
if (props.title && payload.title) prompt.title = payload.title
if (props.type) prompt.type = payload.type
if (payload.options) prompt.options = payload.options.map((option) => transformGuildOnboardingPromptOption(bot, option))
return prompt
}
export function transformGuildOnboardingPromptOption(bot: Bot, payload: DiscordGuildOnboardingPromptOption): GuildOnboardingPromptOption {
const props = bot.transformers.desiredProperties.guildOnboarding.prompts.options
const option = {} as GuildOnboardingPromptOption
if (props.id && payload.id) option.id = bot.transformers.snowflake(payload.id)
if (props.channelIds && payload.channel_ids) option.channelIds = payload.channel_ids.map(bot.transformers.snowflake)
if (props.roleIds && payload.role_ids) option.roleIds = payload.role_ids.map(bot.transformers.snowflake)
if (props.emoji && payload.emoji) option.emoji = bot.transformers.emoji(bot, payload.emoji)
if (props.title && payload.title) option.title = payload.title
if (props.description && payload.description) option.description = payload.description
return option
}
export interface GuildOnboarding {
/** ID of the guild this onboarding is part of */
guildId: bigint
/** Prompts shown during onboarding and in customize community */
prompts: GuildOnboardingPrompt[]
/** Channel IDs that members get opted into automatically */
defaultChannelIds: bigint[]
/** Whether onboarding is enabled in the guild */
enabled: boolean
/** Current mode of onboarding */
mode: DiscordGuildOnboardingMode
}
export interface GuildOnboardingPrompt {
/** ID of the prompt */
id: bigint
/** Type of prompt */
type: DiscordGuildOnboardingPromptType
/** Options available within the prompt */
options: GuildOnboardingPromptOption[]
/** Title of the prompt */
title: string
/** Indicates whether users are limited to selecting one option for the prompt */
singleSelect: boolean
/** Indicates whether the prompt is required before a user completes the onboarding flow */
required: boolean
/** Indicates whether the prompt is present in the onboarding flow. If `false`, the prompt will only appear in the Channels & Roles tab */
inOnboarding: boolean
}
export interface GuildOnboardingPromptOption {
/** ID of the prompt option */
id: bigint
/** IDs for channels a member is added to when the option is selected */
channelIds: bigint[]
/** IDs for roles assigned to a member when the option is selected */
roleIds: bigint[]
/** Emoji of the option */
emoji: Emoji
/** Title of the option */
title: string
/** Description of the option */
description: string | undefined
}

View File

@@ -26,6 +26,7 @@ import {
type DiscordGetGatewayBot,
type DiscordGuild,
type DiscordGuildApplicationCommandPermissions,
type DiscordGuildOnboarding,
type DiscordGuildPreview,
type DiscordGuildWidget,
type DiscordGuildWidgetSettings,
@@ -1387,6 +1388,17 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordMemberWithUser[]>(rest.routes.guilds.members.search(guildId, query, options))
},
async getGuildOnboarding(guildId) {
return await rest.get<DiscordGuildOnboarding>(rest.routes.guilds.onboarding(guildId))
},
async editGuildOnboarding(guildId, options, reason) {
return await rest.put<DiscordGuildOnboarding>(rest.routes.guilds.onboarding(guildId), {
body: options,
reason,
})
},
async unbanMember(guildId, userId, reason) {
await rest.delete(rest.routes.guilds.members.ban(guildId, userId), { reason })
},

View File

@@ -490,6 +490,9 @@ export function createRoutes(): RestRoutes {
widgetJson: (guildId) => {
return `/guilds/${guildId}/widget.json`
},
onboarding: (guildId) => {
return `/guilds/${guildId}/onboarding`
},
},
sticker: (stickerId) => {

View File

@@ -23,6 +23,7 @@ import type {
CamelizedDiscordGetGatewayBot,
CamelizedDiscordGuild,
CamelizedDiscordGuildApplicationCommandPermissions,
CamelizedDiscordGuildOnboarding,
CamelizedDiscordGuildPreview,
CamelizedDiscordGuildWidget,
CamelizedDiscordGuildWidgetSettings,
@@ -70,6 +71,7 @@ import type {
EditAutoModerationRuleOptions,
EditBotMemberOptions,
EditChannelPermissionOverridesOptions,
EditGuildOnboarding,
EditGuildRole,
EditGuildStickerOptions,
EditMessage,
@@ -2759,6 +2761,28 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/resources/channel#unpin-message}
*/
unpinMessage: (channelId: BigString, messageId: BigString, reason?: string) => Promise<void>
/**
* Get the guild onboarding
*
* @param guildId - The guild to get the onboarding from
*/
getGuildOnboarding: (guildId: BigString) => Promise<CamelizedDiscordGuildOnboarding>
/**
* Modifies the onboarding configuration of the guild.
*
* @param guildId - The guild to get the onboarding from
* @param {string} [reason] - An optional reason for the action, to be included in the audit log.
*
* @remarks
* Requires the `MANAGE_GUILD` and `MANAGE_ROLES` permissions.
*
* Onboarding enforces constraints when enabled. These constraints are:
* - at least 7 default channels
* - at least 5 of the 7 channels must allow sending messages to the @everyone role
*
* The `mode` field modifies what is considered when enforcing these constraints.
*/
editGuildOnboarding: (guildId: BigString, options: EditGuildOnboarding, reason?: string) => Promise<CamelizedDiscordGuildOnboarding>
}
export type RequestMethods = 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT'

View File

@@ -206,6 +206,8 @@ export interface RestRoutes {
sticker: (guildId: BigString, stickerId: BigString) => string
/** Route for handling a voice state. */
voice: (guildId: BigString, userId?: BigString) => string
/** Route for the onboarding */
onboarding: (guildId: BigString) => string
}
/** Routes for interaction related endpoints. */
interactions: {

View File

@@ -64,8 +64,11 @@ import type {
DiscordGuildIntegrationsUpdate,
DiscordGuildMemberAdd,
DiscordGuildMemberRemove,
DiscordGuildMembersChunk,
DiscordGuildMemberUpdate,
DiscordGuildMembersChunk,
DiscordGuildOnboarding,
DiscordGuildOnboardingPrompt,
DiscordGuildOnboardingPromptOption,
DiscordGuildPreview,
DiscordGuildRoleCreate,
DiscordGuildRoleDelete,
@@ -136,8 +139,8 @@ import type {
DiscordTemplate,
DiscordThreadListSync,
DiscordThreadMember,
DiscordThreadMembersUpdate,
DiscordThreadMemberUpdate,
DiscordThreadMembersUpdate,
DiscordThreadMetadata,
DiscordTokenExchange,
DiscordTokenExchangeAuthorizationCode,
@@ -314,3 +317,6 @@ export type CamelizedDiscordArchivedThreads = Camelize<DiscordArchivedThreads>
export interface CamelizedDiscordActiveThreads extends Camelize<DiscordActiveThreads> {}
export interface CamelizedDiscordVanityUrl extends Camelize<DiscordVanityUrl> {}
export interface CamelizedDiscordPrunedCount extends Camelize<DiscordPrunedCount> {}
export interface CamelizedDiscordGuildOnboarding extends Camelize<DiscordGuildOnboarding> {}
export interface CamelizedDiscordGuildOnboardingPrompt extends Camelize<DiscordGuildOnboardingPrompt> {}
export interface CamelizedDiscordGuildOnboardingOption extends Camelize<DiscordGuildOnboardingPromptOption> {}

View File

@@ -2920,3 +2920,91 @@ export interface DiscordVanityUrl {
export interface DiscordPrunedCount {
pruned: number
}
/** https://discord.com/developers/docs/resources/guild#guild-onboarding-object-guild-onboarding-structure */
export interface DiscordGuildOnboarding {
/** ID of the guild this onboarding is part of */
guild_id: string
/** Prompts shown during onboarding and in customize community */
prompts: DiscordGuildOnboardingPrompt[]
/** Channel IDs that members get opted into automatically */
default_channel_ids: string[]
/** Whether onboarding is enabled in the guild */
enabled: boolean
/** Current mode of onboarding */
mode: DiscordGuildOnboardingMode
}
/** https://discord.com/developers/docs/resources/guild#guild-onboarding-object-onboarding-prompt-structure */
export interface DiscordGuildOnboardingPrompt {
/** ID of the prompt */
id: string
/** Type of prompt */
type: DiscordGuildOnboardingPromptType
/** Options available within the prompt */
options: DiscordGuildOnboardingPromptOption[]
/** Title of the prompt */
title: string
/** Indicates whether users are limited to selecting one option for the prompt */
single_select: boolean
/** Indicates whether the prompt is required before a user completes the onboarding flow */
required: boolean
/** Indicates whether the prompt is present in the onboarding flow. If `false`, the prompt will only appear in the Channels & Roles tab */
in_onboarding: boolean
}
/** https://discord.com/developers/docs/resources/guild#guild-onboarding-object-prompt-option-structure */
export interface DiscordGuildOnboardingPromptOption {
/** ID of the prompt option */
id: string
/** IDs for channels a member is added to when the option is selected */
channel_ids: string[]
/** IDs for roles assigned to a member when the option is selected */
role_ids: string[]
/**
* Emoji of the option
*
* @remarks
* When creating or updating a prompt option, the `emoji_id`, `emoji_name`, and `emoji_animated` fields must be used instead of the emoji object.
*/
emoji?: DiscordEmoji
/**
* Emoji ID of the option
*
* @remarks
* When creating or updating a prompt option, the `emoji_id`, `emoji_name`, and `emoji_animated` fields must be used instead of the emoji object.
*/
emoji_id?: string
/**
* Emoji name of the option
*
* @remarks
* When creating or updating a prompt option, the `emoji_id`, `emoji_name`, and `emoji_animated` fields must be used instead of the emoji object.
*/
emoji_name?: string
/**
* Whether the emoji is animated
*
* @remarks
* When creating or updating a prompt option, the `emoji_id`, `emoji_name`, and `emoji_animated` fields must be used instead of the emoji object.
*/
emoji_animated?: boolean
/** Title of the option */
title: string
/** Description of the option */
description: string | undefined
}
/** https://discord.com/developers/docs/resources/guild#guild-onboarding-object-prompt-types */
export enum DiscordGuildOnboardingPromptType {
MultipleChoice,
DropDown,
}
/** https://discord.com/developers/docs/resources/guild#guild-onboarding-object-onboarding-mode */
export enum DiscordGuildOnboardingMode {
/** Counts only Default Channels towards constraints */
OnboardingDefault,
/** Counts Default Channels and Questions towards constraints */
OnboardingAdvanced,
}

View File

@@ -8,6 +8,8 @@ import type {
DiscordAutoModerationRuleTriggerMetadataPresets,
DiscordChannel,
DiscordEmbed,
DiscordGuildOnboardingMode,
DiscordGuildOnboardingPrompt,
DiscordRole,
} from './discord.js'
import type {
@@ -1188,3 +1190,15 @@ export interface BeginGuildPrune {
/** Role(s) ro include, default: none */
includeRoles?: string[]
}
/** https://discord.com/developers/docs/resources/guild#modify-guild-onboarding-json-params */
export interface EditGuildOnboarding {
/** Prompts shown during onboarding and in customize community */
prompts: Array<Camelize<DiscordGuildOnboardingPrompt>>
/** Channel IDs that members get opted into automatically */
defaultChannelIds: BigString[]
/** Whether onboarding is enabled in the guild */
enabled: boolean
/** Current mode of onboarding */
mode: DiscordGuildOnboardingMode
}