From 680d28496950c08231a34817ec20e38b4a6d5866 Mon Sep 17 00:00:00 2001 From: Jason Lin <98117700+JasonLin0991@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:43:45 -0500 Subject: [PATCH] MCR-4887: add new application settings table (#3093) * Add New tables and migration * Extend prisma to restrict new table methods * Pass prisma options to extendedPrismaClient --- .../migration.sql | 75 +++++++++++++++++++ services/app-api/prisma/schema.prisma | 26 +++++++ services/app-api/src/postgres/prismaClient.ts | 68 ++++++++++++++++- 3 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 services/app-api/prisma/migrations/20250122005954_add_application_and_email_settings_table/migration.sql diff --git a/services/app-api/prisma/migrations/20250122005954_add_application_and_email_settings_table/migration.sql b/services/app-api/prisma/migrations/20250122005954_add_application_and_email_settings_table/migration.sql new file mode 100644 index 0000000000..df4726dbfb --- /dev/null +++ b/services/app-api/prisma/migrations/20250122005954_add_application_and_email_settings_table/migration.sql @@ -0,0 +1,75 @@ +BEGIN; + +-- CreateTable +CREATE TABLE "ApplicationSettings" ( + "id" INTEGER NOT NULL DEFAULT 1, + "emailSettingsId" INTEGER DEFAULT 1, + + CONSTRAINT "ApplicationSettings_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "EmailSettings" ( + "id" INTEGER NOT NULL DEFAULT 1, + "emailSource" TEXT NOT NULL DEFAULT 'mc-review@cms.hhs.gov', + "devReviewTeamEmails" TEXT[] DEFAULT ARRAY['mc-review@cms.hhs.gov']::TEXT[], + "cmsReviewHelpEmailAddress" TEXT[] DEFAULT ARRAY['MCOGDMCOActions ']::TEXT[], + "cmsRateHelpEmailAddress" TEXT[] DEFAULT ARRAY['MMCratesetting ']::TEXT[], + "oactEmails" TEXT[] DEFAULT ARRAY['OACT Dev1 ', 'OACT Dev2 ']::TEXT[], + "dmcpReviewEmails" TEXT[] DEFAULT ARRAY['DMCP Review Dev1 ', 'DMCP Review Dev2 ']::TEXT[], + "dmcpSubmissionEmails" TEXT[] DEFAULT ARRAY['DMCP Submission Dev1 ', 'DMCP Submission Dev2 ']::TEXT[], + "dmcoEmails" TEXT[] DEFAULT ARRAY['DMCO Dev1 ', 'DMCO Dev2 ']::TEXT[], + "helpDeskEmail" TEXT[] DEFAULT ARRAY['MC_Review_HelpDesk@cms.hhs.gov']::TEXT[], + "applicationSettingsId" INTEGER DEFAULT 1, + + CONSTRAINT "EmailSettings_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "ApplicationSettings_emailSettingsId_key" ON "ApplicationSettings"("emailSettingsId"); + +-- CreateIndex +CREATE UNIQUE INDEX "ApplicationSettings_id_key" ON "ApplicationSettings"("id"); + +-- CreateIndex +CREATE UNIQUE INDEX "EmailSettings_applicationSettingsId_key" ON "EmailSettings"("applicationSettingsId"); + +-- CreateIndex +CREATE UNIQUE INDEX "EmailSettings_id_key" ON "EmailSettings"("id"); + +-- AddForeignKey +ALTER TABLE "EmailSettings" ADD CONSTRAINT "EmailSettings_applicationSettingsId_fkey" FOREIGN KEY ("applicationSettingsId") REFERENCES "ApplicationSettings"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- Insert Initial Records +INSERT INTO "ApplicationSettings" ("id", "emailSettingsId") +VALUES (1, 1) +ON CONFLICT ("id") DO NOTHING; + +INSERT INTO "EmailSettings" ( + "id", + "emailSource", + "devReviewTeamEmails", + "cmsReviewHelpEmailAddress", + "cmsRateHelpEmailAddress", + "oactEmails", + "dmcpReviewEmails", + "dmcpSubmissionEmails", + "dmcoEmails", + "helpDeskEmail", + "applicationSettingsId" +) VALUES ( + 1, + 'mc-review@cms.hhs.gov', + ARRAY['mc-review@cms.hhs.gov'], + ARRAY['MCOGDMCOActions '], + ARRAY['MMCratesetting '], + ARRAY['OACT Dev1 ', 'OACT Dev2 '], + ARRAY['DMCP Review Dev1 ', 'DMCP Review Dev2 '], + ARRAY['DMCP Submission Dev1 ', 'DMCP Submission Dev2 '], + ARRAY['DMCO Dev1 ', 'DMCO Dev2 '], + ARRAY['MC_Review_HelpDesk@cms.hhs.gov'], + 1 +) +ON CONFLICT ("id") DO NOTHING; + +COMMIT; \ No newline at end of file diff --git a/services/app-api/prisma/schema.prisma b/services/app-api/prisma/schema.prisma index a66f02dfdb..a0bbfa0d57 100644 --- a/services/app-api/prisma/schema.prisma +++ b/services/app-api/prisma/schema.prisma @@ -19,6 +19,32 @@ model ProtoMigrationsTable { migrationName String @id } +model ApplicationSettings { + id Int @id @default(1) + emailSettings EmailSettings? + emailSettingsId Int? @unique @default(1) + + @@unique([id]) +} + +model EmailSettings { + id Int @id @default(1) + emailSource String @default("mc-review@cms.hhs.gov") + devReviewTeamEmails String[] @default(["mc-review@cms.hhs.gov"]) + cmsReviewHelpEmailAddress String[] @default(["MCOGDMCOActions "]) + cmsRateHelpEmailAddress String[] @default(["MMCratesetting "]) + oactEmails String[] @default(["OACT Dev1 ","OACT Dev2 "]) + dmcpReviewEmails String[] @default(["DMCP Review Dev1 ", "DMCP Review Dev2 "]) + dmcpSubmissionEmails String[] @default(["DMCP Submission Dev1 ", "DMCP Submission Dev2 "]) + dmcoEmails String[] @default(["DMCO Dev1 ", "DMCO Dev2 "]) + helpDeskEmail String[] @default(["MC_Review_HelpDesk@cms.hhs.gov"]) + + applicationSettings ApplicationSettings? @relation(fields: [applicationSettingsId], references: [id]) + applicationSettingsId Int? @unique @default(1) + + @@unique([id]) +} + model HealthPlanRevisionTable { id String @id createdAt DateTime diff --git a/services/app-api/src/postgres/prismaClient.ts b/services/app-api/src/postgres/prismaClient.ts index 341ff8d8af..589ae4ecf0 100644 --- a/services/app-api/src/postgres/prismaClient.ts +++ b/services/app-api/src/postgres/prismaClient.ts @@ -1,14 +1,76 @@ -import { PrismaClient } from '@prisma/client' +import { type Prisma, PrismaClient } from '@prisma/client' -async function NewPrismaClient(connURL: string): Promise { +const errorMessages = { + delete: 'Deletion of records is not allowed', + create: 'Creation of new records is not allowed', +} + +/** + * Extends PrismaClient with custom behavior for specific models. + * + * Overrides delete and create operations on `applicationSettings` and `emailSettings` + * models to throw custom error messages. + * + * @param {Prisma.PrismaClientOptions} optionArgs - PrismaClient configuration options. + * @returns {PrismaClient} A new PrismaClient instance with extended behavior. + */ +function extendedPrismaClient(optionArgs: Prisma.PrismaClientOptions) { + return new PrismaClient(optionArgs).$extends({ + query: { + applicationSettings: { + delete: () => { + throw new Error( + `ApplicationSettings: ${errorMessages.delete}` + ) + }, + deleteMany: () => { + throw new Error( + `ApplicationSettings: ${errorMessages.delete}` + ) + }, + create: () => { + throw new Error( + `ApplicationSettings: ${errorMessages.create}` + ) + }, + createMany: () => { + throw new Error( + `ApplicationSettings: ${errorMessages.create}` + ) + }, + }, + emailSettings: { + delete: () => { + throw new Error(`EmailSettings: ${errorMessages.delete}`) + }, + deleteMany: () => { + throw new Error(`EmailSettings: ${errorMessages.delete}`) + }, + create: () => { + throw new Error(`EmailSettings: ${errorMessages.create}`) + }, + createMany: () => { + throw new Error(`EmailSettings: ${errorMessages.create}`) + }, + }, + }, + }) +} + +type ExtendedPrismaClient = ReturnType + +async function NewPrismaClient( + connURL: string +): Promise { try { - const prismaClient = new PrismaClient({ + const prismaClient = extendedPrismaClient({ datasources: { db: { url: connURL, }, }, }) + return prismaClient } catch (e: unknown) { if (e instanceof Error) {