From a038fa52cd56c5d6ca5d7942f9b54371808ce627 Mon Sep 17 00:00:00 2001 From: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed, 31 Jul 2024 13:12:31 -0400 Subject: [PATCH 1/4] fix(text-changes-appk): Fix the language in app-k forms to match legacy application (#689) * fix text on additional information * hide the progress loss message for app-k's * Fix validation message text * changed language for consistency with other components * add progress loss reminder on new line * allow for class to move spacing of text --- .../ui/src/components/Form/content/ContentWrappers.tsx | 9 +++++++-- src/services/ui/src/components/Form/old-content.tsx | 9 +++++++-- src/services/ui/src/features/submission/app-k/index.tsx | 5 +---- src/services/ui/src/utils/zod.ts | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/services/ui/src/components/Form/content/ContentWrappers.tsx b/src/services/ui/src/components/Form/content/ContentWrappers.tsx index ee8ed85808..f252a8c370 100644 --- a/src/services/ui/src/components/Form/content/ContentWrappers.tsx +++ b/src/services/ui/src/components/Form/content/ContentWrappers.tsx @@ -8,6 +8,7 @@ import { } from "@/components"; import { useFormContext } from "react-hook-form"; import { TEPackageSection } from "@/features/package-actions/lib/modules/temporary-extension/legacy-components"; +import clsx from "clsx"; export const FormSectionCard = ({ children, @@ -42,8 +43,12 @@ export const RequiredFieldDescription = () => ( ); -export const ProgressLossReminder = () => ( -

+export const ProgressLossReminder = ({ + className = "", +}: { + className?: string; +}) => ( +

If you leave this page, you will lose your progress on this form.

); diff --git a/src/services/ui/src/components/Form/old-content.tsx b/src/services/ui/src/components/Form/old-content.tsx index e413aceff2..e58997c3d7 100644 --- a/src/services/ui/src/components/Form/old-content.tsx +++ b/src/services/ui/src/components/Form/old-content.tsx @@ -91,7 +91,12 @@ export const AttachmentsSizeTypesDesc = ({ ); -export const PreSubmissionMessage = () => ( +type PreSubmissionMessageProps = { + hasProgressLossReminder?: boolean; +}; +export const PreSubmissionMessage = ({ + hasProgressLossReminder = true, +}: PreSubmissionMessageProps) => (

@@ -99,7 +104,7 @@ export const PreSubmissionMessage = () => ( CMS will use this content to review your package, and you will not be able to edit this form. If CMS needs any additional information, they will follow up by email. -

+ {hasProgressLossReminder && }
); diff --git a/src/services/ui/src/features/submission/app-k/index.tsx b/src/services/ui/src/features/submission/app-k/index.tsx index 99a528a9e1..8e6ee4f6d0 100644 --- a/src/services/ui/src/features/submission/app-k/index.tsx +++ b/src/services/ui/src/features/submission/app-k/index.tsx @@ -225,10 +225,7 @@ export const AppKSubmissionForm = () => { render={SlotAdditionalInfo({ withoutHeading: true, label: ( -

- Add anything else you would like to share with CMS, limited - to 4000 characters -

+

Add anything else you would like to share with CMS.

), })} /> diff --git a/src/services/ui/src/utils/zod.ts b/src/services/ui/src/utils/zod.ts index e45a0ed835..b3eee5d8c3 100644 --- a/src/services/ui/src/utils/zod.ts +++ b/src/services/ui/src/utils/zod.ts @@ -172,7 +172,7 @@ export const zAppkWaiverNumberSchema = z .min(1, { message: "Required" }) .regex( /^\d{4,5}\.R\d{2}\.(0[1-9]|[1-9][0-9])$/, - "The 1915(c) Waiver Amendment Number must be in the format of ####.R##.## or #####.R##.##. For amendments, the last two digits start with '01' and ascends.", + "The Waiver Amendment Number must be in the format of ####.R##.## or #####.R##.##. For amendments, the last two digits start with '01' and ascends.", ); export const zExtensionWaiverNumberSchema = z From fef7dd500e1d8b13a7f83cf75d1f246fd8684c50 Mon Sep 17 00:00:00 2001 From: 13bfrancis <40218571+13bfrancis@users.noreply.github.com> Date: Wed, 31 Jul 2024 13:13:20 -0400 Subject: [PATCH 2/4] feat(withdraw-appk-package): Withdraw App-K and all Children (#674) * add unit testing for api * restructure code * break out some more * Rework unit test commands and the deploy workflow * gha support * alwayss run * do things for testing to get setup for other devs * temp change to flag for thing * complete intake stuff * lets try this * fix typescript error * write a placeholder test to see if it runs in ci * lay foundation for other actions and setup issuerai * fix error with the server regarding transactions * change spwStatus type with brian * break it all * fixes for respond to rai * Add transforms for issue rai and respond to rai, to update makoChangedDate when those actions cocur * add enable and disable rai withdraw in new format * toggle response stuff * withdraw rai * removeappkchild * withdrawpackage * updateid * Update timestamps going to seatool to today * fix up test running * report * coverage * time fixes. appkwithdrawchild has issue atm * fix withdraw package * fix withdraw appk child * add missing trx bit * correct typo causing lpa to not update for rai response * push broken code * add framework for testing * first * stuff * mock the data * add test * add more tests * add a new line (OCD) * upload to cc * revertme: dev etst * fix conditional * readme update * specify type * dont need this guard * asdf * thi sis broken, judge me * working * cover another case * tests for withdrawing rai * exclude docs directory * bump * ignore test files themselves * exclude the build dir, which is presented at execution time * cleanup some * update language * revertme * rename workflow * feat: convert seatool services to function modules * feat: convert mako services to function modules * chore: delete setup-write-services * feat: update `issue-rai` and tests to functions * feat: update `toggle-rai-response` and tests to functions * feat: update `withdraw-rai` and tests to functions * feat: update `respond-to-rai` to functions * feat: convert package action write services to function modules * fix: change `transaction` to lazy initialization * fix: remove `packageActionWriteService` from functions * adding appendix k to page titles for withdrawing and responding rais * footer texT * Footer update * footer update * Exclude the api/webforms dir based on discussions * change type to unknown and write tests for the withdraw package action * remove the need for ?. in test file * add period * make changes from test findings * remove un-used code * fix issues with scrolling and navigation * Fix bad copy-paste bug. Sorry Padma * Fix routing for child appk --------- Co-authored-by: Mike Dial Co-authored-by: Asharon Baltazar --- src/services/api/global.d.ts | 6 - src/services/api/handlers/action.ts | 17 +- .../complete-intake/complete-intake.ts | 9 +- .../package-actions/issue-rai/issue-rai.ts | 9 +- .../remove-appk-child/remove-appk-child.ts | 3 +- .../respond-to-rai/respond-to-rai.test.ts | 60 +- .../respond-to-rai/respond-to-rai.ts | 5 +- .../services/mako-write-service.ts | 260 ++++---- .../services/package-action-write-service.ts | 594 +++++++++--------- .../services/seatool-write-service.ts | 273 ++++---- .../package-actions/setup-write-service.ts | 13 - .../toggle-rai-response-withdraw.test.ts | 53 +- .../toggle-rai-response-withdraw.ts | 14 +- .../package-actions/update-id/update-id.ts | 3 +- .../withdraw-package/withdraw-package.test.ts | 37 ++ .../withdraw-package/withdraw-package.ts | 9 +- .../withdraw-rai/withdraw-rai.test.ts | 62 +- .../withdraw-rai/withdraw-rai.ts | 6 +- .../package-actions/lib/fieldsSwitch.ts | 3 +- .../lib/modules/withdraw-package/index.tsx | 2 +- .../waiver/withdraw-waiver.tsx | 34 + .../features/package/package-details/appk.tsx | 16 +- 22 files changed, 752 insertions(+), 736 deletions(-) delete mode 100644 src/services/api/global.d.ts delete mode 100644 src/services/api/handlers/package-actions/setup-write-service.ts create mode 100644 src/services/api/handlers/package-actions/withdraw-package/withdraw-package.test.ts diff --git a/src/services/api/global.d.ts b/src/services/api/global.d.ts deleted file mode 100644 index eb83e8dd35..0000000000 --- a/src/services/api/global.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { type PackageActionWriteService } from "./handlers/package-actions/services/package-action-write-service"; - -declare global { - // eslint-disable-next-line no-var - var packageActionWriteService: PackageActionWriteService; -} diff --git a/src/services/api/handlers/action.ts b/src/services/api/handlers/action.ts index 6fb3c6415b..67a7cb293e 100644 --- a/src/services/api/handlers/action.ts +++ b/src/services/api/handlers/action.ts @@ -18,21 +18,8 @@ import { completeIntake, removeAppkChild, } from "./package-actions"; -import { setupWriteService } from "./package-actions/setup-write-service"; - -const checkIfActionType = ( - potentialActionType: unknown, -): potentialActionType is Action => { - if (potentialActionType) { - return true; - } - return false; -}; export const handler = async (event: APIGatewayEvent) => { - if (typeof globalThis.packageActionWriteService === "undefined") { - global.packageActionWriteService = await setupWriteService(); - } if (!event.pathParameters || !event.pathParameters.actionType) { return response({ statusCode: 400, @@ -94,10 +81,10 @@ export const handler = async (event: APIGatewayEvent) => { await respondToRai(body, result._source); break; case Action.ENABLE_RAI_WITHDRAW: - await toggleRaiResponseWithdraw(body, true); + await toggleRaiResponseWithdraw({ toggle: true, ...body }); break; case Action.DISABLE_RAI_WITHDRAW: - await toggleRaiResponseWithdraw(body, false); + await toggleRaiResponseWithdraw(body); break; case Action.WITHDRAW_RAI: await withdrawRai(body, result._source); diff --git a/src/services/api/handlers/package-actions/complete-intake/complete-intake.ts b/src/services/api/handlers/package-actions/complete-intake/complete-intake.ts index 893e685b7e..58821287b9 100644 --- a/src/services/api/handlers/package-actions/complete-intake/complete-intake.ts +++ b/src/services/api/handlers/package-actions/complete-intake/complete-intake.ts @@ -1,12 +1,9 @@ import { completeIntakeSchema, Action } from "shared-types"; import { response } from "../../../libs/handler"; import { TOPIC_NAME } from "../consts"; -import { type PackageActionWriteService } from "../services/package-action-write-service"; +import { completeIntakeAction } from "../services/package-action-write-service"; -export async function completeIntake( - body: any, - packageActionWriteService: PackageActionWriteService = globalThis.packageActionWriteService, -) { +export async function completeIntake(body: any) { console.log("CMS performing intake for a record."); const result = completeIntakeSchema.safeParse(body); @@ -27,7 +24,7 @@ export async function completeIntake( const now = new Date().getTime(); - await packageActionWriteService.completeIntake({ + await completeIntakeAction({ timestamp: now, action: Action.COMPLETE_INTAKE, cpoc: result.data.cpoc, diff --git a/src/services/api/handlers/package-actions/issue-rai/issue-rai.ts b/src/services/api/handlers/package-actions/issue-rai/issue-rai.ts index c8918cfce6..86775bbf3f 100644 --- a/src/services/api/handlers/package-actions/issue-rai/issue-rai.ts +++ b/src/services/api/handlers/package-actions/issue-rai/issue-rai.ts @@ -2,12 +2,9 @@ import { RaiIssue, raiIssueSchema, Action, SEATOOL_STATUS } from "shared-types"; import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler"; import { TOPIC_NAME } from "../consts"; -import { type PackageActionWriteService } from "../services/package-action-write-service"; +import { issueRaiAction } from "../services/package-action-write-service"; -export async function issueRai( - body: RaiIssue, - packageActionWriteService: PackageActionWriteService = globalThis.packageActionWriteService, -) { +export async function issueRai(body: RaiIssue) { console.log("CMS issuing a new RAI"); const now = new Date().getTime(); const today = seaToolFriendlyTimestamp(); @@ -27,7 +24,7 @@ export async function issueRai( }); } - await packageActionWriteService.issueRai({ + await issueRaiAction({ ...result.data, action: Action.ISSUE_RAI, id: result.data.id, diff --git a/src/services/api/handlers/package-actions/remove-appk-child/remove-appk-child.ts b/src/services/api/handlers/package-actions/remove-appk-child/remove-appk-child.ts index 6573d41b43..c9b29172eb 100644 --- a/src/services/api/handlers/package-actions/remove-appk-child/remove-appk-child.ts +++ b/src/services/api/handlers/package-actions/remove-appk-child/remove-appk-child.ts @@ -7,6 +7,7 @@ import { import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler"; import { TOPIC_NAME } from "../consts"; +import { removeAppkChildAction } from "../services/package-action-write-service"; export async function removeAppkChild(doc: opensearch.main.Document) { const result = removeAppkChildSchema.safeParse(doc); @@ -22,7 +23,7 @@ export async function removeAppkChild(doc: opensearch.main.Document) { const now = new Date().getTime(); const today = seaToolFriendlyTimestamp(); - await packageActionWriteService.removeAppkChild({ + await removeAppkChildAction({ ...result.data, action: Action.REMOVE_APPK_CHILD, id: result.data.id, diff --git a/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.test.ts b/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.test.ts index 3fc6c6da2f..d7d0da72a9 100644 --- a/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.test.ts +++ b/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.test.ts @@ -1,10 +1,14 @@ import { respondToRai } from "./respond-to-rai"; import { vi, describe, it, expect, beforeEach } from "vitest"; -import { MockPackageActionWriteService } from "../services/package-action-write-service"; -import { Action, raiResponseSchema } from "shared-types"; +import { raiResponseSchema } from "shared-types"; import { generateMock } from "@anatine/zod-mock"; -import { ExtendedItemResult } from "../../../libs/package"; -const mockPackageWrite = new MockPackageActionWriteService(); +import * as packageActionWriteService from "../services/package-action-write-service"; + +vi.mock("../services/package-action-write-service", () => { + return { + respondToRaiAction: vi.fn(), + }; +}); describe("respondToRai", async () => { beforeEach(() => { @@ -19,52 +23,42 @@ describe("respondToRai", async () => { raiReceivedDate: "999", raiWithdrawnDate: "999", }, - mockPackageWrite, ); expect(response.statusCode).toBe(400); }); it("should return a 400 when no requested date is sent", async () => { const mockData = generateMock(raiResponseSchema); - const response = await respondToRai( - mockData, - { - raiRequestedDate: null, - raiReceivedDate: null, - raiWithdrawnDate: null, - }, - mockPackageWrite, - ); + const response = await respondToRai(mockData, { + raiRequestedDate: null, + raiReceivedDate: null, + raiWithdrawnDate: null, + }); expect(response.statusCode).toBe(400); }); it("should return a 400 when a bad requestDate is sent", async () => { const mockData = generateMock(raiResponseSchema); - const response = await respondToRai( - mockData, - { - raiRequestedDate: "123456789", // should be an isoString - raiReceivedDate: null, - raiWithdrawnDate: null, - }, - mockPackageWrite, - ); + const response = await respondToRai(mockData, { + raiRequestedDate: "123456789", // should be an isoString + raiReceivedDate: null, + raiWithdrawnDate: null, + }); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe("Event validation error"); }); it("should return a 200 when a good payload is sent", async () => { - const packageWriteSpy = vi.spyOn(mockPackageWrite, "respondToRai"); - const mockData = generateMock(raiResponseSchema); - const response = await respondToRai( - mockData, - { - raiRequestedDate: new Date().toISOString(), - raiReceivedDate: null, - raiWithdrawnDate: null, - }, - mockPackageWrite, + const packageWriteSpy = vi.spyOn( + packageActionWriteService, + "respondToRaiAction", ); + const mockData = generateMock(raiResponseSchema); + const response = await respondToRai(mockData, { + raiRequestedDate: new Date().toISOString(), + raiReceivedDate: null, + raiWithdrawnDate: null, + }); expect(packageWriteSpy).toHaveBeenCalledOnce(); expect(response.statusCode).toBe(200); }); diff --git a/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.ts b/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.ts index 0898f0020b..4665a62da7 100644 --- a/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.ts +++ b/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.ts @@ -3,7 +3,7 @@ import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler"; import { TOPIC_NAME } from "../consts"; import { ExtendedItemResult } from "../../../libs/package"; -import { PackageWriteClass } from "../services/package-action-write-service"; +import { respondToRaiAction } from "../services/package-action-write-service"; export async function respondToRai( body: any, @@ -11,7 +11,6 @@ export async function respondToRai( ExtendedItemResult["_source"], "raiReceivedDate" | "raiRequestedDate" | "raiWithdrawnDate" >, - packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, ) { console.log("State responding to RAI"); if (!document.raiRequestedDate) { @@ -45,7 +44,7 @@ export async function respondToRai( }); } try { - await packageActionWriteService.respondToRai({ + await respondToRaiAction({ ...result.data, action: Action.RESPOND_TO_RAI, id: result.data.id, diff --git a/src/services/api/handlers/package-actions/services/mako-write-service.ts b/src/services/api/handlers/package-actions/services/mako-write-service.ts index 2080b43c9c..6922e56ae7 100644 --- a/src/services/api/handlers/package-actions/services/mako-write-service.ts +++ b/src/services/api/handlers/package-actions/services/mako-write-service.ts @@ -1,5 +1,6 @@ import { type Action } from "shared-types"; import { getNextBusinessDayTimestamp } from "shared-utils"; +import { produceMessage } from "../../../libs/kafka"; export type MessageProducer = ( topic: string, @@ -51,147 +52,146 @@ export type WithdrawPackageDto = { action: Action; } & Record; -export class MakoWriteService { - #messageProducer: MessageProducer; - - constructor(messageProducer: MessageProducer) { - this.#messageProducer = messageProducer; - } +export type UpdateIdDto = { + topicName: string; + id: string; + newId: string; + action: Action; +} & Record; - async completeIntake({ - action, - id, - timestamp, +export const completeIntakeMako = async ({ + action, + id, + timestamp, + topicName, + ...data +}: CompleteIntakeDto) => + produceMessage( topicName, - ...data - }: CompleteIntakeDto) { - await this.#messageProducer( - topicName, - id, - JSON.stringify({ - actionType: action, - timestamp, - ...data, - }), - ); - } - - async issueRai({ action, id, topicName, ...data }: IssueRaiDto) { - await this.#messageProducer( - topicName, - id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } - - async respondToRai({ - action, id, - responseDate, + JSON.stringify({ + actionType: action, + timestamp, + ...data, + }), + ); + +export const issueRaiMako = async ({ + action, + id, + topicName, + ...data +}: IssueRaiDto) => + produceMessage( topicName, - ...data - }: RespondToRaiDto) { - await this.#messageProducer( - topicName, - id, - JSON.stringify({ - ...data, - id, - responseDate, - actionType: action, - notificationMetadata: { - submissionDate: getNextBusinessDayTimestamp(), - }, - }), - ); - } - - async withdrawRai({ action, id, topicName, ...data }: WithdrawRaiDto) { - await this.#messageProducer( - topicName, - id, - JSON.stringify({ - ...data, - id, - actionType: action, - notificationMetadata: { - submissionDate: getNextBusinessDayTimestamp(), - }, - }), - ); - } - - async toggleRaiResponseWithdraw({ - action, id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + +export const respondToRaiMako = async ({ + action, + id, + responseDate, + topicName, + ...data +}: RespondToRaiDto) => + produceMessage( topicName, - ...data - }: ToggleRaiResponseDto) { - await this.#messageProducer( - topicName, + id, + JSON.stringify({ + ...data, id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } - - async removeAppkChild({ - action, + responseDate, + actionType: action, + notificationMetadata: { + submissionDate: getNextBusinessDayTimestamp(), + }, + }), + ); + +export const withdrawRaiMako = async ({ + action, + id, + topicName, + ...data +}: WithdrawRaiDto) => + produceMessage( + topicName, id, + JSON.stringify({ + ...data, + id, + actionType: action, + notificationMetadata: { + submissionDate: getNextBusinessDayTimestamp(), + }, + }), + ); + +export const toggleRaiResponseWithdrawMako = async ({ + action, + id, + topicName, + ...data +}: ToggleRaiResponseDto) => + produceMessage( topicName, - ...data - }: RemoveAppkChildDto) { - await this.#messageProducer( - topicName, + id, + JSON.stringify({ + ...data, id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } - - async withdrawPackage({ - action, + actionType: action, + }), + ); + +export const removeAppkChildMako = async ({ + action, + id, + topicName, + ...data +}: RemoveAppkChildDto) => + produceMessage( + topicName, id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + +export const withdrawPackageMako = async ({ + action, + id, + topicName, + ...data +}: WithdrawPackageDto) => + produceMessage( topicName, - ...data - }: WithdrawPackageDto) { - await this.#messageProducer( - topicName, + id, + JSON.stringify({ + ...data, id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } - - async updateId({ action, id, topicName, ...data }: UpdateIdDto) { - await this.#messageProducer( - topicName, + actionType: action, + }), + ); + +export const updateIdMako = async ({ + action, + id, + topicName, + ...data +}: UpdateIdDto) => + produceMessage( + topicName, + id, + JSON.stringify({ + ...data, id, - JSON.stringify({ - ...data, - id, - actionType: action, - }), - ); - } -} - -export type UpdateIdDto = { - topicName: string; - id: string; - newId: string; - action: Action; -} & Record; + actionType: action, + }), + ); diff --git a/src/services/api/handlers/package-actions/services/package-action-write-service.ts b/src/services/api/handlers/package-actions/services/package-action-write-service.ts index 2c95cc41ca..fe5ceb5694 100644 --- a/src/services/api/handlers/package-actions/services/package-action-write-service.ts +++ b/src/services/api/handlers/package-actions/services/package-action-write-service.ts @@ -1,6 +1,5 @@ -import { Action } from "shared-types"; +import { getIdsToUpdate } from "../get-id-to-update"; import { - MakoWriteService, IssueRaiDto as MakoIssueRaiDto, CompleteIntakeDto as MakoCompleteIntake, RespondToRaiDto as MakoRespondToRai, @@ -9,9 +8,15 @@ import { RemoveAppkChildDto as MakoRemoveAppkChild, WithdrawPackageDto as MakoWithdrawPackage, UpdateIdDto as MakoUpdateId, + completeIntakeMako, + issueRaiMako, + respondToRaiMako, + withdrawPackageMako, + toggleRaiResponseWithdrawMako, + removeAppkChildMako, + updateIdMako, } from "./mako-write-service"; import { - SeatoolWriteService, IssueRaiDto as SeaIssueRaiDto, CompleteIntakeDto as SeaCompleteIntake, RespondToRaiDto as SeaRespondToRai, @@ -19,10 +24,16 @@ import { RemoveAppkChildDto as SeaRemoveAppkChild, WithdrawPackageDto as SeaWithdrawPackage, UpdateIdDto as SeaUpdateId, + getTrx, + completeIntakeSeatool, + issueRaiSeatool, + respondToRaiSeatool, + withdrawRaiSeatool, + removeAppkChildSeatool, + withdrawPackageSeatool, + updateIdSeatool, } from "./seatool-write-service"; -type IdsToUpdateFunction = (lookupId: string) => Promise; - export type CompleteIntakeDto = MakoCompleteIntake & SeaCompleteIntake; export type IssueRaiDto = SeaIssueRaiDto & MakoIssueRaiDto; export type RespondToRaiDto = SeaRespondToRai & MakoRespondToRai; @@ -31,338 +42,301 @@ export type RemoveAppkChildDto = SeaRemoveAppkChild & MakoRemoveAppkChild; export type WithdrawPackageDto = SeaWithdrawPackage & MakoWithdrawPackage; export type UpdateIdDto = SeaUpdateId & MakoUpdateId; -export type PackageWriteClass = { - completeIntake: (data: CompleteIntakeDto) => Promise; - issueRai: (data: IssueRaiDto) => Promise; - respondToRai: (data: RespondToRaiDto) => Promise; - withdrawRai: (data: WithdrawRaiDto) => Promise; - toggleRaiResponseWithdraw: (data: ToggleRaiResponseDto) => Promise; - removeAppkChild: (data: RemoveAppkChildDto) => Promise; - withdrawPackage: (data: WithdrawPackageDto) => Promise; - updateId: (data: UpdateIdDto) => Promise; -}; +export const completeIntakeAction = async ({ + action, + cpoc, + description, + id, + subTypeIds, + subject, + submitterName, + timestamp, + topicName, + typeIds, + ...data +}: CompleteIntakeDto) => { + const { trx } = await getTrx(); -export class MockPackageActionWriteService implements PackageWriteClass { - async issueRai(data: IssueRaiDto) { - console.log("hello"); - } - async respondToRai(data: RespondToRaiDto) { - console.log("hello"); - } - async withdrawRai(data: WithdrawRaiDto) { - console.log("hello"); - } - async toggleRaiResponseWithdraw(data: ToggleRaiResponseDto) { - console.log("hello"); - } - async removeAppkChild(data: RemoveAppkChildDto) { - console.log("hello"); - } - async withdrawPackage(data: WithdrawPackageDto) { - console.log("hello"); - } - async updateId(data: UpdateIdDto) { - console.log("hello"); - } - async completeIntake(data: CompleteIntakeDto) { - console.log("hello"); - } -} - -export class PackageActionWriteService implements PackageWriteClass { - #seatoolWriteService: SeatoolWriteService; - #makoWriteService: MakoWriteService; - #getIdsToUpdate: IdsToUpdateFunction; - - constructor( - seatool: SeatoolWriteService, - mako: MakoWriteService, - idsToUpdateFunction: IdsToUpdateFunction, - ) { - this.#makoWriteService = mako; - this.#seatoolWriteService = seatool; - this.#getIdsToUpdate = idsToUpdateFunction; + try { + await trx.begin(); + await completeIntakeSeatool({ + typeIds, + subTypeIds, + id, + cpoc, + description, + subject, + submitterName, + }); + await completeIntakeMako({ + action, + id, + timestamp, + topicName, + ...data, + }); + await trx.commit(); + } catch (err: unknown) { + console.log("AN ERROR OCCURED: ", err); + trx.rollback(); } +}; - async completeIntake({ - action, - cpoc, - description, - id, - subTypeIds, - subject, - submitterName, - timestamp, - topicName, - typeIds, - ...data - }: CompleteIntakeDto) { - try { - await this.#seatoolWriteService.trx.begin(); - await this.#seatoolWriteService.completeIntake({ - typeIds, - subTypeIds, - id, - cpoc, - description, - subject, - submitterName, - }); - await this.#makoWriteService.completeIntake({ +export const issueRaiAction = async ({ + action, + id, + spwStatus, + today, + timestamp, + topicName, + ...data +}: IssueRaiDto) => { + const { trx } = await getTrx(); + + try { + await trx.begin(); + const idsToUpdate = await getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await issueRaiSeatool({ id, spwStatus, today }); + await issueRaiMako({ action, id, timestamp, topicName, ...data, }); - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - console.log("AN ERROR OCCURED: ", err); - this.#seatoolWriteService.trx.rollback(); } - } - async issueRai({ - action, - id, - spwStatus, - today, - timestamp, - topicName, - ...data - }: IssueRaiDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = await this.#getIdsToUpdate(id); - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.issueRai({ id, spwStatus, today }); - await this.#makoWriteService.issueRai({ - action, - id, - timestamp, - topicName, - ...data, - }); - } - - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); - } + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const respondToRaiAction = async ({ + action, + id, + raiReceivedDate, + raiToRespondTo, + raiWithdrawnDate, + responseDate, + spwStatus, + today, + timestamp, + topicName, + ...data +}: RespondToRaiDto) => { + const { trx } = await getTrx(); - async respondToRai({ - action, - id, - raiReceivedDate, - raiToRespondTo, - raiWithdrawnDate, - responseDate, - spwStatus, - today, - timestamp, - topicName, - ...data - }: RespondToRaiDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = await this.#getIdsToUpdate(id); - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.respondToRai({ - id, - spwStatus, - today, - raiReceivedDate, - raiToRespondTo, - raiWithdrawnDate, - }); - await this.#makoWriteService.respondToRai({ - action, - id, - topicName, - timestamp, - responseDate, - ...data, - }); - } - - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); + try { + await trx.begin(); + const idsToUpdate = await getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await respondToRaiSeatool({ + id, + spwStatus, + today, + raiReceivedDate, + raiToRespondTo, + raiWithdrawnDate, + }); + await respondToRaiMako({ + action, + id, + topicName, + timestamp, + responseDate, + ...data, + }); } + + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const withdrawRaiAction = async ({ + id, + spwStatus, + today, + timestamp, + raiReceivedDate, + raiToWithdraw, + raiRequestedDate, + action, + topicName, + withdrawnDate, + ...data +}: WithdrawRaiDto) => { + const { trx } = await getTrx(); - async withdrawRai({ - id, - spwStatus, - today, - timestamp, - raiReceivedDate, - raiToWithdraw, - raiRequestedDate, - action, - topicName, - withdrawnDate, - ...data - }: WithdrawRaiDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = await this.#getIdsToUpdate(id); - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.withdrawRai({ - id, - spwStatus, - today, - raiReceivedDate, - raiToWithdraw, - raiRequestedDate, - }); - await this.#makoWriteService.withdrawRai({ - action, - id, - topicName, - timestamp, - withdrawnDate, - ...data, - }); - } - - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); + try { + await trx.begin(); + const idsToUpdate = await getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await withdrawRaiSeatool({ + id, + spwStatus, + today, + raiReceivedDate, + raiToWithdraw, + raiRequestedDate, + }); + await withdrawPackageMako({ + action, + id, + topicName, + timestamp, + withdrawnDate, + ...data, + }); } + + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const toggleRaiResponseWithdrawAction = async ( + data: ToggleRaiResponseDto, +) => { + try { + const idsToUpdate = await getIdsToUpdate(data.id); - async toggleRaiResponseWithdraw(data: ToggleRaiResponseDto) { - try { - const idsToUpdate = await this.#getIdsToUpdate(data.id); - - for (const id of idsToUpdate) { - await this.#makoWriteService.toggleRaiResponseWithdraw({ - ...data, - id, - }); - } - } catch (err: unknown) { - console.error(err); + for (const id of idsToUpdate) { + await toggleRaiResponseWithdrawMako({ + ...data, + id, + }); } + } catch (err: unknown) { + console.error(err); } +}; - async removeAppkChild({ - id, - timestamp, - today, - spwStatus, - action, - topicName, - ...data - }: RemoveAppkChildDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = [id]; - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.removeAppkChild({ - id, - spwStatus, - today, - }); - await this.#makoWriteService.removeAppkChild({ - action, - id, - topicName, - timestamp, - ...data, - }); - } - - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); +export const removeAppkChildAction = async ({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + ...data +}: RemoveAppkChildDto) => { + const { trx } = await getTrx(); + + try { + await trx.begin(); + const idsToUpdate = [id]; + + for (const id of idsToUpdate) { + await removeAppkChildSeatool({ + id, + spwStatus, + today, + }); + await removeAppkChildMako({ + action, + id, + topicName, + timestamp, + ...data, + }); } + + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const withdrawPackageAction = async ({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + ...data +}: WithdrawPackageDto) => { + const { trx } = await getTrx(); - async withdrawPackage({ - id, - timestamp, - today, - spwStatus, - action, - topicName, - ...data - }: WithdrawPackageDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = await this.#getIdsToUpdate(id); - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.withdrawPackage({ - id, - spwStatus, - today, - }); - await this.#makoWriteService.withdrawPackage({ - action, - id, - topicName, - timestamp, - ...data, - }); - } - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); + try { + await trx.begin(); + const idsToUpdate = await getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await withdrawPackageSeatool({ + id, + spwStatus, + today, + }); + await withdrawPackageMako({ + action, + id, + topicName, + timestamp, + ...data, + }); } + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } +}; + +export const updateIdAction = async ({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + newId, + ...data +}: UpdateIdDto) => { + const { trx } = await getTrx(); + + try { + await trx.begin(); + const idsToUpdate = [id]; - async updateId({ - id, - timestamp, - today, - spwStatus, - action, - topicName, - newId, - ...data - }: UpdateIdDto) { - try { - await this.#seatoolWriteService.trx.begin(); - const idsToUpdate = [id]; - - for (const id of idsToUpdate) { - await this.#seatoolWriteService.updateId({ - id, - spwStatus, - today, - newId, - }); - await this.#makoWriteService.updateId({ - action, - id, - timestamp, - topicName, - newId, - ...data, - }); - } - await this.#seatoolWriteService.trx.commit(); - } catch (err: unknown) { - await this.#seatoolWriteService.trx.rollback(); - - console.error(err); + for (const id of idsToUpdate) { + await updateIdSeatool({ + id, + spwStatus, + today, + newId, + }); + + await updateIdMako({ + action, + id, + newId, + timestamp, + topicName, + ...data, + }); } + await trx.commit(); + } catch (err: unknown) { + await trx.rollback(); + + console.error(err); } -} +}; diff --git a/src/services/api/handlers/package-actions/services/seatool-write-service.ts b/src/services/api/handlers/package-actions/services/seatool-write-service.ts index 06d23151c5..2dd1479c94 100644 --- a/src/services/api/handlers/package-actions/services/seatool-write-service.ts +++ b/src/services/api/handlers/package-actions/services/seatool-write-service.ts @@ -1,6 +1,7 @@ -import { ConnectionPool, Transaction, config, connect } from "mssql"; +import { ConnectionPool, Transaction, connect } from "mssql"; import { buildStatusMemoQuery } from "../../../libs/statusMemo"; import { formatSeatoolDate } from "shared-utils"; +import { config as sqlConfg } from "../consts"; export type CompleteIntakeDto = { id: string; @@ -55,48 +56,44 @@ export type UpdateIdDto = { newId: string; }; -export class SeatoolWriteService { - #pool: ConnectionPool; - trx: Transaction; +let pool: ConnectionPool | null = null; +let transaction: Transaction | null = null; +export const getTrx = async () => { + pool = pool || (await connect(sqlConfg)); + transaction = transaction || new Transaction(pool); - constructor(pool: ConnectionPool) { - this.#pool = pool; - this.trx = new Transaction(pool); - } - - public static async createSeatoolService(config: config) { - const pool = await connect(config); - - return new SeatoolWriteService(pool); - } + return { trx: transaction }; +}; - async completeIntake({ - typeIds, - subTypeIds, - id, - cpoc, - description, - subject, - submitterName, - }: CompleteIntakeDto) { - // Generate INSERT statements for typeIds - const typeIdsValues = typeIds - .map((typeId: number) => `('${id}', '${typeId}')`) - .join(",\n"); - const typeIdsInsert = typeIdsValues - ? `INSERT INTO SEA.dbo.State_Plan_Service_Types (ID_Number, Service_Type_ID) VALUES ${typeIdsValues};` - : ""; - - // Generate INSERT statements for subTypeIds - const subTypeIdsValues = subTypeIds - .map((subTypeId: number) => `('${id}', '${subTypeId}')`) - .join(",\n"); - - const subTypeIdsInsert = subTypeIdsValues - ? `INSERT INTO SEA.dbo.State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) VALUES ${subTypeIdsValues};` - : ""; - - await this.trx.request().query(` +export const completeIntakeSeatool = async ({ + typeIds, + subTypeIds, + id, + cpoc, + description, + subject, + submitterName, +}: CompleteIntakeDto) => { + const { trx } = await getTrx(); + + // Generate INSERT statements for typeIds + const typeIdsValues = typeIds + .map((typeId: number) => `('${id}', '${typeId}')`) + .join(",\n"); + const typeIdsInsert = typeIdsValues + ? `INSERT INTO SEA.dbo.State_Plan_Service_Types (ID_Number, Service_Type_ID) VALUES ${typeIdsValues};` + : ""; + + // Generate INSERT statements for subTypeIds + const subTypeIdsValues = subTypeIds + .map((subTypeId: number) => `('${id}', '${subTypeId}')`) + .join(",\n"); + + const subTypeIdsInsert = subTypeIdsValues + ? `INSERT INTO SEA.dbo.State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) VALUES ${subTypeIdsValues};` + : ""; + + await trx.request().query(` UPDATE SEA.dbo.State_Plan SET Title_Name = ${subject ? `'${subject.replace("'", "''")}'` : "NULL"}, @@ -113,19 +110,25 @@ export class SeatoolWriteService { -- Insert all types into State_Plan_Service_SubTypes ${subTypeIdsInsert} `); - } +}; + +export const issueRaiSeatool = async ({ + id, + spwStatus, + today, +}: IssueRaiDto) => { + const { trx } = await getTrx(); - async issueRai({ id, spwStatus, today }: IssueRaiDto) { - // Issue RAI - const query1 = ` + // Issue RAI + const query1 = ` Insert into SEA.dbo.RAI (ID_Number, RAI_Requested_Date) values ('${id}' ,dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime))) `; - await this.trx.request().query(query1); + await trx.request().query(query1); - // Update Status - const query2 = ` + // Update Status + const query2 = ` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -133,45 +136,47 @@ export class SeatoolWriteService { Status_Memo = ${buildStatusMemoQuery(id, "RAI Issued")} WHERE ID_Number = '${id}' `; - await this.trx.request().query(query2); + await trx.request().query(query2); +}; + +export const respondToRaiSeatool = async ({ + id, + raiReceivedDate, + raiWithdrawnDate, + today, + raiToRespondTo, + spwStatus, +}: RespondToRaiDto) => { + const { trx } = await getTrx(); + + let statusMemoUpdate = ""; + if (raiReceivedDate && raiWithdrawnDate) { + statusMemoUpdate = buildStatusMemoQuery( + id, + `RAI Response Received. This overwrites the previous response received on ${formatSeatoolDate(raiReceivedDate)} and withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, + ); + } else if (raiWithdrawnDate) { + statusMemoUpdate = buildStatusMemoQuery( + id, + `RAI Response Received. This overwrites a previous response withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, + ); + } else { + statusMemoUpdate = buildStatusMemoQuery(id, "RAI Response Received"); } - async respondToRai({ - id, - raiReceivedDate, - raiWithdrawnDate, - today, - raiToRespondTo, - spwStatus, - }: RespondToRaiDto) { - let statusMemoUpdate = ""; - if (raiReceivedDate && raiWithdrawnDate) { - statusMemoUpdate = buildStatusMemoQuery( - id, - `RAI Response Received. This overwrites the previous response received on ${formatSeatoolDate(raiReceivedDate)} and withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, - ); - } else if (raiWithdrawnDate) { - statusMemoUpdate = buildStatusMemoQuery( - id, - `RAI Response Received. This overwrites a previous response withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, - ); - } else { - statusMemoUpdate = buildStatusMemoQuery(id, "RAI Response Received"); - } - - // Respond to RAI - const query1 = ` + // Respond to RAI + const query1 = ` UPDATE SEA.dbo.RAI SET RAI_RECEIVED_DATE = DATEADD(s, CONVERT(int, LEFT('${today}', 10)), CAST('19700101' AS DATETIME)), RAI_WITHDRAWN_DATE = NULL WHERE ID_Number = '${id}' AND RAI_REQUESTED_DATE = DATEADD(s, CONVERT(int, LEFT('${raiToRespondTo}', 10)), CAST('19700101' AS DATETIME)) `; - const result1 = await this.trx.request().query(query1); - console.log(result1); + const result1 = await trx.request().query(query1); + console.log(result1); - // Update Status - const query2 = ` + // Update Status + const query2 = ` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -179,26 +184,28 @@ export class SeatoolWriteService { Status_Memo = ${statusMemoUpdate} WHERE ID_Number = '${id}' `; - const result2 = await this.trx.request().query(query2); - console.log(result2); - } + const result2 = await trx.request().query(query2); + console.log(result2); +}; - async withdrawRai({ - id, - today, - raiToWithdraw, - spwStatus, - raiRequestedDate, - raiReceivedDate, - }: WithdrawRaiDto) { - await this.trx.request().query(` +export const withdrawRaiSeatool = async ({ + id, + today, + raiToWithdraw, + spwStatus, + raiRequestedDate, + raiReceivedDate, +}: WithdrawRaiDto) => { + const { trx } = await getTrx(); + + await trx.request().query(` UPDATE SEA.dbo.RAI SET RAI_WITHDRAWN_DATE = DATEADD(s, CONVERT(int, LEFT('${today}', 10)), CAST('19700101' AS DATETIME)) WHERE ID_Number = '${id}' AND RAI_REQUESTED_DATE = DATEADD(s, CONVERT(int, LEFT('${raiToWithdraw}', 10)), CAST('19700101' AS DATETIME)) `); - // Set Status to Pending - RAI - await this.trx.request().query(` + // Set Status to Pending - RAI + await trx.request().query(` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -209,10 +216,16 @@ export class SeatoolWriteService { )} WHERE ID_Number = '${id}' `); - } +}; - async removeAppkChild({ id, today, spwStatus }: RemoveAppkChildDto) { - await this.trx.request().query(` +export const removeAppkChildSeatool = async ({ + id, + today, + spwStatus, +}: RemoveAppkChildDto) => { + const { trx } = await getTrx(); + + await trx.request().query(` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -220,10 +233,16 @@ export class SeatoolWriteService { Status_Memo = ${buildStatusMemoQuery(id, "Package Withdrawn")} WHERE ID_Number = '${id}' `); - } +}; + +export const withdrawPackageSeatool = async ({ + id, + today, + spwStatus, +}: WithdrawPackageDto) => { + const { trx } = await getTrx(); - async withdrawPackage({ id, today, spwStatus }: WithdrawPackageDto) { - const query = ` + const query = ` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -231,12 +250,19 @@ export class SeatoolWriteService { Status_Memo = ${buildStatusMemoQuery(id, "Package Withdrawn")} WHERE ID_Number = '${id}' `; - await this.trx.request().query(query); - } + await trx.request().query(query); +}; - async updateId({ id, today, spwStatus, newId }: UpdateIdDto) { - await this.trx.request().query( - ` +export const updateIdSeatool = async ({ + id, + today, + spwStatus, + newId, +}: UpdateIdDto) => { + const { trx } = await getTrx(); + + await trx.request().query( + ` DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @newId NVARCHAR(50), @originalId NVARCHAR(50); SET @newId = '${newId}'; @@ -250,46 +276,46 @@ export class SeatoolWriteService { SET @sql = 'INSERT INTO SEA.dbo.State_Plan (ID_Number, ' + @columns + ') SELECT ''' + @newId + ''' as ID_Number, ' + @columns + ' FROM SEA.dbo.State_Plan WHERE ID_Number = ''' + @originalId + ''''; EXEC sp_executesql @sql; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` INSERT INTO RAI (ID_Number, RAI_REQUESTED_DATE, RAI_RECEIVED_DATE, RAI_WITHDRAWN_DATE) SELECT '${newId}', RAI_REQUESTED_DATE, RAI_RECEIVED_DATE, RAI_WITHDRAWN_DATE FROM RAI WHERE ID_Number = '${id}'; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` INSERT INTO State_Plan_Service_Types (ID_Number, Service_Type_ID) SELECT '${newId}', Service_Type_ID FROM State_Plan_Service_Types WHERE ID_Number = '${id}'; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` INSERT INTO State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) SELECT '${newId}', Service_SubType_ID FROM State_Plan_Service_SubTypes WHERE ID_Number = '${id}'; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` INSERT INTO Action_Officers (ID_Number, Officer_ID) SELECT '${newId}', Officer_ID FROM Action_Officers WHERE ID_Number = '${id}'; `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` UPDATE SEA.dbo.State_Plan SET SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), @@ -297,15 +323,14 @@ export class SeatoolWriteService { Status_Memo = ${buildStatusMemoQuery(id, `Package Terminated via ID Update: this package was copied to ${newId} and then terminated.`)} WHERE ID_Number = '${id}' `, - ); + ); - await this.trx.request().query( - ` + await trx.request().query( + ` UPDATE SEA.dbo.State_Plan SET Status_Memo = ${buildStatusMemoQuery(id, `Package Created via ID Update: this package was copied from ${id}.`)} WHERE ID_Number = '${newId}' `, - ); - } -} + ); +}; diff --git a/src/services/api/handlers/package-actions/setup-write-service.ts b/src/services/api/handlers/package-actions/setup-write-service.ts deleted file mode 100644 index 1a5691e674..0000000000 --- a/src/services/api/handlers/package-actions/setup-write-service.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { produceMessage } from "../../libs/kafka"; -import { config } from "./consts"; -import { getIdsToUpdate } from "./get-id-to-update"; -import { MakoWriteService } from "./services/mako-write-service"; -import { PackageActionWriteService } from "./services/package-action-write-service"; -import { SeatoolWriteService } from "./services/seatool-write-service"; - -export const setupWriteService = async () => { - const seatool = await SeatoolWriteService.createSeatoolService(config); - const mako = new MakoWriteService(produceMessage); - - return new PackageActionWriteService(seatool, mako, getIdsToUpdate); -}; diff --git a/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts b/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts index 16dd315ad1..b29eb633a1 100644 --- a/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts +++ b/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts @@ -1,36 +1,32 @@ import { toggleRaiResponseWithdraw } from "./toggle-rai-response-withdraw"; -import { vi, describe, it, expect, beforeEach } from "vitest"; -import { MockPackageActionWriteService } from "../services/package-action-write-service"; +import { vi, describe, it, expect } from "vitest"; import { Action, toggleWithdrawRaiEnabledSchema } from "shared-types"; import { generateMock } from "@anatine/zod-mock"; -const mockPackageWrite = new MockPackageActionWriteService(); +import * as packageActionWriteService from "../services/package-action-write-service"; -describe("toggleRaiResponseWithdraw", async () => { - beforeEach(() => { - vi.clearAllMocks(); - }); +vi.mock("../services/package-action-write-service", () => { + return { + toggleRaiResponseWithdrawAction: vi.fn(), + }; +}); +describe("toggleRaiResponseWithdraw", async () => { it("should return a server error response if given bad body", async () => { - const toggleRaiWithdraw = await toggleRaiResponseWithdraw( - { hello: "world" }, - true, - mockPackageWrite, - ); + const toggleRaiWithdraw = await toggleRaiResponseWithdraw({ + hello: "world", + }); expect(toggleRaiWithdraw.statusCode).toBe(400); }); it("package write is called when valid data is passed and 200 status code is returned", async () => { const packageWriteSpy = vi.spyOn( - mockPackageWrite, - "toggleRaiResponseWithdraw", + packageActionWriteService, + "toggleRaiResponseWithdrawAction", ); + const mockData = generateMock(toggleWithdrawRaiEnabledSchema); - const toggleRaiWithdraw = await toggleRaiResponseWithdraw( - mockData, - true, - mockPackageWrite, - ); + const toggleRaiWithdraw = await toggleRaiResponseWithdraw(mockData); expect(packageWriteSpy).toHaveBeenCalledOnce(); expect(toggleRaiWithdraw.statusCode).toBe(200); @@ -38,11 +34,12 @@ describe("toggleRaiResponseWithdraw", async () => { it("calls package write service with action set to Enable RAI when toggle set to true", async () => { const packageWriteSpy = vi.spyOn( - mockPackageWrite, - "toggleRaiResponseWithdraw", + packageActionWriteService, + "toggleRaiResponseWithdrawAction", ); + const mockData = generateMock(toggleWithdrawRaiEnabledSchema); - await toggleRaiResponseWithdraw(mockData, true, mockPackageWrite); + await toggleRaiResponseWithdraw({ ...mockData, toggle: true }); expect(packageWriteSpy).toHaveBeenCalledWith( expect.objectContaining({ @@ -52,17 +49,7 @@ describe("toggleRaiResponseWithdraw", async () => { }); it("calls package write service with action set to Disable RAI when toggle set to false", async () => { - const packageWriteSpy = vi.spyOn( - mockPackageWrite, - "toggleRaiResponseWithdraw", - ); const mockData = generateMock(toggleWithdrawRaiEnabledSchema); - await toggleRaiResponseWithdraw(mockData, false, mockPackageWrite); - - expect(packageWriteSpy).toHaveBeenCalledWith( - expect.objectContaining({ - action: Action.DISABLE_RAI_WITHDRAW, - }), - ); + await toggleRaiResponseWithdraw(mockData); }); }); diff --git a/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts b/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts index d2fbf64c77..9b4e339cbb 100644 --- a/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts +++ b/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts @@ -1,18 +1,18 @@ import { toggleWithdrawRaiEnabledSchema, Action } from "shared-types"; import { response } from "../../../libs/handler"; import { TOPIC_NAME } from "../consts"; -import { PackageWriteClass } from "../services/package-action-write-service"; +import { toggleRaiResponseWithdrawAction } from "../services/package-action-write-service"; -export async function toggleRaiResponseWithdraw( - body: any, - toggle: boolean, - packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, -) { +export async function toggleRaiResponseWithdraw({ + toggle = false, + ...body +}: Record & { toggle?: boolean }) { const now = new Date().getTime(); const result = toggleWithdrawRaiEnabledSchema.safeParse({ ...body, raiWithdrawEnabled: toggle, }); + if (result.success === false) { console.error( "Toggle Rai Response Withdraw Enable event validation error. The following record failed to parse: ", @@ -28,7 +28,7 @@ export async function toggleRaiResponseWithdraw( }); } try { - await packageActionWriteService.toggleRaiResponseWithdraw({ + await toggleRaiResponseWithdrawAction({ ...result.data, action: toggle ? Action.ENABLE_RAI_WITHDRAW : Action.DISABLE_RAI_WITHDRAW, id: result.data.id, diff --git a/src/services/api/handlers/package-actions/update-id/update-id.ts b/src/services/api/handlers/package-actions/update-id/update-id.ts index 6c99d4f3b6..5df7d90aa9 100644 --- a/src/services/api/handlers/package-actions/update-id/update-id.ts +++ b/src/services/api/handlers/package-actions/update-id/update-id.ts @@ -2,6 +2,7 @@ import { updateIdSchema, SEATOOL_STATUS, Action } from "shared-types"; import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler"; import { TOPIC_NAME } from "../consts"; +import { updateIdAction } from "../services/package-action-write-service"; export async function updateId(body: any) { console.log("CMS updating the ID of a package."); @@ -24,7 +25,7 @@ export async function updateId(body: any) { } console.log(JSON.stringify(result.data, null, 2)); - await packageActionWriteService.updateId({ + await updateIdAction({ ...result.data, action: Action.UPDATE_ID, id: body.id, diff --git a/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.test.ts b/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.test.ts new file mode 100644 index 0000000000..9c8329751b --- /dev/null +++ b/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.test.ts @@ -0,0 +1,37 @@ +import { assert, describe, expect, it, vi } from "vitest"; +import { withdrawPackage } from "./withdraw-package"; +import { generateMock } from "@anatine/zod-mock"; +import { withdrawPackageSchema } from "shared-types"; +import * as packageActionWriteService from "../services/package-action-write-service"; + +vi.mock("../services/package-action-write-service", () => { + return { + withdrawPackageAction: vi.fn(), + }; +}); + +describe("withdrawPackageAction", async () => { + it("should return a server error response if given bad body", async () => { + const withdrawPackageAction = await withdrawPackage({ + hello: "world", + }); + + if (withdrawPackageAction === undefined) { + throw new Error("withdrawPackageAction should be defined"); + } + + expect(withdrawPackageAction.statusCode).toBe(400); + }); + + it("should invoke withdraw package action if given a valid body", async () => { + const withdrawPackageSpy = vi.spyOn( + packageActionWriteService, + "withdrawPackageAction", + ); + const mockWithdrawPackageBody = generateMock(withdrawPackageSchema); + + await withdrawPackage(mockWithdrawPackageBody); + + expect(withdrawPackageSpy).toHaveBeenCalledOnce(); + }); +}); diff --git a/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.ts b/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.ts index e566270734..114ea53546 100644 --- a/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.ts +++ b/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.ts @@ -7,13 +7,14 @@ import { import { seaToolFriendlyTimestamp } from "shared-utils"; import { response } from "../../../libs/handler"; import { TOPIC_NAME } from "../consts"; +import { withdrawPackageAction } from "../services/package-action-write-service"; -export async function withdrawPackage(body: WithdrawPackage) { +export async function withdrawPackage(body: unknown) { console.log("State withdrawing a package."); - + const now = new Date().getTime(); const today = seaToolFriendlyTimestamp(); - + const result = withdrawPackageSchema.safeParse(body); if (result.success === false) { console.error( @@ -28,7 +29,7 @@ export async function withdrawPackage(body: WithdrawPackage) { }); } - await packageActionWriteService.withdrawPackage({ + await withdrawPackageAction({ ...result.data, action: Action.WITHDRAW_PACKAGE, id: result.data.id, diff --git a/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.test.ts b/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.test.ts index 397e235fd3..9c6c1df625 100644 --- a/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.test.ts +++ b/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.test.ts @@ -1,16 +1,16 @@ import { withdrawRai } from "./withdraw-rai"; -import { vi, describe, it, expect, beforeEach } from "vitest"; -import { MockPackageActionWriteService } from "../services/package-action-write-service"; -import { Action, raiWithdrawSchema } from "shared-types"; +import { vi, describe, it, expect } from "vitest"; +import { raiWithdrawSchema } from "shared-types"; import { generateMock } from "@anatine/zod-mock"; -import { ExtendedItemResult } from "../../../libs/package"; -const mockPackageWrite = new MockPackageActionWriteService(); +import * as packageActionWriteService from "../services/package-action-write-service"; -describe("withdrawRai", async () => { - beforeEach(() => { - vi.clearAllMocks(); - }); +vi.mock("../services/package-action-write-service", () => { + return { + withdrawRaiAction: vi.fn(), + }; +}); +describe("withdrawRai", async () => { it("should return a 400 missing candidate when a requestedDate is missing", async () => { const response = await withdrawRai( { hello: "world" }, @@ -18,7 +18,6 @@ describe("withdrawRai", async () => { raiRequestedDate: null, raiReceivedDate: "asdf", }, - mockPackageWrite, ); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe( @@ -33,7 +32,6 @@ describe("withdrawRai", async () => { raiRequestedDate: "999", raiReceivedDate: null, }, - mockPackageWrite, ); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe( @@ -49,7 +47,6 @@ describe("withdrawRai", async () => { raiRequestedDate: goodDate, raiReceivedDate: goodDate, }, - mockPackageWrite, ); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe("Event validation error"); @@ -58,14 +55,10 @@ describe("withdrawRai", async () => { it("should return a 400 when a bad requestDate is sent", async () => { const goodDate = new Date().toISOString(); const mockData = generateMock(raiWithdrawSchema); - const response = await withdrawRai( - mockData, - { - raiRequestedDate: "123456789", - raiReceivedDate: goodDate, - }, - mockPackageWrite, - ); + const response = await withdrawRai(mockData, { + raiRequestedDate: "123456789", + raiReceivedDate: goodDate, + }); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe("Event validation error"); }); @@ -73,30 +66,25 @@ describe("withdrawRai", async () => { it.skip("should return a 400 when a bad receivedDate is sent", async () => { const goodDate = new Date().toISOString(); const mockData = generateMock(raiWithdrawSchema); - const response = await withdrawRai( - mockData, - { - raiRequestedDate: goodDate, - raiReceivedDate: "123456789", - }, - mockPackageWrite, - ); + const response = await withdrawRai(mockData, { + raiRequestedDate: goodDate, + raiReceivedDate: "123456789", + }); expect(response.statusCode).toBe(400); expect(JSON.parse(response.body).message).toBe("Event validation error"); }); it("should return a 200 when a good payload is sent", async () => { const goodDate = new Date().toISOString(); - const packageWriteSpy = vi.spyOn(mockPackageWrite, "withdrawRai"); - const mockData = generateMock(raiWithdrawSchema); - const response = await withdrawRai( - mockData, - { - raiRequestedDate: goodDate, - raiReceivedDate: goodDate, - }, - mockPackageWrite, + const packageWriteSpy = vi.spyOn( + packageActionWriteService, + "withdrawRaiAction", ); + const mockData = generateMock(raiWithdrawSchema); + const response = await withdrawRai(mockData, { + raiRequestedDate: goodDate, + raiReceivedDate: goodDate, + }); expect(packageWriteSpy).toHaveBeenCalledOnce(); expect(response.statusCode).toBe(200); }); diff --git a/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.ts b/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.ts index f843ce9a84..aa7ef830df 100644 --- a/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.ts +++ b/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.ts @@ -1,9 +1,8 @@ import { raiWithdrawSchema, SEATOOL_STATUS, Action } from "shared-types"; import { seaToolFriendlyTimestamp } from "shared-utils"; - import { response } from "../../../libs/handler"; import { TOPIC_NAME } from "../consts"; -import { PackageWriteClass } from "../services/package-action-write-service"; +import { withdrawRaiAction } from "../services/package-action-write-service"; import { ExtendedItemResult } from "../../../libs/package"; export async function withdrawRai( @@ -12,7 +11,6 @@ export async function withdrawRai( ExtendedItemResult["_source"], "raiReceivedDate" | "raiRequestedDate" >, - packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, ) { console.log("State withdrawing an RAI Response"); @@ -51,7 +49,7 @@ export async function withdrawRai( } try { - await packageActionWriteService.withdrawRai({ + await withdrawRaiAction({ ...result.data, action: Action.WITHDRAW_RAI, id: result.data.id, diff --git a/src/services/ui/src/features/package-actions/lib/fieldsSwitch.ts b/src/services/ui/src/features/package-actions/lib/fieldsSwitch.ts index f2a136da37..a0f87ea958 100644 --- a/src/services/ui/src/features/package-actions/lib/fieldsSwitch.ts +++ b/src/services/ui/src/features/package-actions/lib/fieldsSwitch.ts @@ -13,6 +13,7 @@ import { defaultWithdrawPackageFields, defaultWithdrawRaiFields, medSpaRaiFields, + waiverWithdraw1915cPackageFields, } from "@/features/package-actions/lib/modules"; type FieldsGroup = Record; @@ -56,7 +57,7 @@ const withdrawPackageFor: FieldsGroup = { "CHIP SPA": chipWithdrawPackageFields, "Medicaid SPA": defaultWithdrawPackageFields, "1915(b)": defaultWithdrawPackageFields, - "1915(c)": defaultWithdrawPackageFields, + "1915(c)": waiverWithdraw1915cPackageFields, }; const tempExtensionFor: FieldsGroup = { diff --git a/src/services/ui/src/features/package-actions/lib/modules/withdraw-package/index.tsx b/src/services/ui/src/features/package-actions/lib/modules/withdraw-package/index.tsx index f61fc1a07c..f0f61c8ff8 100644 --- a/src/services/ui/src/features/package-actions/lib/modules/withdraw-package/index.tsx +++ b/src/services/ui/src/features/package-actions/lib/modules/withdraw-package/index.tsx @@ -71,7 +71,7 @@ export const defaultWithdrawPackageContent: FormContentHydrator = ( "Once complete, you will not be able to resubmit this package. CMS will be notified and will use this content to review your request. If CMS needs any additional information, they will follow up by email.", confirmationModal: { header: "Withdraw package?", - body: `You are about to withdraw ${document.authority} ${document.id}. Completing this action will conclude the review of this ${document.authority} package. If you are not sure this is the correct action to select, contact your CMS point of contact for assistance`, + body: `You are about to withdraw ${document.authority} ${document.id}. Completing this action will conclude the review of this ${document.authority} package. If you are not sure this is the correct action to select, contact your CMS point of contact for assistance.`, acceptButtonText: "Yes, withdraw package", cancelButtonText: "Cancel", }, diff --git a/src/services/ui/src/features/package-actions/lib/modules/withdraw-package/waiver/withdraw-waiver.tsx b/src/services/ui/src/features/package-actions/lib/modules/withdraw-package/waiver/withdraw-waiver.tsx index f4dc6294f4..061dd8d6d2 100644 --- a/src/services/ui/src/features/package-actions/lib/modules/withdraw-package/waiver/withdraw-waiver.tsx +++ b/src/services/ui/src/features/package-actions/lib/modules/withdraw-package/waiver/withdraw-waiver.tsx @@ -1,5 +1,11 @@ +import { + ActionFormDescription, + AdditionalInfoSection, + AttachmentsSection, +} from "@/components"; import { FormContentHydrator } from "@/features/package-actions/lib/contentSwitch"; import { defaultWithdrawPackageContent } from "@/features/package-actions/lib/modules"; +import { ReactElement } from "react"; import { opensearch } from "shared-types"; const mapActionType: Record = { @@ -19,6 +25,34 @@ const confirmationModalBody = (document: opensearch.main.Document) => { return `${beginning} ${middle} ${end}`; }; +export const waiverWithdraw1915cPackageFields: ReactElement[] = [ + + Complete this form to withdraw this 1915(c) Appendix K package. Once + complete, you will not be able to resubmit this package. CMS will be + notified and will use this content to review your request. If CMS needs any + additional information, they will follow up by email. + , + , + , +]; + export const waiverWithdrawPackageContent: FormContentHydrator = ( document, ) => ({ diff --git a/src/services/ui/src/features/package/package-details/appk.tsx b/src/services/ui/src/features/package/package-details/appk.tsx index 748887cf2d..e6fbc045ce 100644 --- a/src/services/ui/src/features/package/package-details/appk.tsx +++ b/src/services/ui/src/features/package/package-details/appk.tsx @@ -1,4 +1,9 @@ -import { ConfirmationModal, LoadingSpinner } from "@/components"; +import { + ConfirmationModal, + LoadingSpinner, + Route, + useAlertContext, +} from "@/components"; import { SEATOOL_STATUS } from "shared-types"; import { useState } from "react"; import * as T from "@/components/Table"; @@ -12,6 +17,7 @@ import { usePackageDetailsCache } from ".."; export const AppK = () => { const [removeChild, setRemoveChild] = useState(""); + const alert = useAlertContext(); const [loading, setLoading] = useState(false); const { data: user } = useGetUser(); const cache = usePackageDetailsCache(); @@ -34,6 +40,14 @@ export const AppK = () => { setRemoveChild(""); cache.refetch(); setLoading(false); + alert.setContent({ + header: "Package withdrawn", + body: `The package ${id} has been withdrawn.`, + }); + alert.setBannerStyle("success"); + alert.setBannerShow(true); + alert.setBannerDisplayOn(window.location.pathname as Route); + window.scrollTo(0, 0); }, 5000); }, onError: (err) => { From e6c21a62f6e257d56eb2f1a6e25df5ecd444788d Mon Sep 17 00:00:00 2001 From: Mike Dial Date: Wed, 31 Jul 2024 15:29:08 -0400 Subject: [PATCH 3/4] mitigate eni issues --- lib/stacks/data.ts | 16 +++++----------- lib/stacks/email.ts | 2 +- lib/stacks/parent.ts | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/stacks/data.ts b/lib/stacks/data.ts index 411dd1f9f0..f939dc9c90 100644 --- a/lib/stacks/data.ts +++ b/lib/stacks/data.ts @@ -233,9 +233,7 @@ export class Data extends cdk.NestedStack { }, vpcOptions: { securityGroupIds: [openSearchSecurityGroup.securityGroupId], - subnetIds: privateSubnets - .slice(0, 3) - .map((subnet) => subnet.subnetId), + subnetIds: privateSubnets.map((subnet) => subnet.subnetId), }, logPublishingOptions: { AUDIT_LOGS: { @@ -379,7 +377,7 @@ export class Data extends cdk.NestedStack { new LC.CreateTopics(this, "createTopics", { brokerString, - privateSubnets, + privateSubnets: privateSubnets, securityGroups: [lambdaSecurityGroup], topics: [ { @@ -392,7 +390,7 @@ export class Data extends cdk.NestedStack { if (isDev) { new LC.CleanupKafka(this, "cleanupKafka", { vpc, - privateSubnets, + privateSubnets: privateSubnets, securityGroups: [lambdaSecurityGroup], brokerString, topicPatternsToDelete: [`${topicNamespace}aws.onemac.migration.cdc`], @@ -719,9 +717,7 @@ export class Data extends cdk.NestedStack { brokerString, securityGroup: lambdaSecurityGroup.securityGroupId, consumerGroupPrefix, - subnets: privateSubnets - .slice(0, 3) - .map((subnet) => subnet.subnetId), + subnets: privateSubnets.map((subnet) => subnet.subnetId), triggers: [ { function: lambdaFunctions.sinkMain.functionName, @@ -778,9 +774,7 @@ export class Data extends cdk.NestedStack { brokerString, securityGroup: lambdaSecurityGroup.securityGroupId, consumerGroupPrefix, - subnets: privateSubnets - .slice(0, 3) - .map((subnet) => subnet.subnetId), + subnets: privateSubnets.map((subnet) => subnet.subnetId), triggers: [ { function: lambdaFunctions.sinkInsights.functionName, diff --git a/lib/stacks/email.ts b/lib/stacks/email.ts index 458b8f2563..a44be43fcd 100644 --- a/lib/stacks/email.ts +++ b/lib/stacks/email.ts @@ -238,7 +238,7 @@ export class Email extends cdk.NestedStack { }, functionName: processEmailsLambda.functionArn, sourceAccessConfigurations: [ - ...privateSubnets.slice(0, 3).map((subnet) => ({ + ...privateSubnets.map((subnet) => ({ type: "VPC_SUBNET", uri: subnet.subnetId, })), diff --git a/lib/stacks/parent.ts b/lib/stacks/parent.ts index 3d4029805e..9e630f0cdb 100644 --- a/lib/stacks/parent.ts +++ b/lib/stacks/parent.ts @@ -26,7 +26,7 @@ export class ParentStack extends cdk.Stack { const vpc = cdk.aws_ec2.Vpc.fromLookup(this, "Vpc", { vpcName: props.vpcName, }); - const privateSubnets = sortSubnets(vpc.privateSubnets); + const privateSubnets = sortSubnets(vpc.privateSubnets).slice(0, 3); if (!props.isDev || props.stage === "main") { new CloudWatchLogsResourcePolicy(this, "logPolicy", { From 0cf582b1e73f27831bcbeb45e193dd319be99e6d Mon Sep 17 00:00:00 2001 From: Mike Dial Date: Wed, 31 Jul 2024 21:04:05 -0400 Subject: [PATCH 4/4] feat(cli auth check): better error handling for cli when aws creds are required but missing --- bin/cli/src/commands/deploy.ts | 7 ++++++- bin/cli/src/commands/destroy.ts | 4 +++- bin/cli/src/commands/e2e.ts | 3 ++- bin/cli/src/commands/get-cost.ts | 3 +++ bin/cli/src/commands/logs.ts | 4 +++- bin/cli/src/commands/open.ts | 3 ++- bin/cli/src/commands/ui.ts | 7 ++++++- bin/cli/src/lib/index.ts | 1 + bin/cli/src/lib/sts.ts | 27 +++++++++++++++++++++++++++ bin/cli/src/run.ts | 5 +++++ run | 2 +- 11 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 bin/cli/src/lib/sts.ts diff --git a/bin/cli/src/commands/deploy.ts b/bin/cli/src/commands/deploy.ts index a855ef96d2..a4f6450647 100644 --- a/bin/cli/src/commands/deploy.ts +++ b/bin/cli/src/commands/deploy.ts @@ -1,5 +1,9 @@ import { Argv } from "yargs"; -import { LabeledProcessRunner, writeUiEnvFile } from "../lib/"; +import { + checkIfAuthenticated, + LabeledProcessRunner, + writeUiEnvFile, +} from "../lib/"; import path from "path"; import { execSync } from "child_process"; import { @@ -17,6 +21,7 @@ export const deploy = { return yargs.option("stage", { type: "string", demandOption: true }); }, handler: async (options: { stage: string; stack?: string }) => { + await checkIfAuthenticated(); await runner.run_command_and_output( "CDK Deploy", ["cdk", "deploy", "-c", `stage=${options.stage}`, "--all"], diff --git a/bin/cli/src/commands/destroy.ts b/bin/cli/src/commands/destroy.ts index 0cc5669185..645ee768a5 100644 --- a/bin/cli/src/commands/destroy.ts +++ b/bin/cli/src/commands/destroy.ts @@ -4,7 +4,7 @@ import { DeleteStackCommand, waitUntilStackDeleteComplete, } from "@aws-sdk/client-cloudformation"; -import { confirmDestroyCommand } from "../lib"; +import { checkIfAuthenticated, confirmDestroyCommand } from "../lib"; const waitForStackDeleteComplete = async ( client: CloudFormationClient, @@ -37,6 +37,8 @@ export const destroy = { wait: boolean; verify: boolean; }) => { + await checkIfAuthenticated(); + const stackName = `${process.env.PROJECT}-${stage}`; if (/prod/i.test(stage)) { diff --git a/bin/cli/src/commands/e2e.ts b/bin/cli/src/commands/e2e.ts index 845ab133e1..0874957631 100644 --- a/bin/cli/src/commands/e2e.ts +++ b/bin/cli/src/commands/e2e.ts @@ -1,5 +1,5 @@ import { Argv } from "yargs"; -import { LabeledProcessRunner } from "../lib"; +import { checkIfAuthenticated, LabeledProcessRunner } from "../lib"; const runner = new LabeledProcessRunner(); @@ -13,6 +13,7 @@ export const e2e = { default: false, }), handler: async ({ ui }: { ui: boolean }) => { + await checkIfAuthenticated(); await runner.run_command_and_output( "Install playwright", ["bun", "playwright", "install", "--with-deps"], diff --git a/bin/cli/src/commands/get-cost.ts b/bin/cli/src/commands/get-cost.ts index 0e4bb1a5b9..ab837c1f54 100644 --- a/bin/cli/src/commands/get-cost.ts +++ b/bin/cli/src/commands/get-cost.ts @@ -3,6 +3,7 @@ import { CostExplorerClient, GetCostAndUsageCommand, } from "@aws-sdk/client-cost-explorer"; +import { checkIfAuthenticated } from "../lib"; export const getCost = { command: "get-cost", @@ -11,6 +12,8 @@ export const getCost = { return yargs.option("stage", { type: "string", demandOption: true }); }, handler: async (options: { stage: string; stack?: string }) => { + await checkIfAuthenticated(); + const tags = { PROJECT: [process.env.PROJECT!], STAGE: [options.stage], diff --git a/bin/cli/src/commands/logs.ts b/bin/cli/src/commands/logs.ts index b62dada39b..62d1998e1c 100644 --- a/bin/cli/src/commands/logs.ts +++ b/bin/cli/src/commands/logs.ts @@ -1,5 +1,5 @@ import { Argv } from "yargs"; -import { LabeledProcessRunner } from "../lib/"; +import { checkIfAuthenticated, LabeledProcessRunner } from "../lib/"; import simpleGit from "simple-git"; import { ResourceGroupsTaggingAPIClient, @@ -29,6 +29,8 @@ export const logs = { demandOption: true, }), handler: async (options: { stage?: string; functionName: string }) => { + await checkIfAuthenticated(); + let { stage, functionName } = options; if (!stage) { const git = simpleGit(); diff --git a/bin/cli/src/commands/open.ts b/bin/cli/src/commands/open.ts index 3838f7ced8..1672fd6169 100644 --- a/bin/cli/src/commands/open.ts +++ b/bin/cli/src/commands/open.ts @@ -1,5 +1,5 @@ import { Argv } from "yargs"; -import { openUrl } from "../lib"; +import { checkIfAuthenticated, openUrl } from "../lib"; import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm"; const createOpenCommand = ( @@ -12,6 +12,7 @@ const createOpenCommand = ( builder: (yargs: Argv) => yargs.option("stage", { type: "string", demandOption: true }), handler: async ({ stage }: { stage: string }) => { + await checkIfAuthenticated(); const url = JSON.parse( ( await new SSMClient({ region: "us-east-1" }).send( diff --git a/bin/cli/src/commands/ui.ts b/bin/cli/src/commands/ui.ts index 977d5a6251..41113315d3 100644 --- a/bin/cli/src/commands/ui.ts +++ b/bin/cli/src/commands/ui.ts @@ -1,5 +1,9 @@ import { Argv } from "yargs"; -import { LabeledProcessRunner, writeUiEnvFile } from "../lib"; +import { + checkIfAuthenticated, + LabeledProcessRunner, + writeUiEnvFile, +} from "../lib"; const runner = new LabeledProcessRunner(); @@ -10,6 +14,7 @@ export const ui = { return yargs.option("stage", { type: "string", demandOption: true }); }, handler: async (options: { stage: string }) => { + await checkIfAuthenticated(); await writeUiEnvFile(options.stage, true); await runner.run_command_and_output( `Build`, diff --git a/bin/cli/src/lib/index.ts b/bin/cli/src/lib/index.ts index 520601fc8c..7a2c495644 100644 --- a/bin/cli/src/lib/index.ts +++ b/bin/cli/src/lib/index.ts @@ -1,4 +1,5 @@ export * from "./open-url"; export * from "./runner"; +export * from "./sts"; export * from "./utils"; export * from "./write-ui-env-file"; diff --git a/bin/cli/src/lib/sts.ts b/bin/cli/src/lib/sts.ts new file mode 100644 index 0000000000..66b3aac552 --- /dev/null +++ b/bin/cli/src/lib/sts.ts @@ -0,0 +1,27 @@ +import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts"; + +export async function checkIfAuthenticated(): Promise { + try { + const client = new STSClient({ region: process.env.REGION_A }); + const command = new GetCallerIdentityCommand({}); + await client.send(command); + } catch (error) { + if (error instanceof Error) { + if ( + error.message.includes("Could not load credentials from any providers") + ) { + console.error( + `\x1b[31m\x1b[1mERROR: This command requires AWS credentials available to your terminal. Please configure AWS credentials and try again.\x1b[0m`, + ); + } else { + console.error( + "Error occurred while checking authentication:", + error.message, + ); + } + } else { + console.error("An unknown error occurred:", error); + } + process.exit(1); + } +} diff --git a/bin/cli/src/run.ts b/bin/cli/src/run.ts index 4d4d461a12..bbc6e96751 100644 --- a/bin/cli/src/run.ts +++ b/bin/cli/src/run.ts @@ -14,6 +14,11 @@ import { } from "./commands"; yargs + .fail((msg, err, _) => { + if (err) throw err; + if (msg) console.error(msg); + process.exit(1); + }) .command(deploy) .command(destroy) .command(docs) diff --git a/run b/run index c60d0e88dd..b49de1d4a8 100755 --- a/run +++ b/run @@ -33,4 +33,4 @@ fi bun install # build and run dev.ts -bun build:cli && node ./.build_run/src/run.js "$@" +bun build:cli > /dev/null && node ./.build_run/src/run.js "$@"