From e960b8ad101945bf140fb04c1e6ac44f0d397336 Mon Sep 17 00:00:00 2001 From: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Wed, 17 Jul 2024 12:32:22 +0530 Subject: [PATCH] fix: fetch workflows on the backend (#15796) * fix: fetch workflows on the router * chore: remove workflows * chore: import zod * chore: move to repository --- .../views/event-types-single-view.tsx | 2 +- packages/lib/event-types/getEventTypeById.ts | 212 +---------------- packages/lib/server/repository/eventType.ts | 225 ++++++++++++++++++ .../getAllActiveWorkflows.handler.ts | 12 +- .../workflows/getAllActiveWorkflows.schema.ts | 14 +- .../server/routers/viewer/workflows/util.ts | 12 + 6 files changed, 258 insertions(+), 219 deletions(-) diff --git a/apps/web/modules/event-types/views/event-types-single-view.tsx b/apps/web/modules/event-types/views/event-types-single-view.tsx index e198d2150e..927227ab73 100644 --- a/apps/web/modules/event-types/views/event-types-single-view.tsx +++ b/apps/web/modules/event-types/views/event-types-single-view.tsx @@ -859,7 +859,7 @@ const EventTypePageWrapper: React.FC & { const { data: workflows } = trpc.viewer.workflows.getAllActiveWorkflows.useQuery({ eventType: { - workflows: eventType.workflows, + id: props.type, teamId: eventType.teamId, userId: eventType.userId, parent: eventType.parent, diff --git a/packages/lib/event-types/getEventTypeById.ts b/packages/lib/event-types/getEventTypeById.ts index abdc3c76ac..67ff434a28 100644 --- a/packages/lib/event-types/getEventTypeById.ts +++ b/packages/lib/event-types/getEventTypeById.ts @@ -7,6 +7,7 @@ import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/ import { parseBookingLimit, parseDurationLimit, parseRecurringEvent } from "@calcom/lib"; import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl"; import { getTranslation } from "@calcom/lib/server/i18n"; +import { EventTypeRepository } from "@calcom/lib/server/repository/eventType"; import { UserRepository } from "@calcom/lib/server/repository/user"; import type { PrismaClient } from "@calcom/prisma"; import { SchedulingType, MembershipRole } from "@calcom/prisma/enums"; @@ -46,216 +47,7 @@ export const getEventTypeById = async ({ defaultScheduleId: true, }); - const rawEventType = await prisma.eventType.findFirst({ - where: { - AND: [ - { - OR: [ - { - users: { - some: { - id: userId, - }, - }, - }, - { - team: { - members: { - some: { - userId: userId, - }, - }, - }, - }, - { - userId: userId, - }, - ], - }, - { - id: eventTypeId, - }, - ], - }, - select: { - id: true, - title: true, - slug: true, - description: true, - length: true, - isInstantEvent: true, - instantMeetingExpiryTimeOffsetInSeconds: true, - aiPhoneCallConfig: true, - offsetStart: true, - hidden: true, - locations: true, - eventName: true, - customInputs: true, - timeZone: true, - periodType: true, - metadata: true, - periodDays: true, - periodStartDate: true, - periodEndDate: true, - periodCountCalendarDays: true, - lockTimeZoneToggleOnBookingPage: true, - requiresConfirmation: true, - requiresBookerEmailVerification: true, - recurringEvent: true, - hideCalendarNotes: true, - disableGuests: true, - minimumBookingNotice: true, - beforeEventBuffer: true, - afterEventBuffer: true, - slotInterval: true, - hashedLink: true, - bookingLimits: true, - onlyShowFirstAvailableSlot: true, - durationLimits: true, - assignAllTeamMembers: true, - successRedirectUrl: true, - forwardParamsSuccessRedirect: true, - currency: true, - bookingFields: true, - useEventTypeDestinationCalendarEmail: true, - owner: { - select: { - id: true, - }, - }, - parent: { - select: { - id: true, - teamId: true, - }, - }, - teamId: true, - team: { - select: { - id: true, - name: true, - slug: true, - parentId: true, - parent: { - select: { - slug: true, - organizationSettings: { - select: { - lockEventTypeCreationForUsers: true, - }, - }, - }, - }, - members: { - select: { - role: true, - accepted: true, - user: { - select: { - ...userSelect, - eventTypes: { - select: { - slug: true, - }, - }, - }, - }, - }, - }, - }, - }, - users: { - select: userSelect, - }, - schedulingType: true, - schedule: { - select: { - id: true, - name: true, - }, - }, - hosts: { - select: { - isFixed: true, - userId: true, - priority: true, - }, - }, - userId: true, - price: true, - children: { - select: { - owner: { - select: { - avatarUrl: true, - name: true, - username: true, - email: true, - id: true, - }, - }, - hidden: true, - slug: true, - }, - }, - destinationCalendar: true, - seatsPerTimeSlot: true, - seatsShowAttendees: true, - seatsShowAvailabilityCount: true, - webhooks: { - select: { - id: true, - subscriberUrl: true, - payloadTemplate: true, - active: true, - eventTriggers: true, - secret: true, - eventTypeId: true, - }, - }, - workflows: { - include: { - workflow: { - select: { - name: true, - id: true, - trigger: true, - time: true, - timeUnit: true, - userId: true, - teamId: true, - team: { - select: { - id: true, - slug: true, - name: true, - members: true, - }, - }, - activeOn: { - select: { - eventType: { - select: { - id: true, - title: true, - parentId: true, - _count: { - select: { - children: true, - }, - }, - }, - }, - }, - }, - steps: true, - }, - }, - }, - }, - secondaryEmailId: true, - }, - }); + const rawEventType = await EventTypeRepository.findById({ id: eventTypeId, userId }); if (!rawEventType) { if (isTrpcCall) { diff --git a/packages/lib/server/repository/eventType.ts b/packages/lib/server/repository/eventType.ts index 2eb92e5376..8cd75eb046 100644 --- a/packages/lib/server/repository/eventType.ts +++ b/packages/lib/server/repository/eventType.ts @@ -194,6 +194,231 @@ export class EventTypeRepository { }); } + static async findById({ id, userId }: { id: number; userId: number }) { + const userSelect = Prisma.validator()({ + name: true, + avatarUrl: true, + username: true, + id: true, + email: true, + locale: true, + defaultScheduleId: true, + }); + + const CompleteEventTypeSelect = Prisma.validator()({ + id: true, + title: true, + slug: true, + description: true, + length: true, + isInstantEvent: true, + instantMeetingExpiryTimeOffsetInSeconds: true, + aiPhoneCallConfig: true, + offsetStart: true, + hidden: true, + locations: true, + eventName: true, + customInputs: true, + timeZone: true, + periodType: true, + metadata: true, + periodDays: true, + periodStartDate: true, + periodEndDate: true, + periodCountCalendarDays: true, + lockTimeZoneToggleOnBookingPage: true, + requiresConfirmation: true, + requiresBookerEmailVerification: true, + recurringEvent: true, + hideCalendarNotes: true, + disableGuests: true, + minimumBookingNotice: true, + beforeEventBuffer: true, + afterEventBuffer: true, + slotInterval: true, + hashedLink: true, + bookingLimits: true, + onlyShowFirstAvailableSlot: true, + durationLimits: true, + assignAllTeamMembers: true, + successRedirectUrl: true, + forwardParamsSuccessRedirect: true, + currency: true, + bookingFields: true, + useEventTypeDestinationCalendarEmail: true, + owner: { + select: { + id: true, + }, + }, + parent: { + select: { + id: true, + teamId: true, + }, + }, + teamId: true, + team: { + select: { + id: true, + name: true, + slug: true, + parentId: true, + parent: { + select: { + slug: true, + organizationSettings: { + select: { + lockEventTypeCreationForUsers: true, + }, + }, + }, + }, + members: { + select: { + role: true, + accepted: true, + user: { + select: { + ...userSelect, + eventTypes: { + select: { + slug: true, + }, + }, + }, + }, + }, + }, + }, + }, + users: { + select: userSelect, + }, + schedulingType: true, + schedule: { + select: { + id: true, + name: true, + }, + }, + hosts: { + select: { + isFixed: true, + userId: true, + priority: true, + }, + }, + userId: true, + price: true, + children: { + select: { + owner: { + select: { + avatarUrl: true, + name: true, + username: true, + email: true, + id: true, + }, + }, + hidden: true, + slug: true, + }, + }, + destinationCalendar: true, + seatsPerTimeSlot: true, + seatsShowAttendees: true, + seatsShowAvailabilityCount: true, + webhooks: { + select: { + id: true, + subscriberUrl: true, + payloadTemplate: true, + active: true, + eventTriggers: true, + secret: true, + eventTypeId: true, + }, + }, + workflows: { + include: { + workflow: { + select: { + name: true, + id: true, + trigger: true, + time: true, + timeUnit: true, + userId: true, + teamId: true, + team: { + select: { + id: true, + slug: true, + name: true, + members: true, + }, + }, + activeOn: { + select: { + eventType: { + select: { + id: true, + title: true, + parentId: true, + _count: { + select: { + children: true, + }, + }, + }, + }, + }, + }, + steps: true, + }, + }, + }, + }, + secondaryEmailId: true, + }); + + return await prisma.eventType.findFirst({ + where: { + AND: [ + { + OR: [ + { + users: { + some: { + id: userId, + }, + }, + }, + { + team: { + members: { + some: { + userId: userId, + }, + }, + }, + }, + { + userId: userId, + }, + ], + }, + { + id, + }, + ], + }, + select: CompleteEventTypeSelect, + }); + } + static async findAllByTeamIdIncludeManagedEventTypes({ teamId }: { teamId?: number }) { return await prisma.eventType.findMany({ where: { diff --git a/packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.handler.ts b/packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.handler.ts index d16f23bd17..c55d13f3d3 100644 --- a/packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.handler.ts +++ b/packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.handler.ts @@ -4,7 +4,7 @@ import type { TrpcSessionUser } from "@calcom/trpc/server/trpc"; import { TRPCError } from "@trpc/server"; import type { TGetAllActiveWorkflowsInputSchema } from "./getAllActiveWorkflows.schema"; -import { getAllWorkflowsFromEventType } from "./util"; +import { getAllWorkflowsFromEventType, getEventTypeWorkflows } from "./util"; type GetAllActiveWorkflowsOptions = { ctx: { @@ -15,6 +15,14 @@ type GetAllActiveWorkflowsOptions = { export const getAllActiveWorkflowsHandler = async ({ input, ctx }: GetAllActiveWorkflowsOptions) => { const { eventType } = input; + const workflows = await getEventTypeWorkflows(ctx.user.id, eventType.id); + const completeEventType = { + workflows, + teamId: eventType.teamId, + userId: eventType.userId, + parent: eventType.parent, + metadata: eventType.metadata, + }; if (eventType.userId && eventType.userId !== ctx.user.id) { throw new TRPCError({ @@ -32,7 +40,7 @@ export const getAllActiveWorkflowsHandler = async ({ input, ctx }: GetAllActiveW if (!team) throw new TRPCError({ code: "UNAUTHORIZED" }); } - const allActiveWorkflows = await getAllWorkflowsFromEventType(eventType, eventType.userId); + const allActiveWorkflows = await getAllWorkflowsFromEventType(completeEventType, eventType.userId); return allActiveWorkflows; }; diff --git a/packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.schema.ts b/packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.schema.ts index 3d86fb3d94..bab48b3ab9 100644 --- a/packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.schema.ts +++ b/packages/trpc/server/routers/viewer/workflows/getAllActiveWorkflows.schema.ts @@ -32,14 +32,16 @@ const ZWorkflow = z.object({ .array(), }); +export const ZWorkflows = z + .object({ + workflow: ZWorkflow, + }) + .array() + .optional(); + export const ZGetAllActiveWorkflowsInputSchema = z.object({ eventType: z.object({ - workflows: z - .object({ - workflow: ZWorkflow, - }) - .array() - .optional(), + id: z.number(), teamId: z.number().optional().nullable(), parent: z .object({ diff --git a/packages/trpc/server/routers/viewer/workflows/util.ts b/packages/trpc/server/routers/viewer/workflows/util.ts index 8125845adf..411be5dc0c 100644 --- a/packages/trpc/server/routers/viewer/workflows/util.ts +++ b/packages/trpc/server/routers/viewer/workflows/util.ts @@ -1,4 +1,5 @@ import type { Workflow } from "@prisma/client"; +import type { z } from "zod"; import { isSMSOrWhatsappAction } from "@calcom/ee/workflows/lib/actionHelperFunctions"; import { getAllWorkflows } from "@calcom/ee/workflows/lib/getAllWorkflows"; @@ -25,6 +26,7 @@ import { SENDER_ID, SENDER_NAME } from "@calcom/lib/constants"; import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType"; import logger from "@calcom/lib/logger"; +import { EventTypeRepository } from "@calcom/lib/server/repository/eventType"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; import prisma from "@calcom/prisma"; import type { Prisma, WorkflowStep } from "@calcom/prisma/client"; @@ -40,6 +42,8 @@ import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; import { TRPCError } from "@trpc/server"; +import type { ZWorkflows } from "./getAllActiveWorkflows.schema"; + const log = logger.getSubLogger({ prefix: ["workflow"] }); export const bookingSelect = { @@ -804,3 +808,11 @@ export async function getAllWorkflowsFromEventType( return allWorkflows; } + +export const getEventTypeWorkflows = async ( + userId: number, + eventTypeId: number +): Promise> => { + const rawEventType = await EventTypeRepository.findById({ id: eventTypeId, userId }); + return rawEventType?.workflows; +};