From 9459b9048db6adeeb7b83f2948915300553d4469 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 31 May 2022 18:33:01 +0200 Subject: [PATCH 01/36] feat: Admin API users manegement endpoints --- lib/utils/isAdmin.ts | 6 +++++ lib/validations/user.ts | 32 ++++++++++++++++++++--- pages/api/users/[id].ts | 8 ++++-- pages/api/users/index.ts | 56 +++++++++++++++++++++------------------- 4 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 lib/utils/isAdmin.ts diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts new file mode 100644 index 0000000000..1026b8deb1 --- /dev/null +++ b/lib/utils/isAdmin.ts @@ -0,0 +1,6 @@ +import prisma from "@calcom/prisma"; + +export const isAdminGuard = async (userId: number) => { + const user = await prisma.user.findUnique({ where: { id: userId } }); + return user?.role === "ADMIN"; +}; diff --git a/lib/validations/user.ts b/lib/validations/user.ts index d78d8e23b2..3955caabd4 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -85,19 +85,45 @@ const schemaUserEditParams = z.object({ bufferTime: z.number().min(0).max(86400).optional(), startTime: z.number().min(0).max(86400).optional(), endTime: z.number().min(0).max(86400).optional(), - theme: z.nativeEnum(theme).optional(), + theme: z.nativeEnum(theme).optional().nullable(), timeFormat: z.nativeEnum(timeFormat).optional(), defaultScheduleId: z .number() .refine((id: number) => id > 0) - .optional(), + .optional() + .nullable(), + locale: z.nativeEnum(locales).optional().nullable(), + metadata: jsonSchema.or(z.null()), +}); + +// @note: These are the values that are editable via PATCH method on the user Model, +// merging both BaseBodyParams with RequiredParams, and omiting whatever we want at the end. + +const schemaUserCreateParams = z.object({ + email: z.string().email(), + weekStart: z.nativeEnum(weekdays).optional(), + brandColor: z.string().min(4).max(9).regex(/^#/).optional(), + darkBrandColor: z.string().min(4).max(9).regex(/^#/).optional(), + timeZone: timeZone.optional(), + bufferTime: z.number().min(0).max(86400).optional(), + startTime: z.number().min(0).max(86400).optional(), + endTime: z.number().min(0).max(86400).optional(), + theme: z.nativeEnum(theme).optional().nullable(), + timeFormat: z.nativeEnum(timeFormat).optional(), + defaultScheduleId: z + .number() + .refine((id: number) => id > 0) + .optional() + .nullable(), locale: z.nativeEnum(locales).optional(), metadata: jsonSchema, + createdDate: z.string().or(z.date()).optional(), }); // @note: These are the values that are editable via PATCH method on the user Model, // merging both BaseBodyParams with RequiredParams, and omiting whatever we want at the end. export const schemaUserEditBodyParams = schemaUserBaseBodyParams.merge(schemaUserEditParams).omit({}); +export const schemaUserCreateBodyParams = schemaUserBaseBodyParams.merge(schemaUserCreateParams).omit({}); // @note: These are the values that are always returned when reading a user export const schemaUserReadPublic = User.pick({ @@ -124,4 +150,4 @@ export const schemaUserReadPublic = User.pick({ createdDate: true, verified: true, invitedTo: true, -}); +}).merge(schemaUserEditBodyParams); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 7539d513b8..65b864c652 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -20,8 +21,11 @@ export async function userById( res.status(400).json({ message: "Your query was invalid" }); return; } - if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); - else { + const isAdmin = await isAdminGuard(userId); + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin) { + if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { case "GET": /** diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 9f80a421d2..122892f2e1 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -4,7 +4,8 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UserResponse, UsersResponse } from "@lib/types"; -import { schemaUserReadPublic } from "@lib/validations/user"; +import { isAdminGuard } from "@lib/utils/isAdmin"; +import { schemaUserReadPublic, schemaUserCreateBodyParams } from "@lib/validations/user"; /** * @swagger @@ -26,34 +27,35 @@ async function getAllorCreateUser( { userId, method, body }: NextApiRequest, res: NextApiResponse ) { + const isAdmin = await isAdminGuard(userId); if (method === "GET") { - const data = await prisma.user.findMany({ - where: { - id: userId, - }, - }); - const users = data.map((user) => schemaUserReadPublic.parse(user)); - if (users) res.status(200).json({ users }); - else - (error: Error) => - res.status(404).json({ - message: "No Users were found", - error, - }); + if (!isAdmin) { + const data = await prisma.user.findMany({ + where: { + id: userId, + }, + }); + const users = data.map((user) => schemaUserReadPublic.parse(user)); + if (users) res.status(200).json({ users }); + } else { + const data = await prisma.user.findMany({}); + const users = data.map((user) => schemaUserReadPublic.parse(user)); + if (users) res.status(200).json({ users }); + } + } else if (method === "POST") { + if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); + else { + const safeBody = schemaUserCreateBodyParams.safeParse(body); + if (!safeBody.success) { + res.status(400).json({ message: "Your body was invalid" }); + return; + } + const user = await prisma.user.create({ + data: safeBody.data, + }); + res.status(201).json({ user }); + } } - // else if (method === "POST") { - // const isAdmin = await prisma.user - // .findUnique({ where: { id: userId } }) - // .then((user) => user?.role === "ADMIN"); - // if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); - // else { - // const user = await prisma.user.create({ - // data: schemaUserReadPublic.parse(body), - // }); - // res.status(201).json({ user }); - // } - // } } -// No POST endpoint for users for now as a regular user you're expected to signup. export default withMiddleware("HTTP_GET_OR_POST")(getAllorCreateUser); From 4eccc8a74befcc0daf05f5148be3141f3f419541 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 31 May 2022 18:42:20 +0200 Subject: [PATCH 02/36] fix: build error jsonSchema metadata not nullable --- lib/validations/user.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 3955caabd4..528bc2e292 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -93,7 +93,7 @@ const schemaUserEditParams = z.object({ .optional() .nullable(), locale: z.nativeEnum(locales).optional().nullable(), - metadata: jsonSchema.or(z.null()), + metadata: jsonSchema, }); // @note: These are the values that are editable via PATCH method on the user Model, From 187d5f2b1003f222d4224db1381e51e6da59dd5e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 31 May 2022 18:53:41 +0200 Subject: [PATCH 03/36] docs: add some comments --- pages/api/users/index.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 122892f2e1..3839ae21b6 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -30,19 +30,18 @@ async function getAllorCreateUser( const isAdmin = await isAdminGuard(userId); if (method === "GET") { if (!isAdmin) { - const data = await prisma.user.findMany({ - where: { - id: userId, - }, - }); + // If user is not ADMIN, return only his data. + const data = await prisma.user.findMany({ where: { id: userId } }); const users = data.map((user) => schemaUserReadPublic.parse(user)); if (users) res.status(200).json({ users }); } else { + // If user is admin, return all users. const data = await prisma.user.findMany({}); const users = data.map((user) => schemaUserReadPublic.parse(user)); if (users) res.status(200).json({ users }); } } else if (method === "POST") { + // If user is not ADMIN, return unauthorized. if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); else { const safeBody = schemaUserCreateBodyParams.safeParse(body); From 7f42cc84793fd59808a030aedcc44079c1315565 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 31 May 2022 20:46:09 +0200 Subject: [PATCH 04/36] fix: improve admin check using enum instead of string --- lib/utils/isAdmin.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index 1026b8deb1..c97628b46d 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,6 +1,7 @@ import prisma from "@calcom/prisma"; +import { UserPermissionRole } from "@calcom/prisma/client"; export const isAdminGuard = async (userId: number) => { const user = await prisma.user.findUnique({ where: { id: userId } }); - return user?.role === "ADMIN"; + return user?.role === UserPermissionRole.ADMIN; }; From 43b94d3e9662bb2be8128c7546cc58148c2fbf8f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 1 Jun 2022 17:05:33 +0200 Subject: [PATCH 05/36] feat: adds automatic generation of uuid id for webhooks create on API --- lib/helpers/verifyApiKey.ts | 1 - lib/utils/isAdmin.ts | 3 ++- lib/validations/webhook.ts | 2 +- pages/api/hooks/[id].ts | 4 ++-- pages/api/hooks/index.ts | 3 ++- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 38fa6b44c3..c45f3d3c3f 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -11,7 +11,6 @@ declare module "next" { userId: number; method: string; query: { [key: string]: string | string[] }; - body: any; } } diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index c97628b46d..64af37367f 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,5 +1,6 @@ +import { UserPermissionRole } from "@prisma/client"; + import prisma from "@calcom/prisma"; -import { UserPermissionRole } from "@calcom/prisma/client"; export const isAdminGuard = async (userId: number) => { const user = await prisma.user.findUnique({ where: { id: userId } }); diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index ee42052204..c157a6e367 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -26,7 +26,7 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ - id: z.string(), + // id: z.string(), subscriberUrl: z.string().url(), eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), active: z.boolean(), diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index dcf82aaa2d..32a81e7b12 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -51,7 +51,7 @@ export async function WebhookById( case "GET": await prisma.webhook .findUnique({ where: { id: safeQuery.data.id } }) - // .then((data) => schemaWebhookReadPublic.parse(data)) + .then((data) => schemaWebhookReadPublic.parse(data)) .then((webhook) => res.status(200).json({ webhook })) .catch((error: Error) => res.status(404).json({ @@ -97,7 +97,7 @@ export async function WebhookById( } await prisma.webhook .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - // .then((data) => schemaWebhookReadPublic.parse(data)) + .then((data) => schemaWebhookReadPublic.parse(data)) .then((webhook) => res.status(200).json({ webhook })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 05b6e90d57..422a30e419 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -1,4 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import { v4 as uuidv4 } from "uuid"; import prisma from "@calcom/prisma"; @@ -60,7 +61,7 @@ async function createOrlistAllWebhooks( res.status(400).json({ message: "Invalid request body" }); return; } - const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); + const data = await prisma.webhook.create({ data: { id: uuidv4(), ...safe.data, userId } }); if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); else (error: Error) => From 3fc22a8eff2cd9327ebd5e2c19af58925be5df16 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 1 Jun 2022 17:08:01 +0200 Subject: [PATCH 06/36] fix: remove comments --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index c157a6e367..f5de69c45a 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -26,7 +26,6 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ - // id: z.string(), subscriberUrl: z.string().url(), eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), active: z.boolean(), @@ -52,6 +51,7 @@ export const schemaWebhookReadPublic = Webhook.pick({ eventTypeId: true, payloadTemplate: true, eventTriggers: true, + /** @todo: find out how to properly add back and validate those. */ // eventType: true, // app: true, appId: true, From fe73973b7a9bf9869174a1d5e6b8ed1ed24da3ab Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 2 Jun 2022 15:55:52 +0200 Subject: [PATCH 07/36] fix: add uuid to api/package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 16c51d9d6b..57da05e5e6 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "next-validations": "^0.2.0", "typescript": "^4.6.4", "tzdata": "^1.0.30", + "uuid": "^8.3.2", "zod": "^3.16.0" } } From cd03f5a821e4271df3291b4f1603d1574de9f269 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:06:28 +0530 Subject: [PATCH 08/36] Adds team event type check --- pages/api/hooks/[id].ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 32a81e7b12..3a14efa592 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -95,6 +95,27 @@ export async function WebhookById( return; } } + if (safeBody.data.eventTypeId) { + const team = await ctx.prisma.team.findFirst({ + where: { + eventTypes: { + some: { + id: safeBody.data.eventTypeId, + }, + }, + }, + include: { + members: true, + }, + }); + + // Team should be available and the user should be a member of the team + if (!team?.members.some((membership) => membership.userId === userId)) { + throw new TRPCError({ + code: "UNAUTHORIZED", + }); + } + } await prisma.webhook .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) .then((data) => schemaWebhookReadPublic.parse(data)) From bae84f2ce4e7daa9fcc3c8984a18997946cdab20 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:12:05 +0530 Subject: [PATCH 09/36] Added team event check to POST --- pages/api/hooks/index.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 422a30e419..e92a681080 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -61,6 +61,27 @@ async function createOrlistAllWebhooks( res.status(400).json({ message: "Invalid request body" }); return; } + if (safe.data.eventTypeId) { + const team = await ctx.prisma.team.findFirst({ + where: { + eventTypes: { + some: { + id: safe.data.eventTypeId, + }, + }, + }, + include: { + members: true, + }, + }); + + // Team should be available and the user should be a member of the team + if (!team?.members.some((membership) => membership.userId === userId)) { + throw new TRPCError({ + code: "UNAUTHORIZED", + }); + } + } const data = await prisma.webhook.create({ data: { id: uuidv4(), ...safe.data, userId } }); if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); else From ef3838b4764cf57d9928fa6581f814652627248b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:20:09 +0530 Subject: [PATCH 10/36] hotfix ctx removal --- pages/api/hooks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index e92a681080..f3f3257499 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -62,7 +62,7 @@ async function createOrlistAllWebhooks( return; } if (safe.data.eventTypeId) { - const team = await ctx.prisma.team.findFirst({ + const team = await prisma.team.findFirst({ where: { eventTypes: { some: { From b881312f1038ea9b67afa52c6a01a9c3c07f8028 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:20:44 +0530 Subject: [PATCH 11/36] hotfix ctx removal --- pages/api/hooks/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 3a14efa592..7debc7ac8d 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -96,7 +96,7 @@ export async function WebhookById( } } if (safeBody.data.eventTypeId) { - const team = await ctx.prisma.team.findFirst({ + const team = await prisma.team.findFirst({ where: { eventTypes: { some: { From 9b1dffbdb9e64969c79d87c892e4a0083e8e64f1 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:27:48 +0530 Subject: [PATCH 12/36] 401 return fix --- pages/api/hooks/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index f3f3257499..ec85ab13df 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -77,9 +77,8 @@ async function createOrlistAllWebhooks( // Team should be available and the user should be a member of the team if (!team?.members.some((membership) => membership.userId === userId)) { - throw new TRPCError({ - code: "UNAUTHORIZED", - }); + res.status(401).json({ message: "Unauthorized" }); + return; } } const data = await prisma.webhook.create({ data: { id: uuidv4(), ...safe.data, userId } }); From db6f5cad1512ac6d6efc8b4c9368634ebcde348b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:28:22 +0530 Subject: [PATCH 13/36] 401 message fix --- pages/api/hooks/[id].ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 7debc7ac8d..8f81fc62d1 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -111,9 +111,8 @@ export async function WebhookById( // Team should be available and the user should be a member of the team if (!team?.members.some((membership) => membership.userId === userId)) { - throw new TRPCError({ - code: "UNAUTHORIZED", - }); + res.status(401).json({ message: "Unauthorized" }); + return; } } await prisma.webhook From d569296654495621b0475a4636fa9ac937cccd56 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 9 Jun 2022 17:09:20 +0530 Subject: [PATCH 14/36] Add webhook trigger --init --- pages/api/bookings/index.ts | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 40f24283ee..1951e4475d 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -81,7 +81,31 @@ async function createOrlistAllBookings( const data = await prisma.booking.create({ data: { ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); - if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); + if (booking) { + res.status(201).json({ booking, message: "Booking created successfully" }); + + // Send Webhook call if hooked to BOOKING_CREATED & BOOKING_RESCHEDULED +// const eventTrigger: WebhookTriggerEvents = rescheduleUid ? "BOOKING_RESCHEDULED" : "BOOKING_CREATED"; +// const subscriberOptions = { +// userId: user.id, +// eventTypeId, +// triggerEvent: eventTrigger, +// }; + +// const subscribers = await getSubscribers(subscriberOptions); +// const bookingId = booking?.id; +// const promises = subscribers.map((sub) => +// sendPayload(eventTrigger, new Date().toISOString(), sub, { +// ...evt, +// bookingId, +// rescheduleUid, +// metadata: reqBody.metadata, +// }).catch((e) => { +// console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${sub.subscriberUrl}`, e); +// }) +// ); +// await Promise.all(promises); + } else (error: Error) => { console.log(error); From cd482cd91a44a4631bb0be0bce4b82968c4c5068 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:40:38 +0530 Subject: [PATCH 15/36] Add getWebhook function --- lib/utils/webhookSubscriptions.ts | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 lib/utils/webhookSubscriptions.ts diff --git a/lib/utils/webhookSubscriptions.ts b/lib/utils/webhookSubscriptions.ts new file mode 100644 index 0000000000..bdf9d95576 --- /dev/null +++ b/lib/utils/webhookSubscriptions.ts @@ -0,0 +1,42 @@ +import { WebhookTriggerEvents } from "@prisma/client"; + +import prisma from "@calcom/prisma"; + +export type GetSubscriberOptions = { + userId: number; + eventTypeId: number; + triggerEvent: WebhookTriggerEvents; +}; + +const getWebhooks = async (options: GetSubscriberOptions) => { + const { userId, eventTypeId } = options; + const allWebhooks = await prisma.webhook.findMany({ + where: { + OR: [ + { + userId, + }, + { + eventTypeId, + }, + ], + AND: { + eventTriggers: { + has: options.triggerEvent, + }, + active: { + equals: true, + }, + }, + }, + select: { + subscriberUrl: true, + payloadTemplate: true, + appId: true, + }, + }); + + return allWebhooks; +}; + +export default getWebhooks; From 664e697d40bc24232102221ed52443562f0b01b5 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:42:01 +0530 Subject: [PATCH 16/36] add sendPayload file --- lib/utils/sendPayload.ts | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lib/utils/sendPayload.ts diff --git a/lib/utils/sendPayload.ts b/lib/utils/sendPayload.ts new file mode 100644 index 0000000000..62cc3f96d2 --- /dev/null +++ b/lib/utils/sendPayload.ts @@ -0,0 +1,77 @@ +import { Webhook } from "@prisma/client"; +import { compile } from "handlebars"; + +import type { CalendarEvent } from "@calcom/types/Calendar"; + +type ContentType = "application/json" | "application/x-www-form-urlencoded"; + +function applyTemplate(template: string, data: CalendarEvent, contentType: ContentType) { + const compiled = compile(template)(data); + if (contentType === "application/json") { + return JSON.stringify(jsonParse(compiled)); + } + return compiled; +} + +function jsonParse(jsonString: string) { + try { + return JSON.parse(jsonString); + } catch (e) { + // don't do anything. + } + return false; +} + +const sendPayload = async ( + triggerEvent: string, + createdAt: string, + webhook: Pick, + data: CalendarEvent & { + metadata?: { [key: string]: string }; + rescheduleUid?: string; + bookingId?: number; + } +) => { + const { subscriberUrl, appId, payloadTemplate: template } = webhook; + if (!subscriberUrl || !data) { + throw new Error("Missing required elements to send webhook payload."); + } + + const contentType = + !template || jsonParse(template) ? "application/json" : "application/x-www-form-urlencoded"; + + data.description = data.description || data.additionalNotes; + + let body; + + /* Zapier id is hardcoded in the DB, we send the raw data for this case */ + if (appId === "zapier") { + body = JSON.stringify(data); + } else if (template) { + body = applyTemplate(template, data, contentType); + } else { + body = JSON.stringify({ + triggerEvent: triggerEvent, + createdAt: createdAt, + payload: data, + }); + } + + const response = await fetch(subscriberUrl, { + method: "POST", + headers: { + "Content-Type": contentType, + }, + body, + }); + + const text = await response.text(); + + return { + ok: response.ok, + status: response.status, + message: text, + }; +}; + +export default sendPayload; From 542beb007938450ab0365aa4c6367a27cf6b5386 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:46:51 +0530 Subject: [PATCH 17/36] adjust booking file --- pages/api/bookings/index.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 1951e4475d..2ee5c2da1c 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -84,15 +84,17 @@ async function createOrlistAllBookings( if (booking) { res.status(201).json({ booking, message: "Booking created successfully" }); - // Send Webhook call if hooked to BOOKING_CREATED & BOOKING_RESCHEDULED -// const eventTrigger: WebhookTriggerEvents = rescheduleUid ? "BOOKING_RESCHEDULED" : "BOOKING_CREATED"; +// Create Calendar Event for webhook payload + +// Send Webhook call if hooked to BOOKING_CREATED & BOOKING_RESCHEDULED +// const eventTrigger = WebhookTriggerEvents.BOOKING_CREATED; // const subscriberOptions = { // userId: user.id, // eventTypeId, // triggerEvent: eventTrigger, // }; -// const subscribers = await getSubscribers(subscriberOptions); +// const subscribers = await getWebhooks(subscriberOptions); // const bookingId = booking?.id; // const promises = subscribers.map((sub) => // sendPayload(eventTrigger, new Date().toISOString(), sub, { From 804de678680f2fa991c904e1f0fb62f96a53bee5 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 12:17:00 +0530 Subject: [PATCH 18/36] Add eventName file --- lib/utils/eventName.ts | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 lib/utils/eventName.ts diff --git a/lib/utils/eventName.ts b/lib/utils/eventName.ts new file mode 100644 index 0000000000..5d7865fe94 --- /dev/null +++ b/lib/utils/eventName.ts @@ -0,0 +1,62 @@ +import { TFunction } from "next-i18next"; + +type EventNameObjectType = { + attendeeName: string; + eventType: string; + eventName?: string | null; + host: string; + location?: string; + t: TFunction; +}; + +export function getEventName(eventNameObj: EventNameObjectType, forAttendeeView = false) { + if (!eventNameObj.eventName) + return eventNameObj.t("event_between_users", { + eventName: eventNameObj.eventType, + host: eventNameObj.host, + attendeeName: eventNameObj.attendeeName, + }); + + let eventName = eventNameObj.eventName; + let locationString = ""; + + if (eventNameObj.eventName.includes("{LOCATION}")) { + switch (eventNameObj.location) { + case "inPerson": + locationString = "In Person"; + break; + case "userPhone": + case "phone": + locationString = "Phone"; + break; + case "integrations:daily": + locationString = "Cal Video"; + break; + case "integrations:zoom": + locationString = "Zoom"; + break; + case "integrations:huddle01": + locationString = "Huddle01"; + break; + case "integrations:tandem": + locationString = "Tandem"; + break; + case "integrations:office365_video": + locationString = "MS Teams"; + break; + case "integrations:jitsi": + locationString = "Jitsi"; + break; + } + eventName = eventName.replace("{LOCATION}", locationString); + } + + return ( + eventName + // Need this for compatibility with older event names + .replace("{USER}", eventNameObj.attendeeName) + .replace("{ATTENDEE}", eventNameObj.attendeeName) + .replace("{HOST}", eventNameObj.host) + .replace("{HOST/ATTENDEE}", forAttendeeView ? eventNameObj.host : eventNameObj.attendeeName) + ); +} From e3822c50d0998312929a3c6b58e9c728c16a58ed Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 12:43:41 +0530 Subject: [PATCH 19/36] Update booking file with webhook payload --- pages/api/bookings/index.ts | 78 +++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 2ee5c2da1c..f3b9e8c027 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -2,9 +2,14 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { WebhookTriggerEvents } from "@prisma/client"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; +import sendPayload from "@lib/utils/sendPayload"; +import getWebhooks from "@lib/utils/webhookSubscriptions"; import { BookingResponse, BookingsResponse } from "@lib/types"; import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; +import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllBookings( { method, body, userId }: NextApiRequest, @@ -84,29 +89,60 @@ async function createOrlistAllBookings( if (booking) { res.status(201).json({ booking, message: "Booking created successfully" }); -// Create Calendar Event for webhook payload + // Create Calendar Event for webhook payload + const eventType = await prisma.eventType + .findUnique({ where: { id: booking?.eventTypeId } }) + .then((data) => schemaEventTypeReadPublic.parse(data)) + .then((event_type) => res.status(200).json({ event_type })) + .catch((error: Error) => + res.status(404).json({ + message: `EventType with id: ${booking?.eventTypeId} not found`, + error, + }) + ); + const evt = { + type: eventType.title, + title: booking.title, + description: "", + additionalNotes: "", + customInputs: {}, + startTime: booking.startTime, + endTime: booking.endTime, + organizer: { + name: "", + email: "", + timezone: "", + language: { + locale: "en" + } + }, + attendees: [], + location: "", + destinationCalendar: null, + hideCalendar: false, + uid: booking.uid, + metadata: {} + }; -// Send Webhook call if hooked to BOOKING_CREATED & BOOKING_RESCHEDULED -// const eventTrigger = WebhookTriggerEvents.BOOKING_CREATED; -// const subscriberOptions = { -// userId: user.id, -// eventTypeId, -// triggerEvent: eventTrigger, -// }; + // Send Webhook call if hooked to BOOKING_CREATED + const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; + const subscriberOptions = { + userId, + eventTypeId: eventType.id, + triggerEvent, + }; -// const subscribers = await getWebhooks(subscriberOptions); -// const bookingId = booking?.id; -// const promises = subscribers.map((sub) => -// sendPayload(eventTrigger, new Date().toISOString(), sub, { -// ...evt, -// bookingId, -// rescheduleUid, -// metadata: reqBody.metadata, -// }).catch((e) => { -// console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${sub.subscriberUrl}`, e); -// }) -// ); -// await Promise.all(promises); + const subscribers = await getWebhooks(subscriberOptions); + const bookingId = booking?.id; + const promises = subscribers.map((sub) => + sendPayload(eventTrigger, new Date().toISOString(), sub, { + ...evt, + bookingId, + }).catch((e) => { + console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${sub.subscriberUrl}`, e); + }) + ); + await Promise.all(promises); } else (error: Error) => { From 4f3668100691dfb0f4fe8c622fd8bce513eed679 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 12:51:24 +0530 Subject: [PATCH 20/36] --fix --- pages/api/bookings/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index f3b9e8c027..2a11672e32 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -135,11 +135,11 @@ async function createOrlistAllBookings( const subscribers = await getWebhooks(subscriberOptions); const bookingId = booking?.id; const promises = subscribers.map((sub) => - sendPayload(eventTrigger, new Date().toISOString(), sub, { + sendPayload(triggerEvent, new Date().toISOString(), sub, { ...evt, bookingId, }).catch((e) => { - console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${sub.subscriberUrl}`, e); + console.error(`Error executing webhook for event: ${triggerEvent}, URL: ${sub.subscriberUrl}`, e); }) ); await Promise.all(promises); From f9c20bc8ce3544508585d8bb0fece077994da833 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 12:53:59 +0530 Subject: [PATCH 21/36] --fix null estimated value --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 2a11672e32..73c4e8d12b 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -91,7 +91,7 @@ async function createOrlistAllBookings( // Create Calendar Event for webhook payload const eventType = await prisma.eventType - .findUnique({ where: { id: booking?.eventTypeId } }) + .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => From 4431142d4e540b8d0135241cff16d0c7d3fbff61 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 12:58:04 +0530 Subject: [PATCH 22/36] remove unnecessary return --- pages/api/bookings/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 73c4e8d12b..322543078f 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -93,10 +93,9 @@ async function createOrlistAllBookings( const eventType = await prisma.eventType .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) - .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => res.status(404).json({ - message: `EventType with id: ${booking?.eventTypeId} not found`, + message: `EventType with id: ${booking.eventTypeId} not found`, error, }) ); From adab79040f37e83e8ddc5aa4b59f079a21cacbc3 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:06:22 +0530 Subject: [PATCH 23/36] --fix --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 322543078f..2db7abac29 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -100,7 +100,7 @@ async function createOrlistAllBookings( }) ); const evt = { - type: eventType.title, + type: eventType?.title || booking.title, title: booking.title, description: "", additionalNotes: "", From cd3a80006c6eb3b44a17273439f729051406f613 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:10:16 +0530 Subject: [PATCH 24/36] --fix --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 2db7abac29..1b23a5e3f3 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -127,7 +127,7 @@ async function createOrlistAllBookings( const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; const subscriberOptions = { userId, - eventTypeId: eventType.id, + eventTypeId: booking.eventTypeId as number, triggerEvent, }; From a8ad052a037246219eb15cdb82d8dee798b8b057 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:16:58 +0530 Subject: [PATCH 25/36] --convert date to string in calendar event --- pages/api/bookings/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 1b23a5e3f3..0a421298e1 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -105,8 +105,8 @@ async function createOrlistAllBookings( description: "", additionalNotes: "", customInputs: {}, - startTime: booking.startTime, - endTime: booking.endTime, + startTime: booking.startTime.toISOString(), + endTime: booking.endTime.toISOString(), organizer: { name: "", email: "", From ef5bbfe4f96c65480beb7bc88519464368700cdf Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:22:06 +0530 Subject: [PATCH 26/36] fixed timeZone key --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 0a421298e1..a8eaf90662 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -110,7 +110,7 @@ async function createOrlistAllBookings( organizer: { name: "", email: "", - timezone: "", + timeZone: "", language: { locale: "en" } From f1c98181d2daee95d3e16ba25406010914aa8e78 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:30:43 +0530 Subject: [PATCH 27/36] tfunction added --- pages/api/bookings/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index a8eaf90662..f5748daf67 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,5 +1,6 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { getTranslation } from "@calcom/lib/server/i18n"; +import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { WebhookTriggerEvents } from "@prisma/client"; @@ -99,6 +100,7 @@ async function createOrlistAllBookings( error, }) ); + const fallbackTfunction = await getTranslation("en", "common"); const evt = { type: eventType?.title || booking.title, title: booking.title, @@ -112,6 +114,7 @@ async function createOrlistAllBookings( email: "", timeZone: "", language: { + translate: fallbackTfunction, locale: "en" } }, From 54353f99d139395826a270843ad57abd73c38d1d Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:32:47 +0530 Subject: [PATCH 28/36] Calendar event changed to any for loose allowance --- lib/utils/sendPayload.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/sendPayload.ts b/lib/utils/sendPayload.ts index 62cc3f96d2..925be7486a 100644 --- a/lib/utils/sendPayload.ts +++ b/lib/utils/sendPayload.ts @@ -1,11 +1,11 @@ import { Webhook } from "@prisma/client"; import { compile } from "handlebars"; -import type { CalendarEvent } from "@calcom/types/Calendar"; +// import type { CalendarEvent } from "@calcom/types/Calendar"; Add this to make it strict, change data: any to CalendarEvent type type ContentType = "application/json" | "application/x-www-form-urlencoded"; -function applyTemplate(template: string, data: CalendarEvent, contentType: ContentType) { +function applyTemplate(template: string, data: any, contentType: ContentType) { const compiled = compile(template)(data); if (contentType === "application/json") { return JSON.stringify(jsonParse(compiled)); From 8339d339a1ac3f149045e7fa0a180107ea585ce7 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:38:45 +0530 Subject: [PATCH 29/36] prettier and payload fix --- lib/utils/sendPayload.ts | 2 +- pages/api/bookings/index.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/utils/sendPayload.ts b/lib/utils/sendPayload.ts index 925be7486a..f40c0ad743 100644 --- a/lib/utils/sendPayload.ts +++ b/lib/utils/sendPayload.ts @@ -26,7 +26,7 @@ const sendPayload = async ( triggerEvent: string, createdAt: string, webhook: Pick, - data: CalendarEvent & { + data: any & { metadata?: { [key: string]: string }; rescheduleUid?: string; bookingId?: number; diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index f5748daf67..7abd8ae5e7 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,14 +1,14 @@ -import { getTranslation } from "@calcom/lib/server/i18n"; - -import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { WebhookTriggerEvents } from "@prisma/client"; +import { getTranslation } from "@calcom/lib/server/i18n"; + +import type { NextApiRequest, NextApiResponse } from "next"; import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { BookingResponse, BookingsResponse } from "@lib/types"; import sendPayload from "@lib/utils/sendPayload"; import getWebhooks from "@lib/utils/webhookSubscriptions"; -import { BookingResponse, BookingsResponse } from "@lib/types"; import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; @@ -115,7 +115,7 @@ async function createOrlistAllBookings( timeZone: "", language: { translate: fallbackTfunction, - locale: "en" + locale: "en", } }, attendees: [], From 5453af6d6ee189185b0c467157013d821825d7cd Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 15:57:31 +0530 Subject: [PATCH 30/36] prettier fix attempt --- pages/api/bookings/index.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 7abd8ae5e7..4db3f3051a 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,10 +1,9 @@ -import prisma from "@calcom/prisma"; - import { WebhookTriggerEvents } from "@prisma/client"; -import { getTranslation } from "@calcom/lib/server/i18n"; - import type { NextApiRequest, NextApiResponse } from "next"; +import { getTranslation } from "@calcom/lib/server/i18n"; +import prisma from "@calcom/prisma"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; import { BookingResponse, BookingsResponse } from "@lib/types"; import sendPayload from "@lib/utils/sendPayload"; From 301c132815bd011f47efae13f21b053704664158 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 16:21:55 +0530 Subject: [PATCH 31/36] prettier fix attempt-2 --- pages/api/bookings/index.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 4db3f3051a..b8ef582dc1 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -88,8 +88,7 @@ async function createOrlistAllBookings( if (booking) { res.status(201).json({ booking, message: "Booking created successfully" }); - - // Create Calendar Event for webhook payload + // Create Calendar Event for webhook payload const eventType = await prisma.eventType .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) @@ -115,24 +114,24 @@ async function createOrlistAllBookings( language: { translate: fallbackTfunction, locale: "en", - } + }, }, attendees: [], location: "", destinationCalendar: null, hideCalendar: false, uid: booking.uid, - metadata: {} + metadata: {}, }; - - // Send Webhook call if hooked to BOOKING_CREATED + + // Send Webhook call if hooked to BOOKING_CREATED const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; const subscriberOptions = { userId, eventTypeId: booking.eventTypeId as number, triggerEvent, }; - + const subscribers = await getWebhooks(subscriberOptions); const bookingId = booking?.id; const promises = subscribers.map((sub) => From 99e58c414c0419b96d9a0fe0c6e992c62307788f Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 16:36:28 +0530 Subject: [PATCH 32/36] prettier fix -3 --- pages/api/bookings/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index b8ef582dc1..90f9cf7f22 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -143,8 +143,7 @@ async function createOrlistAllBookings( }) ); await Promise.all(promises); - } - else + } else (error: Error) => { console.log(error); res.status(400).json({ From 110edd7dcce0ae07554857c7a3c18395f3440b5a Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sat, 11 Jun 2022 16:54:30 +0530 Subject: [PATCH 33/36] removed 18next rel --- pages/api/bookings/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 90f9cf7f22..6f8f2ceadc 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,7 +1,6 @@ import { WebhookTriggerEvents } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { getTranslation } from "@calcom/lib/server/i18n"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; @@ -98,7 +97,6 @@ async function createOrlistAllBookings( error, }) ); - const fallbackTfunction = await getTranslation("en", "common"); const evt = { type: eventType?.title || booking.title, title: booking.title, @@ -112,7 +110,6 @@ async function createOrlistAllBookings( email: "", timeZone: "", language: { - translate: fallbackTfunction, locale: "en", }, }, From 61e742ed5ef42d9d2584a92d06c9ec59e2785e5b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sat, 11 Jun 2022 16:57:35 +0530 Subject: [PATCH 34/36] uuid automate in booking API --- lib/validations/booking.ts | 1 - pages/api/bookings/index.ts | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 67b4f1b35a..b61d6913fd 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -13,7 +13,6 @@ const schemaBookingBaseBodyParams = Booking.pick({ const schemaBookingCreateParams = z .object({ - uid: z.string(), eventTypeId: z.number(), title: z.string(), startTime: z.date().or(z.string()), diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 6f8f2ceadc..37fbd94262 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,5 +1,6 @@ import { WebhookTriggerEvents } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import { v4 as uuidv4 } from "uuid"; import prisma from "@calcom/prisma"; @@ -82,7 +83,7 @@ async function createOrlistAllBookings( return; } safe.data.userId = userId; - const data = await prisma.booking.create({ data: { ...safe.data } }); + const data = await prisma.booking.create({ data: { id: uuidv4(), ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); if (booking) { From 3c98c5cefc4db970d674e54b14846504a2c1bf3f Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sat, 11 Jun 2022 16:58:21 +0530 Subject: [PATCH 35/36] fixing id to uid in create body --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 37fbd94262..6bd220aaf5 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -83,7 +83,7 @@ async function createOrlistAllBookings( return; } safe.data.userId = userId; - const data = await prisma.booking.create({ data: { id: uuidv4(), ...safe.data } }); + const data = await prisma.booking.create({ data: { uid: uuidv4(), ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); if (booking) { From 719e21497b58e4a57b6914a6c4000e9443fa5188 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sat, 11 Jun 2022 17:03:11 +0530 Subject: [PATCH 36/36] removed invalid response --- pages/api/bookings/index.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 6bd220aaf5..af20e851fe 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -92,12 +92,9 @@ async function createOrlistAllBookings( const eventType = await prisma.eventType .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) - .catch((error: Error) => - res.status(404).json({ - message: `EventType with id: ${booking.eventTypeId} not found`, - error, - }) - ); + .catch((e: Error) => { + console.error(`Event type with ID: ${booking.eventTypeId} not found`, e); + }); const evt = { type: eventType?.title || booking.title, title: booking.title,