import type { NextApiRequest, NextApiResponse } from "next"; import { z } from "zod"; import logger from "@calcom/lib/logger"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; import prisma from "@calcom/prisma"; import { getAppKeys } from "../common"; import { sendPostMsg } from "../lib/BotService"; const log = logger.getChildLogger({ prefix: [`[lark/api/events]`] }); const larkKeysSchema = z.object({ open_verification_token: z.string(), }); const appTicketEventsReqSchema = z.object({ body: z.object({ event: z.object({ app_ticket: z.string().min(1), }), }), }); const imMessageReceivedEventsReqSchema = z.object({ body: z.object({ header: z.object({ tenant_key: z.string().min(1), }), event: z.object({ sender: z.object({ sender_id: z.object({ open_id: z.string().min(1), }), }), }), }), }); const p2pChatCreateEventsReqSchema = z.object({ body: z.object({ tenant_key: z.string().min(1), event: z.object({ user: z.object({ open_id: z.string().min(1), }), }), }), }); async function postHandler(req: NextApiRequest, res: NextApiResponse) { log.debug("receive events", req.body); const appKeys = await getAppKeys(); const { open_verification_token } = larkKeysSchema.parse(appKeys); // used for events handler binding in lark open platform, see // https://open.larksuite.com/document/ukTMukTMukTM/uUTNz4SN1MjL1UzM?lang=en-US if (req.body.type === "url_verification") { return res.status(200).json({ challenge: req.body.challenge }); } // used for receiving app_ticket, see // https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/application-v6/event/app_ticket-events if (req.body.event?.type === "app_ticket" && open_verification_token === req.body.token) { const { body: { event: { app_ticket: appTicket }, }, } = appTicketEventsReqSchema.parse(req); await prisma.app.update({ where: { slug: "lark-calendar" }, data: { keys: { ...appKeys, app_ticket: appTicket, }, }, }); return res.status(200).json({ code: 0, msg: "success" }); } // used for handle user at bot in lark chat with cal.com connector bot, see // https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/events/receive if (req.body.header?.event_type === "im.message.receive_v1") { const { body: { header: { tenant_key: tenantKey }, event: { sender: { sender_id: { open_id: senderOpenId }, }, }, }, } = imMessageReceivedEventsReqSchema.parse(req); sendPostMsg(tenantKey, senderOpenId); return res.status(200).json({ code: 0, msg: "success" }); } // used for handle user first talk with cal.com connector bot, see // https://open.larksuite.com/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/bot-events if (req.body.event?.type === "p2p_chat_create") { const { body: { tenant_key: tenantKey, event: { user: { open_id: senderOpenId }, }, }, } = p2pChatCreateEventsReqSchema.parse(req); sendPostMsg(tenantKey, senderOpenId); return res.status(200).json({ code: 0, msg: "success" }); } } export default defaultHandler({ POST: Promise.resolve({ default: defaultResponder(postHandler) }), });