From 606e538beefd28533a9f1739c173313df53fc081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 26 Jan 2023 10:52:10 -0700 Subject: [PATCH] Adds deployment settings to DB (#6706) * WIP * Adds DeploymentTheme * Add missing migrations * Adds client extensions for deployment * Cleanup --- packages/prisma/extensions/index.ts | 62 +++++++++++++++++++ packages/prisma/index.ts | 17 +++-- .../migration.sql | 10 +++ packages/prisma/schema.prisma | 12 +++- packages/prisma/zod-utils.ts | 18 ++++++ 5 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 packages/prisma/extensions/index.ts create mode 100644 packages/prisma/migrations/20230125182832_add_deployment/migration.sql diff --git a/packages/prisma/extensions/index.ts b/packages/prisma/extensions/index.ts new file mode 100644 index 0000000000000..7325ac534f238 --- /dev/null +++ b/packages/prisma/extensions/index.ts @@ -0,0 +1,62 @@ +import { Prisma, PrismaClient } from "@prisma/client"; + +export function addPrismaExtensions(prisma: PrismaClient) { + const xprisma = prisma.$extends({ + model: { + /** + * We extend deployment model since it's supposed to be a single record table. + * New settings should be added as Columns as needed. + * */ + deployment: { + /** + * This is the preferred method for accessing deployment settings, + * it can be called without any arguments: + * @example + * ``` + * const deployment = await prisma.deployment.get(); + * ``` + */ + async get(args?: Omit) { + return prisma.deployment.findUnique({ where: { id: 1 }, ...args }); + }, + async findFirst(args: Omit) { + return prisma.deployment.findFirst({ where: { id: 1 }, ...args }); + }, + async findFirstOrThrow(args: Omit) { + return prisma.deployment.findFirstOrThrow({ where: { id: 1 }, ...args }); + }, + async findUnique(args: Omit) { + return prisma.deployment.findUnique({ where: { id: 1 }, ...args }); + }, + async findUniqueOrThrow(args: Omit) { + return prisma.deployment.findUniqueOrThrow({ where: { id: 1 }, ...args }); + }, + async upsert(args: Omit) { + return prisma.deployment.upsert({ where: { id: 1 }, ...args }); + }, + async update(args: Omit) { + return prisma.deployment.update({ where: { id: 1 }, ...args }); + }, + async findMany() { + throw new Error("Use prisma.deployment.get method"); + }, + async updateMany() { + throw new Error("Use prisma.deployment.update method"); + }, + async create() { + throw new Error("Use prisma.deployment.upsert method"); + }, + async createMany() { + throw new Error("Use prisma.deployment.upsert method"); + }, + async delete() { + throw new Error("Deployment shouldn't be deleted"); + }, + async deleteMany() { + throw new Error("Deployment shouldn't be deleted"); + }, + }, + }, + }); + return xprisma; +} diff --git a/packages/prisma/index.ts b/packages/prisma/index.ts index 6782dbf9c3884..3e6434a432f7d 100644 --- a/packages/prisma/index.ts +++ b/packages/prisma/index.ts @@ -1,27 +1,34 @@ import { Prisma, PrismaClient } from "@prisma/client"; +import { addPrismaExtensions } from "./extensions"; import { bookingReferenceMiddleware, eventTypeDescriptionParseAndSanitizeMiddleware } from "./middleware"; declare global { // eslint-disable-next-line no-var - var prisma: PrismaClient | undefined; + var prisma: ReturnType | undefined; } const prismaOptions: Prisma.PrismaClientOptions = {}; if (!!process.env.NEXT_PUBLIC_DEBUG) prismaOptions.log = ["query", "error", "warn"]; -export const prisma = globalThis.prisma || new PrismaClient(prismaOptions); +function createPrismaClient(options: Prisma.PrismaClientOptions) { + const newPrisma = new PrismaClient(options); + bookingReferenceMiddleware(newPrisma); + eventTypeDescriptionParseAndSanitizeMiddleware(newPrisma); + const xprisma = addPrismaExtensions(newPrisma); + return xprisma; +} + +export const prisma = globalThis.prisma || createPrismaClient(prismaOptions); export const customPrisma = (options: Prisma.PrismaClientOptions) => - new PrismaClient({ ...prismaOptions, ...options }); + createPrismaClient({ ...prismaOptions, ...options }); if (process.env.NODE_ENV !== "production") { globalThis.prisma = prisma; } // If any changed on middleware server restart is required -bookingReferenceMiddleware(prisma); -eventTypeDescriptionParseAndSanitizeMiddleware(prisma); export default prisma; diff --git a/packages/prisma/migrations/20230125182832_add_deployment/migration.sql b/packages/prisma/migrations/20230125182832_add_deployment/migration.sql new file mode 100644 index 0000000000000..9527d41f2f936 --- /dev/null +++ b/packages/prisma/migrations/20230125182832_add_deployment/migration.sql @@ -0,0 +1,10 @@ +-- CreateTable +CREATE TABLE "Deployment" ( + "id" INTEGER NOT NULL DEFAULT 1, + "logo" TEXT, + "theme" JSONB, + "licenseKey" TEXT, + "agreedLicenseAt" TIMESTAMP(3), + + CONSTRAINT "Deployment_pkey" PRIMARY KEY ("id") +); diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index f4b4534362c1a..d32e1dffa329b 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -8,7 +8,7 @@ datasource db { generator client { provider = "prisma-client-js" - previewFeatures = ["interactiveTransactions"] + previewFeatures = ["clientExtensions"] } generator zod { @@ -615,6 +615,16 @@ model WorkflowsOnEventTypes { eventTypeId Int } +model Deployment { + /// This is a single row table, so we use a fixed id + id Int @id @default(1) + logo String? + /// @zod.custom(imports.DeploymentTheme) + theme Json? + licenseKey String? + agreedLicenseAt DateTime? +} + enum TimeUnit { DAY @map("day") HOUR @map("hour") diff --git a/packages/prisma/zod-utils.ts b/packages/prisma/zod-utils.ts index 2615ded55df90..7f50f422b1b05 100644 --- a/packages/prisma/zod-utils.ts +++ b/packages/prisma/zod-utils.ts @@ -293,6 +293,24 @@ export const RoutingFormSettings = z }) .nullable(); +export const DeploymentTheme = z + .object({ + brand: z.string().default("#292929"), + textBrand: z.string().default("#ffffff"), + darkBrand: z.string().default("#fafafa"), + textDarkBrand: z.string().default("#292929"), + bookingHighlight: z.string().default("#10B981"), + bookingLightest: z.string().default("#E1E1E1"), + bookingLighter: z.string().default("#ACACAC"), + bookingLight: z.string().default("#888888"), + bookingMedian: z.string().default("#494949"), + bookingDark: z.string().default("#313131"), + bookingDarker: z.string().default("#292929"), + fontName: z.string().default("Cal Sans"), + fontSrc: z.string().default("https://cal.com/cal.ttf"), + }) + .optional(); + export type ZodDenullish = T extends ZodNullable | ZodOptional ? ZodDenullish : T;