refactor: remove @calcom/features dependency from @calcom/prisma (#23820)
This commit is contained in:
@@ -4,8 +4,8 @@ import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { validPassword } from "@calcom/features/auth/lib/validPassword";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { IdentityProvider } from "@calcom/prisma/enums";
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import z from "zod";
|
||||
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { isPasswordValid } from "@calcom/features/auth/lib/isPasswordValid";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { isPasswordValid } from "@calcom/lib/auth/isPasswordValid";
|
||||
import { emailRegex } from "@calcom/lib/emailSchema";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
|
||||
@@ -5,7 +5,7 @@ import React from "react";
|
||||
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { isPasswordValid } from "@calcom/features/auth/lib/isPasswordValid";
|
||||
import { isPasswordValid } from "@calcom/lib/auth/isPasswordValid";
|
||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { emailRegex } from "@calcom/lib/emailSchema";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
|
||||
@@ -2,13 +2,13 @@ import type { GetServerSidePropsContext } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData";
|
||||
import type { LocationObject } from "@calcom/app-store/locations";
|
||||
import { isConferencing as isConferencingApp } from "@calcom/app-store/utils";
|
||||
import { getLocale } from "@calcom/features/auth/lib/getLocale";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { AppOnboardingSteps } from "@calcom/lib/apps/appOnboardingSteps";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
|
||||
import type { LocationObject } from "@calcom/app-store/locations";
|
||||
import { UserRepository } from "@calcom/lib/server/repository/user";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
"devDependencies": {
|
||||
"@changesets/changelog-github": "^0.5.1",
|
||||
"@changesets/cli": "2.29.4",
|
||||
"@faker-js/faker": "9.2.0",
|
||||
"@jetstreamapp/soql-parser-js": "^6.1.0",
|
||||
"@playwright/test": "^1.45.3",
|
||||
"@snaplet/copycat": "^4.1.0",
|
||||
|
||||
@@ -16,6 +16,7 @@ import createUsersAndConnectToOrg from "@calcom/features/ee/dsync/lib/users/crea
|
||||
import ImpersonationProvider from "@calcom/features/ee/impersonation/lib/ImpersonationProvider";
|
||||
import { getOrgFullOrigin, subdomainSuffix } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import { clientSecretVerifier, hostedCal, isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||
import { isPasswordValid } from "@calcom/lib/auth/isPasswordValid";
|
||||
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
||||
import {
|
||||
GOOGLE_CALENDAR_SCOPES,
|
||||
@@ -46,7 +47,6 @@ import { teamMetadataSchema, userMetadata } from "@calcom/prisma/zod-utils";
|
||||
import { getOrgUsernameFromEmail } from "../signup/utils/getOrgUsernameFromEmail";
|
||||
import { ErrorCode } from "./ErrorCode";
|
||||
import { dub } from "./dub";
|
||||
import { isPasswordValid } from "./isPasswordValid";
|
||||
import CalComAdapter from "./next-auth-custom-adapter";
|
||||
import { verifyPassword } from "./verifyPassword";
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ import { cookies, headers } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { getPremiumMonthlyPlanPriceId } from "@calcom/app-store/stripepayment/lib/utils";
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { sendEmailVerification } from "@calcom/features/auth/lib/verifyEmail";
|
||||
import { createOrUpdateMemberships } from "@calcom/features/auth/signup/utils/createOrUpdateMemberships";
|
||||
import { prefillAvatar } from "@calcom/features/auth/signup/utils/prefillAvatar";
|
||||
import { StripeBillingService } from "@calcom/features/ee/billing/stripe-billling-service";
|
||||
import { checkIfEmailIsBlockedInWatchlistController } from "@calcom/features/watchlist/operations/check-if-email-in-watchlist.controller";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { getLocaleFromRequest } from "@calcom/lib/getLocaleFromRequest";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { checkPremiumUsername } from "@calcom/ee/common/lib/checkPremiumUsername";
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { sendEmailVerification } from "@calcom/features/auth/lib/verifyEmail";
|
||||
import { createOrUpdateMemberships } from "@calcom/features/auth/signup/utils/createOrUpdateMemberships";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { IS_PREMIUM_USERNAME_ENABLED } from "@calcom/lib/constants";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { isUsernameReservedDueToMigration } from "@calcom/lib/server/username";
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Dispatch, SetStateAction } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import type { z } from "zod";
|
||||
|
||||
import { getPaymentAppData } from "@calcom/app-store/_utils/payments/getPaymentAppData";
|
||||
import { useAtomsContext } from "@calcom/atoms/hooks/useAtomsContext";
|
||||
import { useIsPlatform } from "@calcom/atoms/hooks/useIsPlatform";
|
||||
import {
|
||||
@@ -31,8 +32,6 @@ import type {
|
||||
SettingsToggleClassNames,
|
||||
} from "@calcom/features/eventtypes/lib/types";
|
||||
import { FormBuilder } from "@calcom/features/form-builder/FormBuilder";
|
||||
import type { fieldSchema } from "@calcom/features/form-builder/schema";
|
||||
import type { EditableSchema } from "@calcom/features/form-builder/schema";
|
||||
import { BookerLayoutSelector } from "@calcom/features/settings/BookerLayoutSelector";
|
||||
import {
|
||||
DEFAULT_LIGHT_BRAND_COLOR,
|
||||
@@ -42,11 +41,12 @@ import {
|
||||
} from "@calcom/lib/constants";
|
||||
import { generateHashedLink } from "@calcom/lib/generateHashedLink";
|
||||
import { checkWCAGContrastColor } from "@calcom/lib/getBrandColours";
|
||||
import { getPaymentAppData } from "@calcom/app-store/_utils/payments/getPaymentAppData";
|
||||
import { extractHostTimezone } from "@calcom/lib/hashedLinksUtils";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { SchedulingType } from "@calcom/prisma/enums";
|
||||
import type { EditableSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { fieldSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
|
||||
@@ -8,6 +8,7 @@ import type {
|
||||
import Widgets from "@calcom/app-store/routing-forms/components/react-awesome-query-builder/widgets";
|
||||
import PhoneInput from "@calcom/features/components/phone-input";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { fieldSchema, variantsConfigSchema, FieldType } from "@calcom/prisma/zod-utils";
|
||||
import { AddressInput } from "@calcom/ui/components/address";
|
||||
import { InfoBadge } from "@calcom/ui/components/badge";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
@@ -18,7 +19,6 @@ import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
|
||||
import { ComponentForField } from "./FormBuilderField";
|
||||
import { propsTypes } from "./propsTypes";
|
||||
import type { fieldSchema, FieldType, variantsConfigSchema } from "./schema";
|
||||
import { preprocessNameFieldDataWithVariant } from "./utils";
|
||||
|
||||
export const isValidValueProp: Record<Component["propsType"], (val: unknown) => boolean> = {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { md } from "@calcom/lib/markdownIt";
|
||||
import { markdownToSafeHTMLClient } from "@calcom/lib/markdownToSafeHTMLClient";
|
||||
import turndown from "@calcom/lib/turndownService";
|
||||
import { excludeOrRequireEmailSchema } from "@calcom/prisma/zod-utils";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Badge } from "@calcom/ui/components/badge";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
@@ -31,7 +32,7 @@ import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
import { fieldTypesConfigMap } from "./fieldTypes";
|
||||
import { fieldsThatSupportLabelAsSafeHtml } from "./fieldsThatSupportLabelAsSafeHtml";
|
||||
import { type fieldsSchema, excludeOrRequireEmailSchema } from "./schema";
|
||||
import type { fieldsSchema } from "./schema";
|
||||
import { getFieldIdentifier } from "./utils/getFieldIdentifier";
|
||||
import { getConfig as getVariantsConfig } from "./utils/variantsConfig";
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type z from "zod";
|
||||
|
||||
import type { FieldType } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { propsTypes } from "./propsTypes";
|
||||
import type { FieldType, fieldTypeConfigSchema } from "./schema";
|
||||
import type { fieldTypeConfigSchema } from "./schema";
|
||||
|
||||
const configMap: Record<FieldType, Omit<z.infer<typeof fieldTypeConfigSchema>, "propsType">> = {
|
||||
// This won't be stored in DB. It allows UI to be configured from the codebase for all existing booking fields stored in DB as well
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { FieldType } from "./schema";
|
||||
import type { FieldType } from "@calcom/prisma/zod-utils";
|
||||
|
||||
/**
|
||||
* Once a component supports `labelAsSafeHtml`, add it's field's type here
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { getValidRhfFieldName } from "@calcom/lib/getValidRhfFieldName";
|
||||
import { fieldSchema, fieldTypeEnum, variantsConfigSchema, type FieldType } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { fieldTypesConfigMap } from "./fieldTypes";
|
||||
import { preprocessNameFieldDataWithVariant } from "./utils";
|
||||
@@ -8,154 +8,6 @@ import { getConfig as getVariantsConfig } from "./utils/variantsConfig";
|
||||
|
||||
const nonEmptyString = () => z.string().refine((value: string) => value.trim().length > 0);
|
||||
|
||||
const fieldTypeEnum = z.enum([
|
||||
"name",
|
||||
"text",
|
||||
"textarea",
|
||||
"number",
|
||||
"email",
|
||||
"phone",
|
||||
"address",
|
||||
"multiemail",
|
||||
"select",
|
||||
"multiselect",
|
||||
"checkbox",
|
||||
"radio",
|
||||
"radioInput",
|
||||
"boolean",
|
||||
"url",
|
||||
]);
|
||||
|
||||
export type FieldType = z.infer<typeof fieldTypeEnum>;
|
||||
|
||||
export const EditableSchema = z.enum([
|
||||
"system", // Can't be deleted, can't be hidden, name can't be edited, can't be marked optional
|
||||
"system-but-optional", // Can't be deleted. Name can't be edited. But can be hidden or be marked optional
|
||||
"system-but-hidden", // Can't be deleted, name can't be edited, will be shown
|
||||
"user", // Fully editable
|
||||
"user-readonly", // All fields are readOnly.
|
||||
]);
|
||||
|
||||
export const excludeOrRequireEmailSchema = z.string().superRefine((val, ctx) => {
|
||||
const allDomains = val.split(",").map((dom) => dom.trim());
|
||||
|
||||
const regex = /^(?:@?[a-z0-9-]+(?:\.[a-z]{2,})?)?(?:@[a-z0-9-]+\.[a-z]{2,})?$/;
|
||||
|
||||
/*
|
||||
Valid patterns - [ example, example.anything, anyone@example.anything ]
|
||||
Invalid patterns - Patterns involving capital letter [ Example, Example.anything, Anyone@example.anything ]
|
||||
*/
|
||||
|
||||
const isValid = !allDomains.some((domain) => !regex.test(domain));
|
||||
|
||||
if (!isValid) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Enter valid domain or email",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const baseFieldSchema = z.object({
|
||||
name: z.string().transform(getValidRhfFieldName),
|
||||
type: fieldTypeEnum,
|
||||
// TODO: We should make at least one of `defaultPlaceholder` and `placeholder` required. Do the same for label.
|
||||
label: z.string().optional(),
|
||||
labelAsSafeHtml: z.string().optional(),
|
||||
|
||||
/**
|
||||
* It is the default label that will be used when a new field is created.
|
||||
* Note: It belongs in FieldsTypeConfig, so that changing defaultLabel in code can work for existing fields as well(for fields that are using the default label).
|
||||
* Supports translation
|
||||
*/
|
||||
defaultLabel: z.string().optional(),
|
||||
|
||||
placeholder: z.string().optional(),
|
||||
/**
|
||||
* It is the default placeholder that will be used when a new field is created.
|
||||
* Note: Same as defaultLabel, it belongs in FieldsTypeConfig
|
||||
* Supports translation
|
||||
*/
|
||||
defaultPlaceholder: z.string().optional(),
|
||||
required: z.boolean().default(false).optional(),
|
||||
/**
|
||||
* It is the list of options that is valid for a certain type of fields.
|
||||
*
|
||||
*/
|
||||
options: z
|
||||
.array(
|
||||
z.object({
|
||||
label: z.string(),
|
||||
value: z.string(),
|
||||
price: z.coerce.number().min(0).optional(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
/**
|
||||
* This is an alternate way to specify options when the options are stored elsewhere. Form Builder expects options to be present at `dataStore[getOptionsAt]`
|
||||
* This allows keeping a single source of truth in DB.
|
||||
*/
|
||||
getOptionsAt: z.string().optional(),
|
||||
|
||||
/**
|
||||
* For `radioInput` type of questions, it stores the input that is shown based on the user option selected.
|
||||
* e.g. If user is given a list of locations and he selects "Phone", then he will be shown a phone input
|
||||
*/
|
||||
optionsInputs: z
|
||||
.record(
|
||||
z.object({
|
||||
// Support all types as needed
|
||||
// Must be a subset of `fieldTypeEnum`.TODO: Enforce it in TypeScript
|
||||
type: z.enum(["address", "phone", "text"]),
|
||||
required: z.boolean().optional(),
|
||||
placeholder: z.string().optional(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
|
||||
/**
|
||||
* It is the minimum number of characters that can be entered in the field.
|
||||
* It is used for types with `supportsLengthCheck= true`.
|
||||
* @default 0
|
||||
* @requires supportsLengthCheck = true
|
||||
*/
|
||||
minLength: z.number().optional(),
|
||||
|
||||
/**
|
||||
* It is the maximum number of characters that can be entered in the field.
|
||||
* It is used for types with `supportsLengthCheck= true`.
|
||||
* @requires supportsLengthCheck = true
|
||||
*/
|
||||
maxLength: z.number().optional(),
|
||||
|
||||
// Emails that needs to be excluded
|
||||
excludeEmails: excludeOrRequireEmailSchema.optional(),
|
||||
// Emails that need to be required
|
||||
requireEmails: excludeOrRequireEmailSchema.optional(),
|
||||
// Price associated with the field which works like addons which users can add to the booking
|
||||
price: z.coerce.number().min(0).optional(),
|
||||
});
|
||||
|
||||
export const variantsConfigSchema = z.object({
|
||||
variants: z.record(
|
||||
z.object({
|
||||
/**
|
||||
* Variant Fields schema for a variant of the main field.
|
||||
* It doesn't support non text fields as of now
|
||||
**/
|
||||
fields: baseFieldSchema
|
||||
.omit({
|
||||
defaultLabel: true,
|
||||
defaultPlaceholder: true,
|
||||
options: true,
|
||||
getOptionsAt: true,
|
||||
optionsInputs: true,
|
||||
})
|
||||
.array(),
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export type ALL_VIEWS = "ALL_VIEWS";
|
||||
|
||||
// It is the config that is specific to a type and doesn't make sense in all fields individually. Any field with the type will automatically inherit this config.
|
||||
@@ -238,47 +90,6 @@ export const fieldTypeConfigSchema = z
|
||||
return true;
|
||||
});
|
||||
|
||||
/**
|
||||
* Main field Schema
|
||||
*/
|
||||
export const fieldSchema = baseFieldSchema.merge(
|
||||
z.object({
|
||||
variant: z.string().optional(),
|
||||
variantsConfig: variantsConfigSchema.optional(),
|
||||
|
||||
views: z
|
||||
.object({
|
||||
label: z.string(),
|
||||
id: z.string(),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
.array()
|
||||
.optional(),
|
||||
|
||||
/**
|
||||
* It is used to hide fields such as location when there are less than two options
|
||||
*/
|
||||
hideWhenJustOneOption: z.boolean().default(false).optional(),
|
||||
|
||||
hidden: z.boolean().optional(),
|
||||
editable: EditableSchema.default("user").optional(),
|
||||
sources: z
|
||||
.array(
|
||||
z.object({
|
||||
// Unique ID for the `type`. If type is workflow, it's the workflow ID
|
||||
id: z.string(),
|
||||
type: z.union([z.literal("user"), z.literal("system"), z.string()]),
|
||||
label: z.string(),
|
||||
editUrl: z.string().optional(),
|
||||
// Mark if a field is required by this source or not. This allows us to set `field.required` based on all the sources' fieldRequired value
|
||||
fieldRequired: z.boolean().optional(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
disableOnPrefill: z.boolean().default(false).optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const fieldsSchema = z.array(fieldSchema);
|
||||
|
||||
export const fieldTypesSchemaMap: Partial<
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type z from "zod";
|
||||
|
||||
import type { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { fieldSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { fieldTypesConfigMap } from "../fieldTypes";
|
||||
import type { fieldSchema } from "../schema";
|
||||
|
||||
type ConfigVariants = NonNullable<ReturnType<typeof getConfig>>["variants"];
|
||||
type Field = z.infer<typeof fieldSchema>;
|
||||
|
||||
@@ -2,8 +2,8 @@ import prismock from "../../../../tests/libs/__mocks__/prisma";
|
||||
|
||||
import { describe, test, expect, vi, beforeEach } from "vitest";
|
||||
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { checkIfEmailIsBlockedInWatchlistController } from "@calcom/features/watchlist/operations/check-if-email-in-watchlist.controller";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
import { UserRepository } from "../repository/user";
|
||||
@@ -20,7 +20,7 @@ vi.mock("@calcom/lib/server/i18n", () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("@calcom/features/auth/lib/hashPassword", () => ({
|
||||
vi.mock("@calcom/lib/auth/hashPassword", () => ({
|
||||
hashPassword: vi.fn().mockResolvedValue("hashed-password"),
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { checkIfEmailIsBlockedInWatchlistController } from "@calcom/features/watchlist/operations/check-if-email-in-watchlist.controller";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { CreationSource, UserPermissionRole, IdentityProvider } from "@calcom/prisma/enums";
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
"post-install": "yarn generate-schemas",
|
||||
"seed-app-store": "ts-node --transpile-only ../../scripts/seed-app-store.ts",
|
||||
"delete-app": "ts-node --transpile-only ./delete-app.ts",
|
||||
"seed-insights": "ts-node --transpile-only ./seed-insights.ts",
|
||||
"seed-pbac": "ts-node --transpile-only ./seed-pbac-organization.ts"
|
||||
"seed-insights": "ts-node --transpile-only ../../scripts/seed-insights.ts",
|
||||
"seed-pbac": "ts-node --transpile-only ../../scripts/seed-pbac-organization.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "9.2.0",
|
||||
"npm-run-all": "^4.1.5"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -46,4 +45,4 @@
|
||||
"prisma": {
|
||||
"seed": "ts-node --transpile-only ../../scripts/seed.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,9 @@ import type {
|
||||
ZodTypeAny,
|
||||
} from "zod";
|
||||
|
||||
import { isPasswordValid } from "@calcom/features/auth/lib/isPasswordValid";
|
||||
import type { FieldType as FormBuilderFieldType } from "@calcom/features/form-builder/schema";
|
||||
import { fieldsSchema as formBuilderFieldsSchema } from "@calcom/features/form-builder/schema";
|
||||
import { isPasswordValid } from "@calcom/lib/auth/isPasswordValid";
|
||||
import { emailSchema as emailRegexSchema, emailRegex } from "@calcom/lib/emailSchema";
|
||||
import { getValidRhfFieldName } from "@calcom/lib/getValidRhfFieldName";
|
||||
import type { IntervalLimit } from "@calcom/lib/intervalLimits/intervalLimitSchema";
|
||||
import { zodAttributesQueryValue } from "@calcom/lib/raqb/zod";
|
||||
import { slugify } from "@calcom/lib/slugify";
|
||||
@@ -135,10 +134,6 @@ export const eventTypeMetaDataSchemaWithoutApps = _eventTypeMetaDataSchemaWithou
|
||||
|
||||
export type EventTypeMetadata = z.infer<typeof EventTypeMetaDataSchema>;
|
||||
|
||||
export const eventTypeBookingFields = formBuilderFieldsSchema;
|
||||
export const BookingFieldTypeEnum = eventTypeBookingFields.element.shape.type.Enum;
|
||||
export type BookingFieldType = FormBuilderFieldType;
|
||||
|
||||
// Validation of user added bookingFields' responses happen using `getBookingResponsesSchema` which requires `eventType`.
|
||||
// So it is a dynamic validation and thus entire validation can't exist here
|
||||
// Note that this validation runs to validate prefill params as well, so it should consider that partial values can be there. e.g. `name` might be empty string
|
||||
@@ -768,3 +763,193 @@ export const serviceAccountKeySchema = z
|
||||
export type TServiceAccountKeySchema = z.infer<typeof serviceAccountKeySchema>;
|
||||
|
||||
export const rrSegmentQueryValueSchema = zodAttributesQueryValue.nullish();
|
||||
|
||||
// Routing Form Fields
|
||||
export const fieldTypeEnum = z.enum([
|
||||
"name",
|
||||
"text",
|
||||
"textarea",
|
||||
"number",
|
||||
"email",
|
||||
"phone",
|
||||
"address",
|
||||
"multiemail",
|
||||
"select",
|
||||
"multiselect",
|
||||
"checkbox",
|
||||
"radio",
|
||||
"radioInput",
|
||||
"boolean",
|
||||
"url",
|
||||
]);
|
||||
|
||||
export type FieldType = z.infer<typeof fieldTypeEnum>;
|
||||
|
||||
export const excludeOrRequireEmailSchema = z.string().superRefine((val, ctx) => {
|
||||
const allDomains = val.split(",").map((dom) => dom.trim());
|
||||
|
||||
const regex = /^(?:@?[a-z0-9-]+(?:\.[a-z]{2,})?)?(?:@[a-z0-9-]+\.[a-z]{2,})?$/;
|
||||
|
||||
/*
|
||||
Valid patterns - [ example, example.anything, anyone@example.anything ]
|
||||
Invalid patterns - Patterns involving capital letter [ Example, Example.anything, Anyone@example.anything ]
|
||||
*/
|
||||
|
||||
const isValid = !allDomains.some((domain) => !regex.test(domain));
|
||||
|
||||
if (!isValid) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Enter valid domain or email",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const EditableSchema = z.enum([
|
||||
"system", // Can't be deleted, can't be hidden, name can't be edited, can't be marked optional
|
||||
"system-but-optional", // Can't be deleted. Name can't be edited. But can be hidden or be marked optional
|
||||
"system-but-hidden", // Can't be deleted, name can't be edited, will be shown
|
||||
"user", // Fully editable
|
||||
"user-readonly", // All fields are readOnly.
|
||||
]);
|
||||
|
||||
export const baseFieldSchema = z.object({
|
||||
name: z.string().transform(getValidRhfFieldName),
|
||||
type: fieldTypeEnum,
|
||||
// TODO: We should make at least one of `defaultPlaceholder` and `placeholder` required. Do the same for label.
|
||||
label: z.string().optional(),
|
||||
labelAsSafeHtml: z.string().optional(),
|
||||
|
||||
/**
|
||||
* It is the default label that will be used when a new field is created.
|
||||
* Note: It belongs in FieldsTypeConfig, so that changing defaultLabel in code can work for existing fields as well(for fields that are using the default label).
|
||||
* Supports translation
|
||||
*/
|
||||
defaultLabel: z.string().optional(),
|
||||
|
||||
placeholder: z.string().optional(),
|
||||
/**
|
||||
* It is the default placeholder that will be used when a new field is created.
|
||||
* Note: Same as defaultLabel, it belongs in FieldsTypeConfig
|
||||
* Supports translation
|
||||
*/
|
||||
defaultPlaceholder: z.string().optional(),
|
||||
required: z.boolean().default(false).optional(),
|
||||
/**
|
||||
* It is the list of options that is valid for a certain type of fields.
|
||||
*
|
||||
*/
|
||||
options: z
|
||||
.array(
|
||||
z.object({
|
||||
label: z.string(),
|
||||
value: z.string(),
|
||||
price: z.coerce.number().min(0).optional(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
/**
|
||||
* This is an alternate way to specify options when the options are stored elsewhere. Form Builder expects options to be present at `dataStore[getOptionsAt]`
|
||||
* This allows keeping a single source of truth in DB.
|
||||
*/
|
||||
getOptionsAt: z.string().optional(),
|
||||
|
||||
/**
|
||||
* For `radioInput` type of questions, it stores the input that is shown based on the user option selected.
|
||||
* e.g. If user is given a list of locations and he selects "Phone", then he will be shown a phone input
|
||||
*/
|
||||
optionsInputs: z
|
||||
.record(
|
||||
z.object({
|
||||
// Support all types as needed
|
||||
// Must be a subset of `fieldTypeEnum`.TODO: Enforce it in TypeScript
|
||||
type: z.enum(["address", "phone", "text"]),
|
||||
required: z.boolean().optional(),
|
||||
placeholder: z.string().optional(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
|
||||
/**
|
||||
* It is the minimum number of characters that can be entered in the field.
|
||||
* It is used for types with `supportsLengthCheck= true`.
|
||||
* @default 0
|
||||
* @requires supportsLengthCheck = true
|
||||
*/
|
||||
minLength: z.number().optional(),
|
||||
|
||||
/**
|
||||
* It is the maximum number of characters that can be entered in the field.
|
||||
* It is used for types with `supportsLengthCheck= true`.
|
||||
* @requires supportsLengthCheck = true
|
||||
*/
|
||||
maxLength: z.number().optional(),
|
||||
|
||||
// Emails that needs to be excluded
|
||||
excludeEmails: excludeOrRequireEmailSchema.optional(),
|
||||
// Emails that need to be required
|
||||
requireEmails: excludeOrRequireEmailSchema.optional(),
|
||||
// Price associated with the field which works like addons which users can add to the booking
|
||||
price: z.coerce.number().min(0).optional(),
|
||||
});
|
||||
|
||||
export const variantsConfigSchema = z.object({
|
||||
variants: z.record(
|
||||
z.object({
|
||||
/**
|
||||
* Variant Fields schema for a variant of the main field.
|
||||
* It doesn't support non text fields as of now
|
||||
**/
|
||||
fields: baseFieldSchema
|
||||
.omit({
|
||||
defaultLabel: true,
|
||||
defaultPlaceholder: true,
|
||||
options: true,
|
||||
getOptionsAt: true,
|
||||
optionsInputs: true,
|
||||
})
|
||||
.array(),
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export const fieldSchema = baseFieldSchema.merge(
|
||||
z.object({
|
||||
variant: z.string().optional(),
|
||||
variantsConfig: variantsConfigSchema.optional(),
|
||||
|
||||
views: z
|
||||
.object({
|
||||
label: z.string(),
|
||||
id: z.string(),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
.array()
|
||||
.optional(),
|
||||
|
||||
/**
|
||||
* It is used to hide fields such as location when there are less than two options
|
||||
*/
|
||||
hideWhenJustOneOption: z.boolean().default(false).optional(),
|
||||
|
||||
hidden: z.boolean().optional(),
|
||||
editable: EditableSchema.default("user").optional(),
|
||||
sources: z
|
||||
.array(
|
||||
z.object({
|
||||
// Unique ID for the `type`. If type is workflow, it's the workflow ID
|
||||
id: z.string(),
|
||||
type: z.union([z.literal("user"), z.literal("system"), z.string()]),
|
||||
label: z.string(),
|
||||
editUrl: z.string().optional(),
|
||||
// Mark if a field is required by this source or not. This allows us to set `field.required` based on all the sources' fieldRequired value
|
||||
fieldRequired: z.boolean().optional(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
disableOnPrefill: z.boolean().default(false).optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export const eventTypeBookingFields = z.array(fieldSchema);
|
||||
export const BookingFieldTypeEnum = eventTypeBookingFields.element.shape.type.Enum;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { validPassword } from "@calcom/features/auth/lib/validPassword";
|
||||
import { verifyPassword } from "@calcom/features/auth/lib/verifyPassword";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { IdentityProvider } from "@calcom/prisma/enums";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createHash } from "crypto";
|
||||
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { verifyPassword } from "@calcom/features/auth/lib/verifyPassword";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
@@ -2,11 +2,11 @@ import { faker } from "@faker-js/faker";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { PrismaClient } from "@calcom/prisma/client";
|
||||
import { BookingStatus, AssignmentReasonEnum } from "@calcom/prisma/enums";
|
||||
|
||||
import type { Prisma } from "./client";
|
||||
import { PrismaClient } from "./client";
|
||||
import { seedAttributes, seedRoutingFormResponses, seedRoutingForms } from "./seed-utils";
|
||||
|
||||
function getRandomRatingFeedback() {
|
||||
@@ -1,11 +1,10 @@
|
||||
import { uuid } from "short-uuid";
|
||||
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { MembershipRole, RoleType } from "@calcom/prisma/enums";
|
||||
|
||||
import prisma from ".";
|
||||
|
||||
/**
|
||||
* Creates an organization with custom roles and PBAC (Permission-Based Access Control) enabled
|
||||
* This demonstrates how to set up fine-grained permissions for team members
|
||||
@@ -11,7 +11,7 @@ import zoomMeta from "@calcom/app-store/zoomvideo/_metadata";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
|
||||
import { createUserAndEventType } from "../packages/prisma/seed-utils";
|
||||
import { createUserAndEventType } from "./seed-utils";
|
||||
|
||||
async function _createManyDifferentUsersWithDifferentEventTypesAndBookings({
|
||||
tillUser,
|
||||
@@ -322,4 +322,4 @@ async function createAUserWithManyBookings() {
|
||||
// startFrom: 10000,
|
||||
// });
|
||||
|
||||
createAUserWithManyBookings();
|
||||
createAUserWithManyBookings();
|
||||
|
||||
@@ -4,13 +4,12 @@ import { uuid } from "short-uuid";
|
||||
import type z from "zod";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { Prisma, UserPermissionRole } from "@calcom/prisma/client";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
|
||||
import prisma from ".";
|
||||
import type { Prisma, UserPermissionRole } from "./client";
|
||||
import type { teamMetadataSchema } from "./zod-utils";
|
||||
import type { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
export async function createUserAndEventType({
|
||||
user,
|
||||
+3
-3
@@ -6,7 +6,7 @@ import googleMeetMeta from "@calcom/app-store/googlevideo/_metadata";
|
||||
import zoomMeta from "@calcom/app-store/zoomvideo/_metadata";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains";
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { hashPassword } from "@calcom/lib/auth/hashPassword";
|
||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { Membership, Team, User, UserPermissionRole } from "@calcom/prisma/client";
|
||||
@@ -14,10 +14,10 @@ import { Prisma } from "@calcom/prisma/client";
|
||||
import { BookingStatus, MembershipRole, RedirectType, SchedulingType } from "@calcom/prisma/enums";
|
||||
import type { Ensure } from "@calcom/types/utils";
|
||||
|
||||
import mainHugeEventTypesSeed from "../packages/prisma/seed-huge-event-types";
|
||||
import { createUserAndEventType } from "../packages/prisma/seed-utils";
|
||||
import type { teamMetadataSchema } from "../packages/prisma/zod-utils";
|
||||
import mainAppStore from "./seed-app-store";
|
||||
import mainHugeEventTypesSeed from "./seed-huge-event-types";
|
||||
import { createUserAndEventType } from "./seed-utils";
|
||||
|
||||
type PlatformUser = {
|
||||
email: string;
|
||||
|
||||
@@ -6032,9 +6032,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@faker-js/faker@npm:^7.3.0":
|
||||
version: 7.4.0
|
||||
resolution: "@faker-js/faker@npm:7.4.0"
|
||||
checksum: 1acebb84bfb142c08e6ba2942910d16bd92ea147fa585fa2fa9ce9983f7a8c7c016002beb7fc20ef6f7aef6c4ae9cb3fa680b275823402e34802b8489d2b980d
|
||||
version: 7.6.0
|
||||
resolution: "@faker-js/faker@npm:7.6.0"
|
||||
checksum: 942af6221774e8c98a0eb6bc75265e05fb81a941170377666c3439aab9495dd321d6beedc5406f07e6ad44262b3e43c20961f666d116ad150b78e7437dd1bb2b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -21669,6 +21669,7 @@ __metadata:
|
||||
"@changesets/cli": 2.29.4
|
||||
"@daily-co/daily-js": ^0.83.1
|
||||
"@evyweb/ioctopus": ^1.2.0
|
||||
"@faker-js/faker": 9.2.0
|
||||
"@jetstreamapp/soql-parser-js": ^6.1.0
|
||||
"@next/third-parties": ^14.2.5
|
||||
"@playwright/test": ^1.45.3
|
||||
|
||||
Reference in New Issue
Block a user