add: stage instances (#924)

* feat: implement stage instances

Reference: https://github.com/discord/discord-api-docs/pull/2898

* feat: implement stage instances

* Update src/types/misc/stage_instance.ts

Co-authored-by: ITOH <to@itoh.at>

* Update src/helpers/misc/delete_stage_instance.ts

Co-authored-by: ITOH <to@itoh.at>

* Update src/types/misc/stage_instance.ts

Co-authored-by: ITOH <to@itoh.at>

* Move stage instances related modules to channels module

* Move to channels

* Move to channels

* Add permission checks

* Add permissions checl

* Ad inhibitors

* style: fix lint warnings

* Do not throw & add import type

Co-authored-by: ITOH <to@itoh.at>
This commit is contained in:
rigormorrtiss
2021-05-12 17:57:45 +04:00
committed by GitHub
parent 911f4322b0
commit 275d17c6fe
9 changed files with 163 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
import { validateLength } from "../../util/validate_length.ts";
import { Errors } from "../../types/discordeno/errors.ts";
import { rest } from "../../rest/rest.ts";
import { endpoints } from "../../util/constants.ts";
import type { StageInstance } from "../../types/channels/stage_instance.ts";
import { cacheHandlers } from "../../cache.ts";
import { ChannelTypes } from "../../types/channels/channel_types.ts";
import { requireBotChannelPermissions } from "../../util/permissions.ts";
/** Creates a new Stage instance associated to a Stage channel. Requires the user to be a moderator of the Stage channel. */
export async function createStageInstance(channelId: bigint, topic: string) {
const channel = await cacheHandlers.get("channels", channelId);
if (channel) {
if (channel.type !== ChannelTypes.GuildStageVoice) {
throw new Error(Errors.CHANNEL_NOT_STAGE_VOICE);
}
await requireBotChannelPermissions(channel, [
"MANAGE_CHANNELS",
"MUTE_MEMBERS",
"MOVE_MEMBERS",
]);
}
if (
!validateLength(topic, { max: 120, min: 1 })
) {
throw new Error(Errors.INVALID_TOPIC_LENGTH);
}
return await rest.runMethod<StageInstance>(
"post",
endpoints.STAGE_INSTANCES,
{
"channel_id": channelId,
topic,
},
);
}

View File

@@ -0,0 +1,28 @@
import { cacheHandlers } from "../../cache.ts";
import { rest } from "../../rest/rest.ts";
import { ChannelTypes } from "../../types/channels/channel_types.ts";
import { Errors } from "../../types/discordeno/errors.ts";
import { endpoints } from "../../util/constants.ts";
import { requireBotChannelPermissions } from "../../util/permissions.ts";
/** Deletes the Stage instance. Requires the user to be a moderator of the Stage channel. */
export async function deleteStageInstance(channelId: bigint) {
const channel = await cacheHandlers.get("channels", channelId);
if (channel) {
if (channel.type !== ChannelTypes.GuildStageVoice) {
throw new Error(Errors.CHANNEL_NOT_STAGE_VOICE);
}
await requireBotChannelPermissions(channel, [
"MUTE_MEMBERS",
"MANAGE_CHANNELS",
"MOVE_MEMBERS",
]);
}
return await rest.runMethod<undefined>(
"delete",
endpoints.STAGE_INSTANCE(channelId),
);
}

View File

@@ -0,0 +1,22 @@
import { cacheHandlers } from "../../cache.ts";
import { rest } from "../../rest/rest.ts";
import { ChannelTypes } from "../../types/channels/channel_types.ts";
import type { StageInstance } from "../../types/channels/stage_instance.ts";
import { Errors } from "../../types/discordeno/errors.ts";
import { endpoints } from "../../util/constants.ts";
/** Gets the stage instance associated with the Stage channel, if it exists. */
export async function getStageInstance(channelId: bigint) {
const channel = await cacheHandlers.get("channels", channelId);
if (channel) {
if (channel.type !== ChannelTypes.GuildStageVoice) {
throw new Error(Errors.CHANNEL_NOT_STAGE_VOICE);
}
}
return await rest.runMethod<StageInstance>(
"get",
endpoints.STAGE_INSTANCE(channelId),
);
}

View File

@@ -0,0 +1,42 @@
import { rest } from "../../rest/rest.ts";
import { Errors } from "../../types/discordeno/errors.ts";
import type { StageInstance } from "../../types/channels/stage_instance.ts";
import { endpoints } from "../../util/constants.ts";
import { validateLength } from "../../util/validate_length.ts";
import { cacheHandlers } from "../../cache.ts";
import { requireBotChannelPermissions } from "../../util/permissions.ts";
import { ChannelTypes } from "../../types/channels/channel_types.ts";
/** Updates fields of an existing Stage instance. Requires the user to be a moderator of the Stage channel. */
export async function updateStageInstance(channelId: bigint, topic: string) {
const channel = await cacheHandlers.get("channels", channelId);
if (channel) {
if (channel.type !== ChannelTypes.GuildStageVoice) {
throw new Error(Errors.CHANNEL_NOT_STAGE_VOICE);
}
await requireBotChannelPermissions(channel, [
"MOVE_MEMBERS",
"MUTE_MEMBERS",
"MANAGE_CHANNELS",
]);
}
if (
!validateLength(topic, {
min: 1,
max: 120,
})
) {
throw new Error(Errors.INVALID_TOPIC_LENGTH);
}
return await rest.runMethod<StageInstance>(
"patch",
endpoints.STAGE_INSTANCE(channelId),
{
topic,
},
);
}

View File

@@ -128,6 +128,10 @@ import { getWebhooks } from "./webhooks/get_webhooks.ts";
import { getWebhookMessage } from "./webhooks/get_webhook_message.ts";
import { getWebhookWithToken } from "./webhooks/get_webhook_with_token.ts";
import { sendWebhook } from "./webhooks/send_webhook.ts";
import { createStageInstance } from "./channels/create_stage_instance.ts";
import { updateStageInstance } from "./channels/update_stage_instance.ts";
import { getStageInstance } from "./channels/get_stage_instance.ts";
import { deleteStageInstance } from "./channels/delete_stage_instance.ts";
export {
addDiscoverySubcategory,
@@ -148,6 +152,7 @@ export {
createInvite,
createRole,
createSlashCommand,
createStageInstance,
createWebhook,
deleteChannel,
deleteChannelOverwrite,
@@ -161,6 +166,7 @@ export {
deleteRole,
deleteSlashCommand,
deleteSlashResponse,
deleteStageInstance,
deleteWebhook,
deleteWebhookMessage,
deleteWebhookWithToken,
@@ -217,6 +223,7 @@ export {
getSlashCommandPermission,
getSlashCommandPermissions,
getSlashCommands,
getStageInstance,
getTemplate,
getUser,
getVanityURL,
@@ -260,6 +267,7 @@ export {
unpin,
unpinMessage,
updateBotVoiceState,
updateStageInstance,
upsertSlashCommand,
upsertSlashCommands,
validDiscoveryTerm,
@@ -282,6 +290,10 @@ export let helpers = {
startTyping,
swapChannels,
updateBotVoiceState,
createStageInstance,
getStageInstance,
updateStageInstance,
deleteStageInstance,
// commands
createSlashCommand,
deleteSlashCommand,

View File

@@ -0,0 +1,11 @@
// TODO: add resource link
export interface StageInstance {
/** The id of this Stage instance */
id: string;
/** The guild id of the associated Stage channel */
guildId: string;
/** The id of the associated Stage channel */
channelId: string;
/** The topic of the Stage instance (1-120 characters) */
topic: string;
}

View File

@@ -5,9 +5,11 @@ export enum Errors {
CHANNEL_NOT_FOUND = "CHANNEL_NOT_FOUND",
CHANNEL_NOT_IN_GUILD = "CHANNEL_NOT_IN_GUILD",
CHANNEL_NOT_TEXT_BASED = "CHANNEL_NOT_TEXT_BASED",
CHANNEL_NOT_STAGE_VOICE = "CHANNEL_NOT_STAGE_VOICE",
MESSAGE_MAX_LENGTH = "MESSAGE_MAX_LENGTH",
RULES_CHANNEL_CANNOT_BE_DELETED = "RULES_CHANNEL_CANNOT_BE_DELETED",
UPDATES_CHANNEL_CANNOT_BE_DELETED = "UPDATES_CHANNEL_CANNOT_BE_DELETED",
INVALID_TOPIC_LENGTH = "INVALID_TOPIC_LENGTH",
// Guild Errors
GUILD_NOT_DISCOVERABLE = "GUILD_NOT_DISCOVERABLE",
GUILD_WIDGET_NOT_ENABLED = "GUILD_WIDGET_NOT_ENABLED",

View File

@@ -231,3 +231,4 @@ export * from "./webhooks/execute_webhook.ts";
export * from "./webhooks/modify_webhook.ts";
export * from "./webhooks/webhook.ts";
export * from "./webhooks/webhooks_update.ts";
export * from "./channels/stage_instance.ts";

View File

@@ -226,6 +226,11 @@ export const endpoints = {
// OAuth2
OAUTH2_APPLICATION: `${baseEndpoints.BASE_URL}/oauth2/applications/@me`,
// Stage instances
STAGE_INSTANCES: `${baseEndpoints.BASE_URL}/stage-instances`,
STAGE_INSTANCE: (channelId: bigint) =>
`${baseEndpoints.BASE_URL}/stage-instances/${channelId}`,
};
export const SLASH_COMMANDS_NAME_REGEX = /^[\w-]{1,32}$/;