diff --git a/apps/web/pages/api/trpc/appBasecamp3/[trpc].ts b/apps/web/pages/api/trpc/appBasecamp3/[trpc].ts index 2f77571b8ee38e..3c29f5f0292a6d 100644 --- a/apps/web/pages/api/trpc/appBasecamp3/[trpc].ts +++ b/apps/web/pages/api/trpc/appBasecamp3/[trpc].ts @@ -1,4 +1,4 @@ -import appBasecamp3 from "@calcom/app-store/basecamp3/trpc-router"; import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler"; +import appBasecamp3 from "@calcom/trpc/server/routers/apps/basecamp3/_router"; export default createNextApiHandler(appBasecamp3); diff --git a/apps/web/pages/api/trpc/appRoutingForms/[trpc].ts b/apps/web/pages/api/trpc/appRoutingForms/[trpc].ts index 63037301d8c3f3..06a4e08ddaac37 100644 --- a/apps/web/pages/api/trpc/appRoutingForms/[trpc].ts +++ b/apps/web/pages/api/trpc/appRoutingForms/[trpc].ts @@ -1,4 +1,4 @@ -import appRoutingForms from "@calcom/app-store/routing-forms/trpc-router"; import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler"; +import appRoutingForms from "@calcom/trpc/server/routers/apps/routing-forms/_router"; export default createNextApiHandler(appRoutingForms); diff --git a/packages/app-store/basecamp3/trpc-router.ts b/packages/app-store/basecamp3/trpc-router.ts deleted file mode 100644 index 2adeb779301937..00000000000000 --- a/packages/app-store/basecamp3/trpc-router.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./trpc/_router"; diff --git a/packages/app-store/routing-forms/trpc/onFormSubmission.test.ts b/packages/app-store/routing-forms/lib/formSubmissionUtils.test.ts similarity index 98% rename from packages/app-store/routing-forms/trpc/onFormSubmission.test.ts rename to packages/app-store/routing-forms/lib/formSubmissionUtils.test.ts index e51ad422c012dd..1824e21c82798c 100644 --- a/packages/app-store/routing-forms/trpc/onFormSubmission.test.ts +++ b/packages/app-store/routing-forms/lib/formSubmissionUtils.test.ts @@ -6,7 +6,7 @@ import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload"; import { WebhookTriggerEvents } from "@calcom/prisma/enums"; -import { _onFormSubmission } from "./utils"; +import { _onFormSubmission } from "./formSubmissionUtils"; // Mock dependencies vi.mock("@calcom/lib/getOrgIdFromMemberOrTeamId", () => ({ diff --git a/packages/app-store/routing-forms/lib/formSubmissionUtils.ts b/packages/app-store/routing-forms/lib/formSubmissionUtils.ts index 15dee2b9f3240b..dc177222d0f4e3 100644 --- a/packages/app-store/routing-forms/lib/formSubmissionUtils.ts +++ b/packages/app-store/routing-forms/lib/formSubmissionUtils.ts @@ -1,13 +1,244 @@ import type { Prisma } from "@prisma/client"; +import type { App_RoutingForms_Form, User } from "@prisma/client"; +import dayjs from "@calcom/dayjs"; +import type { Tasker } from "@calcom/features/tasker/tasker"; +import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; +import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload"; +import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; +import logger from "@calcom/lib/logger"; +import { withReporting } from "@calcom/lib/sentryWrapper"; import { prisma } from "@calcom/prisma"; -import type { App_RoutingForms_Form } from "@calcom/prisma/client"; +import { WebhookTriggerEvents } from "@calcom/prisma/enums"; import { RoutingFormSettings } from "@calcom/prisma/zod-utils"; +import type { Ensure } from "@calcom/types/utils"; import { TRPCError } from "@trpc/server"; -import { onFormSubmission } from "../trpc/utils"; -import type { FormResponse, SerializableForm } from "../types/types"; +import type { FormResponse, SerializableForm, SerializableField, OrderedResponses } from "../types/types"; + +const moduleLogger = logger.getSubLogger({ prefix: ["routing-forms/lib/formSubmissionUtils"] }); + +type SelectFieldWebhookResponse = string | number | string[] | { label: string; id: string | null }; +export type FORM_SUBMITTED_WEBHOOK_RESPONSES = Record< + string, + { + /** + * Deprecates `value` prop as it now has both the id(that doesn't change) and the label(that can change but is human friendly) + */ + response: number | string | string[] | SelectFieldWebhookResponse | SelectFieldWebhookResponse[]; + /** + * @deprecated Use `response` instead + */ + value: FormResponse[keyof FormResponse]["value"]; + } +>; + +function isOptionsField(field: Pick) { + return (field.type === "select" || field.type === "multiselect") && field.options; +} + +export function getFieldResponse({ + field, + fieldResponseValue, +}: { + fieldResponseValue: FormResponse[keyof FormResponse]["value"]; + field: Pick; +}) { + if (!isOptionsField(field)) { + return { + value: fieldResponseValue, + response: fieldResponseValue, + }; + } + + if (!field.options) { + return { + value: fieldResponseValue, + response: fieldResponseValue, + }; + } + + const valueArray = fieldResponseValue instanceof Array ? fieldResponseValue : [fieldResponseValue]; + + const chosenOptions = valueArray.map((idOrLabel) => { + const foundOptionById = field.options?.find((option) => { + return option.id === idOrLabel; + }); + if (foundOptionById) { + return { + label: foundOptionById.label, + id: foundOptionById.id, + }; + } else { + return { + label: idOrLabel.toString(), + id: null, + }; + } + }); + return { + // value is a legacy prop that is just sending the labels which can change + value: chosenOptions.map((option) => option.label), + // response is new prop that is sending the label along with id(which doesn't change) + response: chosenOptions, + }; +} + +export const sendResponseEmail = async ( + form: Pick, + orderedResponses: OrderedResponses, + toAddresses: string[] +) => { + try { + if (typeof window === "undefined") { + const { default: ResponseEmail } = await import("../emails/templates/response-email"); + const email = new ResponseEmail({ form: form, toAddresses, orderedResponses }); + await email.sendEmail(); + } + } catch (e) { + moduleLogger.error("Error sending response email", e); + } +}; + +function getWebhookTargetEntity(form: { teamId?: number | null; user: { id: number } }) { + // If it's a team form, the target must be team webhook + // If it's a user form, the target must be user webhook + const isTeamForm = form.teamId; + return { userId: isTeamForm ? null : form.user.id, teamId: isTeamForm ? form.teamId : null }; +} + +/** + * Not called in preview mode or dry run mode + * It takes care of sending webhooks and emails for form submissions + */ +export async function _onFormSubmission( + form: Ensure< + SerializableForm & { user: Pick; userWithEmails?: string[] }, + "fields" + >, + response: FormResponse, + responseId: number, + chosenAction?: { + type: "customPageMessage" | "externalRedirectUrl" | "eventTypeRedirectUrl"; + value: string; + } +) { + const fieldResponsesByIdentifier: FORM_SUBMITTED_WEBHOOK_RESPONSES = {}; + + for (const [fieldId, fieldResponse] of Object.entries(response)) { + const field = form.fields.find((f) => f.id === fieldId); + if (!field) { + throw new Error(`Field with id ${fieldId} not found`); + } + // Use the label lowercased as the key to identify a field. + // TODO: We seem to be using label from the response, Can we not use the field.label + const key = + form.fields.find((f) => f.id === fieldId)?.identifier || + (fieldResponse.label as keyof typeof fieldResponsesByIdentifier); + fieldResponsesByIdentifier[key] = getFieldResponse({ + fieldResponseValue: fieldResponse.value, + field, + }); + } + + const { userId, teamId } = getWebhookTargetEntity(form); + + const orgId = await getOrgIdFromMemberOrTeamId({ memberId: userId, teamId }); + + const subscriberOptionsFormSubmitted = { + userId, + teamId, + orgId, + triggerEvent: WebhookTriggerEvents.FORM_SUBMITTED, + }; + + const subscriberOptionsFormSubmittedNoEvent = { + userId, + teamId, + orgId, + triggerEvent: WebhookTriggerEvents.FORM_SUBMITTED_NO_EVENT, + }; + + const webhooksFormSubmitted = await getWebhooks(subscriberOptionsFormSubmitted); + const webhooksFormSubmittedNoEvent = await getWebhooks(subscriberOptionsFormSubmittedNoEvent); + + const promisesFormSubmitted = webhooksFormSubmitted.map((webhook) => { + sendGenericWebhookPayload({ + secretKey: webhook.secret, + triggerEvent: "FORM_SUBMITTED", + createdAt: new Date().toISOString(), + webhook, + data: { + formId: form.id, + formName: form.name, + teamId: form.teamId, + responses: fieldResponsesByIdentifier, + }, + rootData: { + // Send responses unwrapped at root level for backwards compatibility + ...Object.entries(fieldResponsesByIdentifier).reduce((acc, [key, value]) => { + acc[key] = value.value; + return acc; + }, {} as Record), + }, + }).catch((e) => { + console.error(`Error executing routing form webhook`, webhook, e); + }); + }); + + if (typeof window === "undefined") { + try { + const tasker: Tasker = await (await import("@calcom/features/tasker")).default; + const promisesFormSubmittedNoEvent = webhooksFormSubmittedNoEvent.map((webhook) => { + const scheduledAt = dayjs().add(15, "minute").toDate(); + + return tasker.create( + "triggerFormSubmittedNoEventWebhook", + { + responseId, + form: { + id: form.id, + name: form.name, + teamId: form.teamId ?? null, + }, + responses: fieldResponsesByIdentifier, + redirect: chosenAction, + webhook, + }, + { scheduledAt } + ); + }); + + const promises = [...promisesFormSubmitted, ...promisesFormSubmittedNoEvent]; + + await Promise.all(promises); + const orderedResponses = form.fields.reduce((acc, field) => { + acc.push(response[field.id]); + return acc; + }, [] as OrderedResponses); + + if (form.teamId) { + if (form.userWithEmails?.length) { + moduleLogger.debug( + `Preparing to send Form Response email for Form:${form.id} to users: ${form.userWithEmails.join( + "," + )}` + ); + await sendResponseEmail(form, orderedResponses, form.userWithEmails); + } + } else if (form.settings?.emailOwnerOnSubmission) { + moduleLogger.debug( + `Preparing to send Form Response email for Form:${form.id} to form owner: ${form.user.email}` + ); + await sendResponseEmail(form, orderedResponses, [form.user.email]); + } + } catch (e) { + moduleLogger.error("Error triggering routing form response side effects", e); + } + } +} +export const onFormSubmission = withReporting(_onFormSubmission, "onFormSubmission"); export type TargetRoutingFormForResponse = SerializableForm< App_RoutingForms_Form & { diff --git a/packages/app-store/routing-forms/trpc-router.ts b/packages/app-store/routing-forms/trpc-router.ts deleted file mode 100644 index 2adeb779301937..00000000000000 --- a/packages/app-store/routing-forms/trpc-router.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./trpc/_router"; diff --git a/packages/app-store/routing-forms/trpc/utils.ts b/packages/app-store/routing-forms/trpc/utils.ts deleted file mode 100644 index 5cca3bf78f664b..00000000000000 --- a/packages/app-store/routing-forms/trpc/utils.ts +++ /dev/null @@ -1,237 +0,0 @@ -import type { App_RoutingForms_Form, User } from "@prisma/client"; - -import dayjs from "@calcom/dayjs"; -import type { Tasker } from "@calcom/features/tasker/tasker"; -import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; -import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload"; -import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId"; -import logger from "@calcom/lib/logger"; -import { withReporting } from "@calcom/lib/sentryWrapper"; -import { WebhookTriggerEvents } from "@calcom/prisma/enums"; -import type { Ensure } from "@calcom/types/utils"; - -import type { SerializableField, OrderedResponses } from "../types/types"; -import type { FormResponse, SerializableForm } from "../types/types"; - -const moduleLogger = logger.getSubLogger({ prefix: ["routing-forms/trpc/utils"] }); - -type SelectFieldWebhookResponse = string | number | string[] | { label: string; id: string | null }; -export type FORM_SUBMITTED_WEBHOOK_RESPONSES = Record< - string, - { - /** - * Deprecates `value` prop as it now has both the id(that doesn't change) and the label(that can change but is human friendly) - */ - response: number | string | string[] | SelectFieldWebhookResponse | SelectFieldWebhookResponse[]; - /** - * @deprecated Use `response` instead - */ - value: FormResponse[keyof FormResponse]["value"]; - } ->; - -function isOptionsField(field: Pick) { - return (field.type === "select" || field.type === "multiselect") && field.options; -} - -export function getFieldResponse({ - field, - fieldResponseValue, -}: { - fieldResponseValue: FormResponse[keyof FormResponse]["value"]; - field: Pick; -}) { - if (!isOptionsField(field)) { - return { - value: fieldResponseValue, - response: fieldResponseValue, - }; - } - - if (!field.options) { - return { - value: fieldResponseValue, - response: fieldResponseValue, - }; - } - - const valueArray = fieldResponseValue instanceof Array ? fieldResponseValue : [fieldResponseValue]; - - const chosenOptions = valueArray.map((idOrLabel) => { - const foundOptionById = field.options?.find((option) => { - return option.id === idOrLabel; - }); - if (foundOptionById) { - return { - label: foundOptionById.label, - id: foundOptionById.id, - }; - } else { - return { - label: idOrLabel.toString(), - id: null, - }; - } - }); - return { - // value is a legacy prop that is just sending the labels which can change - value: chosenOptions.map((option) => option.label), - // response is new prop that is sending the label along with id(which doesn't change) - response: chosenOptions, - }; -} - -/** - * Not called in preview mode or dry run mode - * It takes care of sending webhooks and emails for form submissions - */ -export async function _onFormSubmission( - form: Ensure< - SerializableForm & { user: Pick; userWithEmails?: string[] }, - "fields" - >, - response: FormResponse, - responseId: number, - chosenAction?: { - type: "customPageMessage" | "externalRedirectUrl" | "eventTypeRedirectUrl"; - value: string; - } -) { - const fieldResponsesByIdentifier: FORM_SUBMITTED_WEBHOOK_RESPONSES = {}; - - for (const [fieldId, fieldResponse] of Object.entries(response)) { - const field = form.fields.find((f) => f.id === fieldId); - if (!field) { - throw new Error(`Field with id ${fieldId} not found`); - } - // Use the label lowercased as the key to identify a field. - // TODO: We seem to be using label from the response, Can we not use the field.label - const key = - form.fields.find((f) => f.id === fieldId)?.identifier || - (fieldResponse.label as keyof typeof fieldResponsesByIdentifier); - fieldResponsesByIdentifier[key] = getFieldResponse({ - fieldResponseValue: fieldResponse.value, - field, - }); - } - - const { userId, teamId } = getWebhookTargetEntity(form); - - const orgId = await getOrgIdFromMemberOrTeamId({ memberId: userId, teamId }); - - const subscriberOptionsFormSubmitted = { - userId, - teamId, - orgId, - triggerEvent: WebhookTriggerEvents.FORM_SUBMITTED, - }; - - const subscriberOptionsFormSubmittedNoEvent = { - userId, - teamId, - orgId, - triggerEvent: WebhookTriggerEvents.FORM_SUBMITTED_NO_EVENT, - }; - - const webhooksFormSubmitted = await getWebhooks(subscriberOptionsFormSubmitted); - const webhooksFormSubmittedNoEvent = await getWebhooks(subscriberOptionsFormSubmittedNoEvent); - - const promisesFormSubmitted = webhooksFormSubmitted.map((webhook) => { - sendGenericWebhookPayload({ - secretKey: webhook.secret, - triggerEvent: "FORM_SUBMITTED", - createdAt: new Date().toISOString(), - webhook, - data: { - formId: form.id, - formName: form.name, - teamId: form.teamId, - responses: fieldResponsesByIdentifier, - }, - rootData: { - // Send responses unwrapped at root level for backwards compatibility - ...Object.entries(fieldResponsesByIdentifier).reduce((acc, [key, value]) => { - acc[key] = value.value; - return acc; - }, {} as Record), - }, - }).catch((e) => { - console.error(`Error executing routing form webhook`, webhook, e); - }); - }); - - if (typeof window === "undefined") { - try { - const tasker: Tasker = await (await import("@calcom/features/tasker")).default; - const promisesFormSubmittedNoEvent = webhooksFormSubmittedNoEvent.map((webhook) => { - const scheduledAt = dayjs().add(15, "minute").toDate(); - - return tasker.create( - "triggerFormSubmittedNoEventWebhook", - { - responseId, - form: { - id: form.id, - name: form.name, - teamId: form.teamId ?? null, - }, - responses: fieldResponsesByIdentifier, - redirect: chosenAction, - webhook, - }, - { scheduledAt } - ); - }); - - const promises = [...promisesFormSubmitted, ...promisesFormSubmittedNoEvent]; - - await Promise.all(promises); - const orderedResponses = form.fields.reduce((acc, field) => { - acc.push(response[field.id]); - return acc; - }, [] as OrderedResponses); - - if (form.teamId) { - if (form.userWithEmails?.length) { - moduleLogger.debug( - `Preparing to send Form Response email for Form:${form.id} to users: ${form.userWithEmails.join( - "," - )}` - ); - await sendResponseEmail(form, orderedResponses, form.userWithEmails); - } - } else if (form.settings?.emailOwnerOnSubmission) { - moduleLogger.debug( - `Preparing to send Form Response email for Form:${form.id} to form owner: ${form.user.email}` - ); - await sendResponseEmail(form, orderedResponses, [form.user.email]); - } - } catch (e) { - moduleLogger.error("Error triggering routing form response side effects", e); - } - } -} -export const onFormSubmission = withReporting(_onFormSubmission, "onFormSubmission"); - -export const sendResponseEmail = async ( - form: Pick, - orderedResponses: OrderedResponses, - toAddresses: string[] -) => { - try { - if (typeof window === "undefined") { - const { default: ResponseEmail } = await import("../emails/templates/response-email"); - const email = new ResponseEmail({ form: form, toAddresses, orderedResponses }); - await email.sendEmail(); - } - } catch (e) { - moduleLogger.error("Error sending response email", e); - } -}; - -function getWebhookTargetEntity(form: { teamId?: number | null; user: { id: number } }) { - // If it's a team form, the target must be team webhook - // If it's a user form, the target must be user webhook - const isTeamForm = form.teamId; - return { userId: isTeamForm ? null : form.user.id, teamId: isTeamForm ? form.teamId : null }; -} diff --git a/packages/features/tasker/tasks/triggerFormSubmittedNoEvent/triggerFormSubmittedNoEventWebhook.ts b/packages/features/tasker/tasks/triggerFormSubmittedNoEvent/triggerFormSubmittedNoEventWebhook.ts index 324ddc46bbb2c2..d93d3b09efe85f 100644 --- a/packages/features/tasker/tasks/triggerFormSubmittedNoEvent/triggerFormSubmittedNoEventWebhook.ts +++ b/packages/features/tasker/tasks/triggerFormSubmittedNoEvent/triggerFormSubmittedNoEventWebhook.ts @@ -1,7 +1,7 @@ import { z } from "zod"; +import type { FORM_SUBMITTED_WEBHOOK_RESPONSES } from "@calcom/app-store/routing-forms/lib/formSubmissionUtils"; import incompleteBookingActionFunctions from "@calcom/app-store/routing-forms/lib/incompleteBooking/actionFunctions"; -import type { FORM_SUBMITTED_WEBHOOK_RESPONSES } from "@calcom/app-store/routing-forms/trpc/utils"; import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload"; import prisma from "@calcom/prisma"; diff --git a/packages/app-store/basecamp3/trpc/_router.ts b/packages/trpc/server/routers/apps/basecamp3/_router.ts similarity index 100% rename from packages/app-store/basecamp3/trpc/_router.ts rename to packages/trpc/server/routers/apps/basecamp3/_router.ts diff --git a/packages/app-store/basecamp3/trpc/projectMutation.handler.ts b/packages/trpc/server/routers/apps/basecamp3/projectMutation.handler.ts similarity index 89% rename from packages/app-store/basecamp3/trpc/projectMutation.handler.ts rename to packages/trpc/server/routers/apps/basecamp3/projectMutation.handler.ts index ece4c5f15a963e..21ad4a30f629a6 100644 --- a/packages/app-store/basecamp3/trpc/projectMutation.handler.ts +++ b/packages/trpc/server/routers/apps/basecamp3/projectMutation.handler.ts @@ -1,12 +1,12 @@ +import getAppKeysFromSlug from "@calcom/app-store/_utils/getAppKeysFromSlug"; +import { refreshAccessToken } from "@calcom/app-store/basecamp3/lib/helpers"; +import type { BasecampToken } from "@calcom/app-store/basecamp3/lib/types"; import type { PrismaClient } from "@calcom/prisma/client"; import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; -import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug"; -import { refreshAccessToken } from "../lib/helpers"; -import type { BasecampToken } from "../lib/types"; import type { TProjectMutationInputSchema } from "./projectMutation.schema"; interface ProjectMutationHandlerOptions { diff --git a/packages/app-store/basecamp3/trpc/projectMutation.schema.ts b/packages/trpc/server/routers/apps/basecamp3/projectMutation.schema.ts similarity index 100% rename from packages/app-store/basecamp3/trpc/projectMutation.schema.ts rename to packages/trpc/server/routers/apps/basecamp3/projectMutation.schema.ts diff --git a/packages/app-store/basecamp3/trpc/projects.handler.ts b/packages/trpc/server/routers/apps/basecamp3/projects.handler.ts similarity index 85% rename from packages/app-store/basecamp3/trpc/projects.handler.ts rename to packages/trpc/server/routers/apps/basecamp3/projects.handler.ts index c53f9cc3970b48..c6f532c3112bb7 100644 --- a/packages/app-store/basecamp3/trpc/projects.handler.ts +++ b/packages/trpc/server/routers/apps/basecamp3/projects.handler.ts @@ -1,13 +1,12 @@ +import getAppKeysFromSlug from "@calcom/app-store/_utils/getAppKeysFromSlug"; +import { refreshAccessToken } from "@calcom/app-store/basecamp3/lib/helpers"; +import type { BasecampToken } from "@calcom/app-store/basecamp3/lib/types"; import type { PrismaClient } from "@calcom/prisma/client"; import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; -import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug"; -import { refreshAccessToken } from "../lib/helpers"; -import type { BasecampToken } from "../lib/types"; - interface ProjectsHandlerOptions { ctx: { prisma: PrismaClient; diff --git a/packages/app-store/routing-forms/trpc/_router.ts b/packages/trpc/server/routers/apps/routing-forms/_router.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/_router.ts rename to packages/trpc/server/routers/apps/routing-forms/_router.ts diff --git a/packages/app-store/routing-forms/trpc/deleteForm.handler.ts b/packages/trpc/server/routers/apps/routing-forms/deleteForm.handler.ts similarity index 94% rename from packages/app-store/routing-forms/trpc/deleteForm.handler.ts rename to packages/trpc/server/routers/apps/routing-forms/deleteForm.handler.ts index f7a39dc9afee27..07db89f09f09b9 100644 --- a/packages/app-store/routing-forms/trpc/deleteForm.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/deleteForm.handler.ts @@ -1,3 +1,4 @@ +import getConnectedForms from "@calcom/app-store/routing-forms/lib/getConnectedForms"; import { entityPrismaWhereClause } from "@calcom/lib/entityPermissionUtils.server"; import type { PrismaClient } from "@calcom/prisma"; import { MembershipRole } from "@calcom/prisma/enums"; @@ -5,7 +6,6 @@ import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; -import getConnectedForms from "../lib/getConnectedForms"; import type { TDeleteFormInputSchema } from "./deleteForm.schema"; import { checkPermissionOnExistingRoutingForm } from "./permissions"; diff --git a/packages/app-store/routing-forms/trpc/deleteForm.schema.ts b/packages/trpc/server/routers/apps/routing-forms/deleteForm.schema.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/deleteForm.schema.ts rename to packages/trpc/server/routers/apps/routing-forms/deleteForm.schema.ts diff --git a/packages/app-store/routing-forms/trpc/formMutation.handler.ts b/packages/trpc/server/routers/apps/routing-forms/formMutation.handler.ts similarity index 94% rename from packages/app-store/routing-forms/trpc/formMutation.handler.ts rename to packages/trpc/server/routers/apps/routing-forms/formMutation.handler.ts index c60f83006b0807..88979d2188bd43 100644 --- a/packages/app-store/routing-forms/trpc/formMutation.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/formMutation.handler.ts @@ -1,6 +1,13 @@ import type { App_RoutingForms_Form } from "@prisma/client"; import { Prisma } from "@prisma/client"; +import { createFallbackRoute } from "@calcom/app-store/routing-forms/lib/createFallbackRoute"; +import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm"; +import { isFallbackRoute } from "@calcom/app-store/routing-forms/lib/isFallbackRoute"; +import isRouter from "@calcom/app-store/routing-forms/lib/isRouter"; +import isRouterLinkedField from "@calcom/app-store/routing-forms/lib/isRouterLinkedField"; +import type { SerializableForm } from "@calcom/app-store/routing-forms/types/types"; +import { zodFields, zodRouterRoute, zodRoutes } from "@calcom/app-store/routing-forms/zod"; import { PermissionCheckService } from "@calcom/features/pbac/services/permission-check.service"; import { entityPrismaWhereClause, canEditEntity } from "@calcom/lib/entityPermissionUtils.server"; import type { PrismaClient } from "@calcom/prisma"; @@ -9,14 +16,6 @@ import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; -import { createFallbackRoute } from "../lib/createFallbackRoute"; -import { getSerializableForm } from "../lib/getSerializableForm"; -import { isFallbackRoute } from "../lib/isFallbackRoute"; -import { isFormCreateEditAllowed } from "../lib/isFormCreateEditAllowed"; -import isRouter from "../lib/isRouter"; -import isRouterLinkedField from "../lib/isRouterLinkedField"; -import type { SerializableForm } from "../types/types"; -import { zodFields, zodRouterRoute, zodRoutes } from "../zod"; import type { TFormMutationInputSchema } from "./formMutation.schema"; import { checkPermissionOnExistingRoutingForm } from "./permissions"; @@ -69,8 +68,8 @@ export const formMutationHandler = async ({ ctx, input }: FormMutationHandlerOpt inputFields = inputFields || []; inputRoutes = inputRoutes || []; - type InputFields = typeof inputFields; - type InputRoutes = typeof inputRoutes; + type InputFields = NonNullable; + type InputRoutes = NonNullable; let routes: InputRoutes; let fields: InputFields; type DuplicateFrom = NonNullable; diff --git a/packages/app-store/routing-forms/trpc/formMutation.schema.ts b/packages/trpc/server/routers/apps/routing-forms/formMutation.schema.ts similarity index 88% rename from packages/app-store/routing-forms/trpc/formMutation.schema.ts rename to packages/trpc/server/routers/apps/routing-forms/formMutation.schema.ts index c6adfe86e4710f..0f8e5f1db307ab 100644 --- a/packages/app-store/routing-forms/trpc/formMutation.schema.ts +++ b/packages/trpc/server/routers/apps/routing-forms/formMutation.schema.ts @@ -1,9 +1,8 @@ import z from "zod"; +import { zodFields, zodRoutes } from "@calcom/app-store/routing-forms/zod"; import { RoutingFormSettings } from "@calcom/prisma/zod-utils"; -import { zodFields, zodRoutes } from "../zod"; - export const ZFormMutationInputSchema = z.object({ id: z.string(), name: z.string(), diff --git a/packages/app-store/routing-forms/trpc/formQuery.handler.ts b/packages/trpc/server/routers/apps/routing-forms/formQuery.handler.ts similarity index 92% rename from packages/app-store/routing-forms/trpc/formQuery.handler.ts rename to packages/trpc/server/routers/apps/routing-forms/formQuery.handler.ts index f518b02a71a008..05a0b9c4185fa0 100644 --- a/packages/app-store/routing-forms/trpc/formQuery.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/formQuery.handler.ts @@ -1,11 +1,9 @@ +import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm"; import { entityPrismaWhereClause } from "@calcom/lib/entityPermissionUtils.server"; import type { PrismaClient } from "@calcom/prisma"; import { MembershipRole } from "@calcom/prisma/enums"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; -import { TRPCError } from "@trpc/server"; - -import { getSerializableForm } from "../lib/getSerializableForm"; import type { TFormQueryInputSchema } from "./formQuery.schema"; import { checkPermissionOnExistingRoutingForm } from "./permissions"; diff --git a/packages/app-store/routing-forms/trpc/formQuery.schema.ts b/packages/trpc/server/routers/apps/routing-forms/formQuery.schema.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/formQuery.schema.ts rename to packages/trpc/server/routers/apps/routing-forms/formQuery.schema.ts diff --git a/packages/app-store/routing-forms/trpc/forms.handler.ts b/packages/trpc/server/routers/apps/routing-forms/forms.handler.ts similarity index 96% rename from packages/app-store/routing-forms/trpc/forms.handler.ts rename to packages/trpc/server/routers/apps/routing-forms/forms.handler.ts index d731550ad7d671..d29e291d496268 100644 --- a/packages/app-store/routing-forms/trpc/forms.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/forms.handler.ts @@ -1,5 +1,7 @@ import type { z } from "zod"; +import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm"; +import type { zodFields, zodRoutes } from "@calcom/app-store/routing-forms/zod"; import { hasFilter } from "@calcom/features/filters/lib/hasFilter"; import { entityPrismaWhereClause, canEditEntity } from "@calcom/lib/entityPermissionUtils.server"; import logger from "@calcom/lib/logger"; @@ -9,8 +11,6 @@ import type { Prisma } from "@calcom/prisma/client"; import { entries } from "@calcom/prisma/zod-utils"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; -import { getSerializableForm } from "../lib/getSerializableForm"; -import type { zodFields, zodRoutes } from "../zod"; import type { TFormSchema } from "./forms.schema"; interface FormsHandlerOptions { diff --git a/packages/app-store/routing-forms/trpc/forms.schema.ts b/packages/trpc/server/routers/apps/routing-forms/forms.schema.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/forms.schema.ts rename to packages/trpc/server/routers/apps/routing-forms/forms.schema.ts diff --git a/packages/app-store/routing-forms/trpc/getAttributesForTeam.handler.ts b/packages/trpc/server/routers/apps/routing-forms/getAttributesForTeam.handler.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/getAttributesForTeam.handler.ts rename to packages/trpc/server/routers/apps/routing-forms/getAttributesForTeam.handler.ts diff --git a/packages/app-store/routing-forms/trpc/getAttributesForTeam.schema.ts b/packages/trpc/server/routers/apps/routing-forms/getAttributesForTeam.schema.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/getAttributesForTeam.schema.ts rename to packages/trpc/server/routers/apps/routing-forms/getAttributesForTeam.schema.ts diff --git a/packages/app-store/routing-forms/trpc/getIncompleteBookingSettings.handler.ts b/packages/trpc/server/routers/apps/routing-forms/getIncompleteBookingSettings.handler.ts similarity index 95% rename from packages/app-store/routing-forms/trpc/getIncompleteBookingSettings.handler.ts rename to packages/trpc/server/routers/apps/routing-forms/getIncompleteBookingSettings.handler.ts index 90a4526a3a6f1f..13ce3795216673 100644 --- a/packages/app-store/routing-forms/trpc/getIncompleteBookingSettings.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/getIncompleteBookingSettings.handler.ts @@ -1,10 +1,10 @@ +import { enabledIncompleteBookingApps } from "@calcom/app-store/routing-forms/lib/enabledIncompleteBookingApps"; import type { PrismaClient } from "@calcom/prisma"; import { safeCredentialSelect } from "@calcom/prisma/selects/credential"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; -import { enabledIncompleteBookingApps } from "../lib/enabledIncompleteBookingApps"; import type { TGetIncompleteBookingSettingsInputSchema } from "./getIncompleteBookingSettings.schema"; interface GetIncompleteBookingSettingsOptions { diff --git a/packages/app-store/routing-forms/trpc/getIncompleteBookingSettings.schema.ts b/packages/trpc/server/routers/apps/routing-forms/getIncompleteBookingSettings.schema.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/getIncompleteBookingSettings.schema.ts rename to packages/trpc/server/routers/apps/routing-forms/getIncompleteBookingSettings.schema.ts diff --git a/packages/app-store/routing-forms/trpc/getResponseWithFormFields.handler.ts b/packages/trpc/server/routers/apps/routing-forms/getResponseWithFormFields.handler.ts similarity index 90% rename from packages/app-store/routing-forms/trpc/getResponseWithFormFields.handler.ts rename to packages/trpc/server/routers/apps/routing-forms/getResponseWithFormFields.handler.ts index 307b868687990b..4c710033519c9d 100644 --- a/packages/app-store/routing-forms/trpc/getResponseWithFormFields.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/getResponseWithFormFields.handler.ts @@ -1,5 +1,8 @@ import type { z } from "zod"; +import { enrichFormWithMigrationData } from "@calcom/app-store/routing-forms/enrichFormWithMigrationData"; +import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm"; +import type { FormResponse } from "@calcom/app-store/routing-forms/types/types"; import { canAccessEntity } from "@calcom/lib/entityPermissionUtils.server"; import { getTranslation } from "@calcom/lib/server/i18n"; import { prisma } from "@calcom/prisma"; @@ -7,9 +10,6 @@ import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; -import { enrichFormWithMigrationData } from "../enrichFormWithMigrationData"; -import { getSerializableForm } from "../lib/getSerializableForm"; -import type { FormResponse } from "../types/types"; import type { ZFormByResponseIdInputSchema } from "./_router"; type GetResponseWithFormFieldsOptions = { diff --git a/packages/app-store/routing-forms/trpc/permissions.ts b/packages/trpc/server/routers/apps/routing-forms/permissions.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/permissions.ts rename to packages/trpc/server/routers/apps/routing-forms/permissions.ts diff --git a/packages/app-store/routing-forms/trpc/procedures/forms.ts b/packages/trpc/server/routers/apps/routing-forms/procedures/forms.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/procedures/forms.ts rename to packages/trpc/server/routers/apps/routing-forms/procedures/forms.ts diff --git a/packages/app-store/routing-forms/trpc/saveIncompleteBookingSettings.handler.ts b/packages/trpc/server/routers/apps/routing-forms/saveIncompleteBookingSettings.handler.ts similarity index 94% rename from packages/app-store/routing-forms/trpc/saveIncompleteBookingSettings.handler.ts rename to packages/trpc/server/routers/apps/routing-forms/saveIncompleteBookingSettings.handler.ts index acf97d9c276ee8..24c888bba7b797 100644 --- a/packages/app-store/routing-forms/trpc/saveIncompleteBookingSettings.handler.ts +++ b/packages/trpc/server/routers/apps/routing-forms/saveIncompleteBookingSettings.handler.ts @@ -1,10 +1,10 @@ +import incompleteBookingActionDataSchemas from "@calcom/app-store/routing-forms/lib/incompleteBooking/actionDataSchemas"; import logger from "@calcom/lib/logger"; import type { PrismaClient } from "@calcom/prisma"; import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; -import incompleteBookingActionDataSchemas from "../lib/incompleteBooking/actionDataSchemas"; import type { TSaveIncompleteBookingSettingsInputSchema } from "./saveIncompleteBookingSettings.schema"; const log = logger.getSubLogger({ prefix: ["incomplete-booking"] }); diff --git a/packages/app-store/routing-forms/trpc/saveIncompleteBookingSettings.schema.ts b/packages/trpc/server/routers/apps/routing-forms/saveIncompleteBookingSettings.schema.ts similarity index 100% rename from packages/app-store/routing-forms/trpc/saveIncompleteBookingSettings.schema.ts rename to packages/trpc/server/routers/apps/routing-forms/saveIncompleteBookingSettings.schema.ts diff --git a/packages/trpc/server/routers/viewer/_router.tsx b/packages/trpc/server/routers/viewer/_router.tsx index 8875f2fc79e5ab..edfee9705e6a80 100644 --- a/packages/trpc/server/routers/viewer/_router.tsx +++ b/packages/trpc/server/routers/viewer/_router.tsx @@ -1,10 +1,10 @@ -import app_Basecamp3 from "@calcom/app-store/basecamp3/trpc-router"; -import app_RoutingForms from "@calcom/app-store/routing-forms/trpc-router"; import { userAdminRouter } from "@calcom/features/ee/users/server/trpc-router"; import { featureFlagRouter } from "@calcom/features/flags/server/router"; import { insightsRouter } from "@calcom/features/insights/server/trpc-router"; import { router } from "../../trpc"; +import app_Basecamp3 from "../apps/basecamp3/_router"; +import app_RoutingForms from "../apps/routing-forms/_router"; import { loggedInViewerRouter } from "../loggedInViewer/_router"; import { publicViewerRouter } from "../publicViewer/_router"; import { timezonesRouter } from "../publicViewer/timezones/_router"; diff --git a/packages/trpc/server/routers/viewer/workflows/workflowOrder.handler.ts b/packages/trpc/server/routers/viewer/workflows/workflowOrder.handler.ts index 88ec39324fd0e6..b1d489efe4a1ca 100644 --- a/packages/trpc/server/routers/viewer/workflows/workflowOrder.handler.ts +++ b/packages/trpc/server/routers/viewer/workflows/workflowOrder.handler.ts @@ -1,4 +1,3 @@ -import type { TFormSchema } from "@calcom/app-store/routing-forms/trpc/forms.schema"; import { hasFilter } from "@calcom/features/filters/lib/hasFilter"; import { prisma } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; @@ -7,6 +6,7 @@ import type { TrpcSessionUser } from "@calcom/trpc/server/types"; import { TRPCError } from "@trpc/server"; +import type { TFormSchema } from "../../apps/routing-forms/forms.schema"; import type { TWorkflowOrderInputSchema } from "./workflowOrder.schema"; type RoutingFormOrderOptions = {