fix: interaction callback
This commit is contained in:
parent
d0ae4d06bc
commit
bbd0617d53
@ -32,7 +32,7 @@ export const NO_AUTHORIZATION_ROUTES = [
|
|||||||
"GET /invites/",
|
"GET /invites/",
|
||||||
// Routes with a seperate auth system
|
// Routes with a seperate auth system
|
||||||
/^(POST|HEAD|GET|PATCH|DELETE) \/webhooks\/\d+\/\w+\/?/, // no token requires auth
|
/^(POST|HEAD|GET|PATCH|DELETE) \/webhooks\/\d+\/\w+\/?/, // no token requires auth
|
||||||
// /^POST \/interactions\/\d+\/\w+\/callback/, // This is marked as Unauthoricated route on https://discord.food. But when it is then not all requests have req.user_id?
|
/^POST \/interactions\/\d+\/[A-Za-z0-9_-]+\/callback/,
|
||||||
// Public information endpoints
|
// Public information endpoints
|
||||||
"GET /ping",
|
"GET /ping",
|
||||||
"GET /gateway",
|
"GET /gateway",
|
||||||
|
|||||||
@ -55,13 +55,13 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
|||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
case InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE: {
|
case InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE: {
|
||||||
const message = Message.create({
|
const message = await Message.createWithDefaults({
|
||||||
type: MessageType.APPLICATION_COMMAND,
|
type: MessageType.APPLICATION_COMMAND,
|
||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
application_id: req.user_id,
|
application_id: interaction.applicationId,
|
||||||
guild_id: interaction.guildId,
|
guild_id: interaction.guildId,
|
||||||
channel_id: interaction.channelId,
|
channel_id: interaction.channelId,
|
||||||
author_id: req.user_id,
|
author_id: interaction.applicationId,
|
||||||
content: body.data.content,
|
content: body.data.content,
|
||||||
tts: body.data.tts,
|
tts: body.data.tts,
|
||||||
embeds: body.data.embeds || [],
|
embeds: body.data.embeds || [],
|
||||||
@ -69,7 +69,7 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
|||||||
poll: body.data.poll,
|
poll: body.data.poll,
|
||||||
flags: body.data.flags,
|
flags: body.data.flags,
|
||||||
reactions: [],
|
reactions: [],
|
||||||
// webhook_id: req.user_id, // This one requires a webhook to be created first
|
// webhook_id: interaction.applicationId, // This one requires a webhook to be created first
|
||||||
interaction: {
|
interaction: {
|
||||||
id: interactionId,
|
id: interactionId,
|
||||||
name: interaction.commandName,
|
name: interaction.commandName,
|
||||||
@ -98,9 +98,9 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
|||||||
event: "MESSAGE_CREATE",
|
event: "MESSAGE_CREATE",
|
||||||
channel_id: interaction.channelId,
|
channel_id: interaction.channelId,
|
||||||
data: {
|
data: {
|
||||||
application_id: message.application_id,
|
application_id: interaction.applicationId,
|
||||||
attachments: message.attachments,
|
attachments: message.attachments,
|
||||||
author: (await User.findOneOrFail({ where: { id: message.author_id } })).toPublicUser(),
|
author: message.author?.toPublicUser(),
|
||||||
channel_id: message.channel_id,
|
channel_id: message.channel_id,
|
||||||
channel_type: 0,
|
channel_type: 0,
|
||||||
components: message.components,
|
components: message.components,
|
||||||
@ -131,7 +131,7 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
|||||||
timestamp: message.timestamp,
|
timestamp: message.timestamp,
|
||||||
tss: message.tts,
|
tss: message.tts,
|
||||||
type: message.type,
|
type: message.type,
|
||||||
webhook_id: req.user_id,
|
webhook_id: interaction.applicationId,
|
||||||
} as MessageCreateSchema,
|
} as MessageCreateSchema,
|
||||||
} as MessageCreateEvent);
|
} as MessageCreateEvent);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -20,8 +20,9 @@ import { randomBytes } from "crypto";
|
|||||||
import { InteractionSchema } from "@spacebar/schemas";
|
import { InteractionSchema } from "@spacebar/schemas";
|
||||||
import { route } from "@spacebar/api";
|
import { route } from "@spacebar/api";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { emitEvent, InteractionCreateEvent, InteractionFailureEvent, Snowflake } from "@spacebar/util";
|
import { emitEvent, Guild, InteractionCreateEvent, InteractionFailureEvent, InteractionType, Member, Message, Snowflake, User } from "@spacebar/util";
|
||||||
import { pendingInteractions } from "../../../util/imports/Interactions";
|
import { pendingInteractions } from "@spacebar/util/imports/Interactions";
|
||||||
|
import { InteractionCreateSchema } from "@spacebar/schemas/api/bots/InteractionCreateSchema";
|
||||||
|
|
||||||
const router = Router({ mergeParams: true });
|
const router = Router({ mergeParams: true });
|
||||||
|
|
||||||
@ -40,18 +41,56 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
|||||||
},
|
},
|
||||||
} as InteractionCreateEvent);
|
} as InteractionCreateEvent);
|
||||||
|
|
||||||
|
const user = await User.findOneOrFail({ where: { id: req.user_id } });
|
||||||
|
|
||||||
|
const interactionData: Partial<InteractionCreateSchema> = {
|
||||||
|
id: interactionId,
|
||||||
|
application_id: body.application_id,
|
||||||
|
channel_id: body.channel_id,
|
||||||
|
type: body.type,
|
||||||
|
token: interactionToken,
|
||||||
|
version: 1,
|
||||||
|
app_permissions: "0", // TODO: add this later
|
||||||
|
entitlements: [],
|
||||||
|
authorizing_integration_owners: { "0": req.user_id },
|
||||||
|
context: 0, // TODO: add this later
|
||||||
|
attachment_size_limit: 0, // TODO: add this later
|
||||||
|
};
|
||||||
|
|
||||||
|
if (body.type === InteractionType.ApplicationCommand || body.data.type === InteractionType.MessageComponent || body.data.type === InteractionType.ModalSubmit) {
|
||||||
|
interactionData.data = body.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.type != InteractionType.Ping) {
|
||||||
|
interactionData.locale = user?.settings?.locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.guild_id) {
|
||||||
|
interactionData.guild_id = body.guild_id;
|
||||||
|
|
||||||
|
const guild = await Guild.findOneOrFail({ where: { id: body.guild_id } });
|
||||||
|
const member = await Member.findOneOrFail({ where: { guild_id: body.guild_id, id: req.user_id }, relations: ["user"] });
|
||||||
|
|
||||||
|
interactionData.guild = {
|
||||||
|
id: guild.id,
|
||||||
|
features: guild.features,
|
||||||
|
locale: guild.preferred_locale!,
|
||||||
|
};
|
||||||
|
|
||||||
|
interactionData.guild_locale = guild.preferred_locale;
|
||||||
|
interactionData.member = member.toPublicMember();
|
||||||
|
} else {
|
||||||
|
interactionData.user = user.toPublicUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.type === InteractionType.MessageComponent || body.data.type === InteractionType.ModalSubmit) {
|
||||||
|
interactionData.message = await Message.findOneOrFail({ where: { id: body.message_id } });
|
||||||
|
}
|
||||||
|
|
||||||
emitEvent({
|
emitEvent({
|
||||||
event: "INTERACTION_CREATE",
|
event: "INTERACTION_CREATE",
|
||||||
user_id: body.application_id,
|
user_id: body.application_id,
|
||||||
data: {
|
data: interactionData,
|
||||||
channel_id: body.channel_id,
|
|
||||||
guild_id: body.guild_id,
|
|
||||||
id: interactionId,
|
|
||||||
member_id: req.user_id,
|
|
||||||
token: interactionToken,
|
|
||||||
type: body.type,
|
|
||||||
nonce: body.nonce,
|
|
||||||
},
|
|
||||||
} as InteractionCreateEvent);
|
} as InteractionCreateEvent);
|
||||||
|
|
||||||
const interactionTimeout = setTimeout(() => {
|
const interactionTimeout = setTimeout(() => {
|
||||||
@ -69,6 +108,7 @@ router.post("/", route({}), async (req: Request, res: Response) => {
|
|||||||
pendingInteractions.set(interactionId, {
|
pendingInteractions.set(interactionId, {
|
||||||
timeout: interactionTimeout,
|
timeout: interactionTimeout,
|
||||||
nonce: body.nonce,
|
nonce: body.nonce,
|
||||||
|
applicationId: body.application_id,
|
||||||
userId: req.user_id,
|
userId: req.user_id,
|
||||||
guildId: body.guild_id,
|
guildId: body.guild_id,
|
||||||
channelId: body.channel_id,
|
channelId: body.channel_id,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { MessageCreateSchema } from "@spacebar/schemas";
|
import { Message } from "@spacebar/util";
|
||||||
import { InteractionCallbackType } from "./InteractionCallbackType";
|
import { InteractionCallbackType } from "./InteractionCallbackType";
|
||||||
|
|
||||||
export interface InteractionCallbackSchema {
|
export interface InteractionCallbackSchema {
|
||||||
type: InteractionCallbackType;
|
type: InteractionCallbackType;
|
||||||
data: MessageCreateSchema;
|
data: Message;
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/schemas/api/bots/InteractionCreateSchema.ts
Normal file
32
src/schemas/api/bots/InteractionCreateSchema.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { PublicMember, PublicUser, Snowflake } from "@spacebar/schemas";
|
||||||
|
import { Channel, InteractionType, Message } from "@spacebar/util";
|
||||||
|
|
||||||
|
export interface InteractionCreateSchema {
|
||||||
|
version: number; // TODO: types?
|
||||||
|
id: Snowflake;
|
||||||
|
application_id: Snowflake;
|
||||||
|
type: InteractionType;
|
||||||
|
token: string;
|
||||||
|
data?: object; // TODO: types?
|
||||||
|
guild?: InteractionGuild;
|
||||||
|
guild_id?: Snowflake;
|
||||||
|
guild_locale?: string;
|
||||||
|
channel?: Channel; // TODO: is this right?
|
||||||
|
channel_id?: Snowflake;
|
||||||
|
member?: PublicMember; // TODO: is this right?
|
||||||
|
user?: PublicUser; // TODO: is this right?
|
||||||
|
locale?: string;
|
||||||
|
message?: Message; // TODO: is this right?
|
||||||
|
app_permissions: string;
|
||||||
|
entitlements?: object[]; // TODO: types?
|
||||||
|
entitlement_sku_ids?: Snowflake[]; // DEPRECATED
|
||||||
|
authorizing_integration_owners?: Record<number, Snowflake>; // TODO: types?
|
||||||
|
context?: number;
|
||||||
|
attachment_size_limit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InteractionGuild {
|
||||||
|
id: Snowflake;
|
||||||
|
features: string[];
|
||||||
|
locale: string;
|
||||||
|
}
|
||||||
@ -20,6 +20,7 @@ export * from "./ApplicationCommandSchema";
|
|||||||
export * from "./InteractionSchema";
|
export * from "./InteractionSchema";
|
||||||
export * from "./InteractionCallbackSchema";
|
export * from "./InteractionCallbackSchema";
|
||||||
export * from "./InteractionCallbackType";
|
export * from "./InteractionCallbackType";
|
||||||
|
export * from "./InteractionCreateSchema";
|
||||||
export * from "./SendableApplicationCommandDataSchema";
|
export * from "./SendableApplicationCommandDataSchema";
|
||||||
export * from "./SendableMessageComponentDataSchema";
|
export * from "./SendableMessageComponentDataSchema";
|
||||||
export * from "./SendableModalSubmitDataSchema";
|
export * from "./SendableModalSubmitDataSchema";
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import { InteractionType, Snowflake } from "@spacebar/util";
|
|||||||
|
|
||||||
interface PendingInteraction {
|
interface PendingInteraction {
|
||||||
timeout: NodeJS.Timeout;
|
timeout: NodeJS.Timeout;
|
||||||
|
applicationId: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
channelId?: string;
|
channelId?: string;
|
||||||
guildId?: string;
|
guildId?: string;
|
||||||
|
|||||||
@ -30,9 +30,11 @@ export interface Interaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum InteractionType {
|
export enum InteractionType {
|
||||||
SelfCommand = 0,
|
|
||||||
Ping = 1,
|
Ping = 1,
|
||||||
ApplicationCommand = 2,
|
ApplicationCommand = 2,
|
||||||
|
MessageComponent = 3,
|
||||||
|
ApplicationCommandAutocomplete = 4,
|
||||||
|
ModalSubmit = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum InteractionResponseType {
|
export enum InteractionResponseType {
|
||||||
|
|||||||
Reference in New Issue
Block a user