From 980e56aa34c77b713aad424d10ae93ac73df6487 Mon Sep 17 00:00:00 2001 From: Kyle Morel Date: Tue, 26 Nov 2024 14:15:40 -0800 Subject: [PATCH] Move to a generic draft table Previously had individual/specific draft tables --- app/src/controllers/submission.ts | 44 ++++----- .../20241125000000_015-draft-tables.ts | 55 ++++++++++-- app/src/db/models/draft.ts | 22 +++++ app/src/db/models/index.ts | 2 +- app/src/db/models/submission_draft.ts | 20 ----- app/src/db/prisma/schema.prisma | 41 ++++++--- app/src/middleware/authorization.ts | 6 +- app/src/routes/v1/submission.ts | 16 ++-- app/src/services/draft.ts | 90 +++++++++++++++++++ app/src/services/index.ts | 2 +- app/src/services/submissionDraft.ts | 88 ------------------ app/src/types/Draft.ts | 9 ++ app/src/types/SubmissionDraft.ts | 8 -- app/src/types/SubmissionIntake.ts | 2 +- app/src/types/index.ts | 2 +- app/src/utils/enums/housing.ts | 4 + app/src/validators/submission.ts | 14 +-- app/tests/unit/controllers/submission.spec.ts | 24 ++--- .../SubmissionDraftListProponent.vue | 12 +-- .../submission/SubmissionIntakeForm.vue | 30 +++---- .../submission/SubmissionsProponent.vue | 6 +- frontend/src/interfaces/index.ts | 2 +- frontend/src/services/submissionService.ts | 20 ++--- frontend/src/types/Draft.ts | 8 ++ frontend/src/types/SubmissionDraft.ts | 7 -- frontend/src/types/index.ts | 2 +- 26 files changed, 295 insertions(+), 241 deletions(-) create mode 100644 app/src/db/models/draft.ts delete mode 100644 app/src/db/models/submission_draft.ts create mode 100644 app/src/services/draft.ts delete mode 100644 app/src/services/submissionDraft.ts create mode 100644 app/src/types/Draft.ts delete mode 100644 app/src/types/SubmissionDraft.ts create mode 100644 frontend/src/types/Draft.ts delete mode 100644 frontend/src/types/SubmissionDraft.ts diff --git a/app/src/controllers/submission.ts b/app/src/controllers/submission.ts index 013c89af..f9eb5812 100644 --- a/app/src/controllers/submission.ts +++ b/app/src/controllers/submission.ts @@ -5,15 +5,16 @@ import { generateCreateStamps, generateUpdateStamps } from '../db/utils/utils'; import { activityService, contactService, + draftService, emailService, enquiryService, submissionService, - submissionDraftService, permitService } from '../services'; import { BasicResponse, Initiative } from '../utils/enums/application'; import { ApplicationStatus, + DraftCode, IntakeStatus, NumResidentialUnits, PermitNeeded, @@ -27,15 +28,15 @@ import type { NextFunction, Request, Response } from 'express'; import type { ChefsFormConfig, ChefsFormConfigData, - Submission, ChefsSubmissionExport, - Permit, + CurrentContext, + Draft, Email, + Permit, StatisticsFilters, + Submission, SubmissionIntake, - SubmissionSearchParameters, - CurrentContext, - SubmissionDraft + SubmissionSearchParameters } from '../types'; const controller = { @@ -412,9 +413,9 @@ const controller = { } }, - deleteDraft: async (req: Request<{ submissionDraftId: string }>, res: Response, next: NextFunction) => { + deleteDraft: async (req: Request<{ draftId: string }>, res: Response, next: NextFunction) => { try { - const response = await submissionDraftService.deleteDraft(req.params.submissionDraftId); + const response = await draftService.deleteDraft(req.params.draftId); if (!response) { return res.status(404).json({ message: 'Submission draft not found' }); @@ -426,9 +427,9 @@ const controller = { } }, - getDraft: async (req: Request<{ submissionDraftId: string }>, res: Response, next: NextFunction) => { + getDraft: async (req: Request<{ draftId: string }>, res: Response, next: NextFunction) => { try { - const response = await submissionDraftService.getDraft(req.params.submissionDraftId); + const response = await draftService.getDraft(req.params.draftId); if (req.currentAuthorization?.attributes.includes('scope:self')) { if (response?.createdBy !== getCurrentUsername(req.currentContext)) { @@ -444,10 +445,10 @@ const controller = { getDrafts: async (req: Request, res: Response, next: NextFunction) => { try { - let response = await submissionDraftService.getDrafts(); + let response = await draftService.getDrafts(DraftCode.SUBMISSION); if (req.currentAuthorization?.attributes.includes('scope:self')) { - response = response.filter((x: SubmissionDraft) => x?.createdBy === req.currentContext.userId); + response = response.filter((x: Draft) => x?.createdBy === req.currentContext.userId); } res.status(200).json(response); @@ -552,7 +553,7 @@ const controller = { await Promise.all(investigatePermits.map((x: Permit) => permitService.createPermit(x))); // Delete old draft - if (req.body.submissionDraftId) await submissionDraftService.deleteDraft(req.body.submissionDraftId); + if (req.body.draftId) await draftService.deleteDraft(req.body.draftId); res.status(201).json({ activityId: result.activityId, submissionId: result.submissionId }); } catch (e: unknown) { @@ -560,15 +561,15 @@ const controller = { } }, - updateDraft: async (req: Request, res: Response, next: NextFunction) => { + updateDraft: async (req: Request, res: Response, next: NextFunction) => { try { - const update = req.body.submissionDraftId && req.body.activityId; + const update = req.body.draftId && req.body.activityId; let response; if (update) { // Update draft - response = await submissionDraftService.updateDraft({ + response = await draftService.updateDraft({ ...req.body, ...generateUpdateStamps(req.currentContext) }); @@ -578,17 +579,16 @@ const controller = { )?.activityId; // Create new draft - response = await submissionDraftService.createDraft({ - ...req.body, - submissionDraftId: uuidv4(), + response = await draftService.createDraft({ + draftId: uuidv4(), activityId: activityId, + draftCode: DraftCode.SUBMISSION, + data: req.body.data, ...generateCreateStamps(req.currentContext) }); } - res - .status(update ? 200 : 201) - .json({ submissionDraftId: response?.submissionDraftId, activityId: response?.activityId }); + res.status(update ? 200 : 201).json({ draftId: response?.draftId, activityId: response?.activityId }); } catch (e: unknown) { next(e); } diff --git a/app/src/db/migrations/20241125000000_015-draft-tables.ts b/app/src/db/migrations/20241125000000_015-draft-tables.ts index 03631019..6ac29806 100644 --- a/app/src/db/migrations/20241125000000_015-draft-tables.ts +++ b/app/src/db/migrations/20241125000000_015-draft-tables.ts @@ -7,8 +7,13 @@ export async function up(knex: Knex): Promise { return Promise.resolve().then(() => // Create public schema tables knex.schema - .createTable('submission_draft', (table) => { - table.uuid('submission_draft_id').primary(); + .createTable('draft_code', (table) => { + table.text('draft_code').primary(); + stamps(knex, table); + }) + + .createTable('draft', (table) => { + table.uuid('draft_id').primary(); table .text('activity_id') .notNullable() @@ -16,23 +21,52 @@ export async function up(knex: Knex): Promise { .inTable('activity') .onUpdate('CASCADE') .onDelete('CASCADE'); + table + .text('draft_code') + .notNullable() + .references('draft_code') + .inTable('draft_code') + .onUpdate('CASCADE') + .onDelete('CASCADE'); table.json('data').notNullable(); stamps(knex, table); }) // Create before update triggers .then(() => - knex.schema.raw(`CREATE TRIGGER before_update_submission_draft_trigger - BEFORE UPDATE ON submission_draft + knex.schema.raw(`CREATE TRIGGER before_update_draft_code_trigger + BEFORE UPDATE ON draft_code + FOR EACH ROW EXECUTE PROCEDURE public.set_updated_at();`) + ) + + .then(() => + knex.schema.raw(`CREATE TRIGGER before_update_draft_trigger + BEFORE UPDATE ON draft FOR EACH ROW EXECUTE PROCEDURE public.set_updated_at();`) ) // Create audit triggers .then(() => - knex.schema.raw(`CREATE TRIGGER audit_submission_draft_trigger - AFTER UPDATE OR DELETE ON submission_draft + knex.schema.raw(`CREATE TRIGGER audit_draft_code_trigger + AFTER UPDATE OR DELETE ON draft_code + FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func();`) + ) + + .then(() => + knex.schema.raw(`CREATE TRIGGER audit_draft_trigger + AFTER UPDATE OR DELETE ON draft FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func();`) ) + + // Populate Baseline Data + .then(() => { + const items = [ + { + draft_code: 'SUBMISSION' + } + ]; + return knex('draft_code').insert(items); + }) ); } @@ -40,12 +74,15 @@ export async function down(knex: Knex): Promise { return ( Promise.resolve() // Drop audit triggers - .then(() => knex.schema.raw('DROP TRIGGER IF EXISTS audit_submission_draft_trigger ON submission_draft')) + .then(() => knex.schema.raw('DROP TRIGGER IF EXISTS audit_draft_trigger ON draft')) + .then(() => knex.schema.raw('DROP TRIGGER IF EXISTS audit_draft_code_trigger ON draft_code')) // Drop public schema table triggers - .then(() => knex.schema.raw('DROP TRIGGER IF EXISTS before_update_submission_draft_trigger ON submission_draft')) + .then(() => knex.schema.raw('DROP TRIGGER IF EXISTS before_update_draft_trigger ON draft')) + .then(() => knex.schema.raw('DROP TRIGGER IF EXISTS before_update_draft_code_trigger ON draft_code')) // Drop public schema tables - .then(() => knex.schema.dropTableIfExists('submission_draft')) + .then(() => knex.schema.dropTableIfExists('draft')) + .then(() => knex.schema.dropTableIfExists('draft_code')) ); } diff --git a/app/src/db/models/draft.ts b/app/src/db/models/draft.ts new file mode 100644 index 00000000..9c50ebcb --- /dev/null +++ b/app/src/db/models/draft.ts @@ -0,0 +1,22 @@ +import { Prisma } from '@prisma/client'; + +import type { Draft } from '../../types'; + +// Define types +const _draft = Prisma.validator()({}); + +type PrismaGraphDraft = Prisma.draftGetPayload; + +export default { + fromPrismaModel(input: PrismaGraphDraft): Draft { + return { + draftId: input.draft_id, + activityId: input.activity_id, + draftCode: input.draft_code, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: input.data as any, + createdBy: input.created_by, + updatedAt: input.updated_at?.toISOString() ?? null + }; + } +}; diff --git a/app/src/db/models/index.ts b/app/src/db/models/index.ts index fd3a78e8..b3515604 100644 --- a/app/src/db/models/index.ts +++ b/app/src/db/models/index.ts @@ -2,6 +2,7 @@ export { default as activity } from './activity'; export { default as access_request } from './access_request'; export { default as contact } from './contact'; export { default as document } from './document'; +export { default as draft } from './draft'; export { default as enquiry } from './enquiry'; export { default as identity_provider } from './identity_provider'; export { default as note } from './note'; @@ -9,5 +10,4 @@ export { default as permit } from './permit'; export { default as permit_note } from './permit_note'; export { default as permit_type } from './permit_type'; export { default as submission } from './submission'; -export { default as submission_draft } from './submission_draft'; export { default as user } from './user'; diff --git a/app/src/db/models/submission_draft.ts b/app/src/db/models/submission_draft.ts deleted file mode 100644 index 9831a3b0..00000000 --- a/app/src/db/models/submission_draft.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Prisma } from '@prisma/client'; - -import type { SubmissionDraft, SubmissionIntake } from '../../types'; - -// Define types -const _submissionDraft = Prisma.validator()({}); - -type PrismaGraphSubmissionDraft = Prisma.submission_draftGetPayload; - -export default { - fromPrismaModel(input: PrismaGraphSubmissionDraft): SubmissionDraft { - return { - submissionDraftId: input.submission_draft_id, - activityId: input.activity_id, - data: input.data as Partial, - createdBy: input.created_by, - updatedAt: input.updated_at?.toISOString() ?? null - }; - } -}; diff --git a/app/src/db/prisma/schema.prisma b/app/src/db/prisma/schema.prisma index caa484da..3f7a8d88 100644 --- a/app/src/db/prisma/schema.prisma +++ b/app/src/db/prisma/schema.prisma @@ -35,11 +35,11 @@ model activity { initiative initiative @relation(fields: [initiative_id], references: [initiative_id], onDelete: Cascade, map: "activity_initiative_id_foreign") activity_contact activity_contact[] document document[] + draft draft[] enquiry enquiry[] note note[] permit permit[] submission submission[] - submission_draft submission_draft[] @@schema("public") } @@ -299,19 +299,6 @@ model submission { @@schema("public") } -model submission_draft { - submission_draft_id String @id @db.Uuid - activity_id String - data Json @db.Json - created_by String? @default("00000000-0000-0000-0000-000000000000") - created_at DateTime? @default(now()) @db.Timestamptz(6) - updated_by String? - updated_at DateTime? @db.Timestamptz(6) - activity activity @relation(fields: [activity_id], references: [activity_id], onDelete: Cascade, map: "submission_draft_activity_id_foreign") - - @@schema("public") -} - model user { user_id String @id @db.Uuid identity_id String? @db.Uuid @@ -496,6 +483,32 @@ model subject_group { @@schema("yars") } +model draft { + draft_id String @id @db.Uuid + activity_id String + draft_code String + data Json @db.Json + created_by String? @default("00000000-0000-0000-0000-000000000000") + created_at DateTime? @default(now()) @db.Timestamptz(6) + updated_by String? + updated_at DateTime? @db.Timestamptz(6) + activity activity @relation(fields: [activity_id], references: [activity_id], onDelete: Cascade, map: "draft_activity_id_foreign") + draft_code_draft_draft_codeTodraft_code draft_code @relation("draft_draft_codeTodraft_code", fields: [draft_code], references: [draft_code], onDelete: Cascade, map: "draft_draft_code_foreign") + + @@schema("public") +} + +model draft_code { + draft_code String @id + created_by String? @default("00000000-0000-0000-0000-000000000000") + created_at DateTime? @default(now()) @db.Timestamptz(6) + updated_by String? + updated_at DateTime? @db.Timestamptz(6) + draft_draft_draft_codeTodraft_code draft[] @relation("draft_draft_codeTodraft_code") + + @@schema("public") +} + view group_role_policy_vw { row_number BigInt @unique group_id Int? diff --git a/app/src/middleware/authorization.ts b/app/src/middleware/authorization.ts index 936d36a9..1a2becc1 100644 --- a/app/src/middleware/authorization.ts +++ b/app/src/middleware/authorization.ts @@ -4,11 +4,11 @@ import { NIL } from 'uuid'; import { documentService, + draftService, enquiryService, noteService, permitService, submissionService, - submissionDraftService, userService, yarsService } from '../services'; @@ -109,11 +109,11 @@ export const hasAuthorization = (resource: string, action: string) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const paramMap = new Map any>([ ['documentId', documentService.getDocument], + ['draftId', draftService.getDraft], ['enquiryId', enquiryService.getEnquiry], ['noteId', noteService.getNote], ['permitId', permitService.getPermit], - ['submissionId', submissionService.getSubmission], - ['submissionDraftId', submissionDraftService.getDraft] + ['submissionId', submissionService.getSubmission] ]); /** diff --git a/app/src/routes/v1/submission.ts b/app/src/routes/v1/submission.ts index 810a5fca..3a3ab946 100644 --- a/app/src/routes/v1/submission.ts +++ b/app/src/routes/v1/submission.ts @@ -9,10 +9,10 @@ import { submissionValidator } from '../../validators'; import type { NextFunction, Request, Response } from 'express'; import type { + Draft, Email, StatisticsFilters, Submission, - SubmissionDraft, SubmissionIntake, SubmissionSearchParameters } from '../../types'; @@ -61,9 +61,9 @@ router.get( /** Gets a list of submission drafts */ router.get( - '/draft/:submissionDraftId', + '/draft/:draftId', hasAuthorization(Resource.SUBMISSION, Action.READ), - (req: Request<{ submissionDraftId: string }>, res: Response, next: NextFunction): void => { + (req: Request<{ draftId: string }>, res: Response, next: NextFunction): void => { submissionController.getDraft(req, res, next); } ); @@ -81,7 +81,7 @@ router.get( router.put( '/draft', hasAuthorization(Resource.SUBMISSION, Action.CREATE), - (req: Request, res: Response, next: NextFunction): void => { + (req: Request, res: Response, next: NextFunction): void => { submissionController.updateDraft(req, res, next); } ); @@ -129,11 +129,11 @@ router.delete( /** Hard deletes a submission draft */ router.delete( - '/draft/:submissionDraftId', + '/draft/:draftId', hasAuthorization(Resource.SUBMISSION, Action.DELETE), - hasAccess('submissionDraftId'), - submissionValidator.deleteSubmissionDraft, - (req: Request<{ submissionDraftId: string }>, res: Response, next: NextFunction): void => { + hasAccess('draftId'), + submissionValidator.deleteDraft, + (req: Request<{ draftId: string }>, res: Response, next: NextFunction): void => { submissionController.deleteDraft(req, res, next); } ); diff --git a/app/src/services/draft.ts b/app/src/services/draft.ts new file mode 100644 index 00000000..ba1d4f4f --- /dev/null +++ b/app/src/services/draft.ts @@ -0,0 +1,90 @@ +import prisma from '../db/dataConnection'; +import { draft } from '../db/models'; + +import type { Draft } from '../types'; +import { DraftCode } from '../utils/enums/housing'; + +const service = { + /** + * @function createDraft + * Create a draft + * @param {Draft} data Draft data + * @returns {Promise} The result of running the create operation + */ + createDraft: async (data: Draft) => { + const result = await prisma.draft.create({ + data: { + draft_id: data.draftId, + activity_id: data.activityId, + draft_code: data.draftCode, + data: data.data, + created_at: data.createdAt, + created_by: data.createdBy + } + }); + + return draft.fromPrismaModel(result); + }, + + /** + * @function deleteDraft + * Deletes the draft + * @param {string} draftId Draft ID + * @returns {Promise} The result of running the delete operation + */ + deleteDraft: async (draftId: string) => { + const result = await prisma.draft.delete({ + where: { + draft_id: draftId + } + }); + + return draft.fromPrismaModel(result); + }, + + /** + * @function getDraft + * Gets a specific draft from the PCNS database + * @param {string} draftId Draft ID + * @returns {Promise | null>} The result of running the findFirst operation + */ + getDraft: async (draftId: string) => { + const result = await prisma.draft.findFirst({ + where: { + draft_id: draftId + } + }); + + return result ? draft.fromPrismaModel(result) : null; + }, + + /** + * @function getDrafts + * Gets a list of drafts + * @returns {Promise[]>} The result of running the findMany operation + */ + getDrafts: async (draftCode?: DraftCode) => { + const result = await prisma.draft.findMany({ where: { draft_code: draftCode } }); + + return result.map((x) => draft.fromPrismaModel(x)); + }, + + /** + * @function updateDraft + * Updates a specific draft + * @param {Draft} data Draft data + * @returns {Promise} The result of running the update operation + */ + updateDraft: async (data: Draft) => { + const result = await prisma.draft.update({ + data: { data: data.data, updated_at: data?.updatedAt, updated_by: data?.updatedBy }, + where: { + draft_id: data.draftId + } + }); + + return draft.fromPrismaModel(result); + } +}; + +export default service; diff --git a/app/src/services/index.ts b/app/src/services/index.ts index d800777c..23621712 100644 --- a/app/src/services/index.ts +++ b/app/src/services/index.ts @@ -4,6 +4,7 @@ export { default as atsService } from './ats'; export { default as comsService } from './coms'; export { default as contactService } from './contact'; export { default as documentService } from './document'; +export { default as draftService } from './draft'; export { default as emailService } from './email'; export { default as enquiryService } from './enquiry'; export { default as initiativeService } from './initiative'; @@ -12,6 +13,5 @@ export { default as permitService } from './permit'; export { default as permitNoteService } from './permitNote'; export { default as ssoService } from './sso'; export { default as submissionService } from './submission'; -export { default as submissionDraftService } from './submissionDraft'; export { default as userService } from './user'; export { default as yarsService } from './yars'; diff --git a/app/src/services/submissionDraft.ts b/app/src/services/submissionDraft.ts deleted file mode 100644 index 023d731d..00000000 --- a/app/src/services/submissionDraft.ts +++ /dev/null @@ -1,88 +0,0 @@ -import prisma from '../db/dataConnection'; -import { submission_draft } from '../db/models'; - -import type { SubmissionDraft } from '../types'; - -const service = { - /** - * @function createDraft - * Create a submission draft - * @param {SubmissionDraft} data Submission draft data - * @returns {Promise} The result of running the create operation - */ - createDraft: async (data: SubmissionDraft) => { - const result = await prisma.submission_draft.create({ - data: { - submission_draft_id: data.submissionDraftId, - activity_id: data.activityId, - data: data.data, - created_at: data.createdAt, - created_by: data.createdBy - } - }); - - return submission_draft.fromPrismaModel(result); - }, - - /** - * @function deleteDraft - * Deletes the submission draft - * @param {string} submissionDraftId Submission ID - * @returns {Promise} The result of running the delete operation - */ - deleteDraft: async (submissionDraftId: string) => { - const result = await prisma.submission_draft.delete({ - where: { - submission_draft_id: submissionDraftId - } - }); - - return submission_draft.fromPrismaModel(result); - }, - - /** - * @function getDraft - * Gets a specific submission draft from the PCNS database - * @param {string} submissionDraftId Submission draft ID - * @returns {Promise | null>} The result of running the findFirst operation - */ - getDraft: async (submissionDraftId: string) => { - const result = await prisma.submission_draft.findFirst({ - where: { - submission_draft_id: submissionDraftId - } - }); - - return result ? submission_draft.fromPrismaModel(result) : null; - }, - - /** - * @function getDrafts - * Gets a list of submission drafts - * @returns {Promise[]>} The result of running the findMany operation - */ - getDrafts: async () => { - const result = await prisma.submission_draft.findMany(); - - return result.map((x) => submission_draft.fromPrismaModel(x)); - }, - - /** - * @function updateDraft - * Updates a specific submission draft - * @param {SubmissionDraft} data Submission intake draft data - * @returns {Promise} The result of running the update operation - */ - updateDraft: async (data: SubmissionDraft) => { - const result = await prisma.submission_draft.update({ - data: { data: data.data, updated_at: data?.updatedAt, updated_by: data?.updatedBy }, - where: { - submission_draft_id: data.submissionDraftId - } - }); - - return submission_draft.fromPrismaModel(result); - } -}; - -export default service; diff --git a/app/src/types/Draft.ts b/app/src/types/Draft.ts new file mode 100644 index 00000000..5d309294 --- /dev/null +++ b/app/src/types/Draft.ts @@ -0,0 +1,9 @@ +import { IStamps } from '../interfaces/IStamps'; + +export type Draft = { + draftId: string; // Primary key + activityId: string; + draftCode: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: any; +} & Partial; diff --git a/app/src/types/SubmissionDraft.ts b/app/src/types/SubmissionDraft.ts deleted file mode 100644 index 4c858e3c..00000000 --- a/app/src/types/SubmissionDraft.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { IStamps } from '../interfaces/IStamps'; -import { SubmissionIntake } from './SubmissionIntake'; - -export type SubmissionDraft = { - submissionDraftId: string; // Primary key - activityId: string; - data: Partial; -} & Partial; diff --git a/app/src/types/SubmissionIntake.ts b/app/src/types/SubmissionIntake.ts index ff2a5892..75d3d6c6 100644 --- a/app/src/types/SubmissionIntake.ts +++ b/app/src/types/SubmissionIntake.ts @@ -4,7 +4,7 @@ import { ApplicationStatus, SubmissionType } from '../utils/enums/housing'; export type SubmissionIntake = { activityId?: string; - submissionDraftId?: string; + draftId?: string; submittedAt?: string; applicationStatus?: ApplicationStatus; submissionType?: SubmissionType; diff --git a/app/src/types/index.ts b/app/src/types/index.ts index 623a5c42..a4a9914f 100644 --- a/app/src/types/index.ts +++ b/app/src/types/index.ts @@ -10,6 +10,7 @@ export type { Contact } from './Contact'; export type { CurrentAuthorization } from './CurrentAuthorization'; export type { CurrentContext } from './CurrentContext'; export type { Document } from './Document'; +export type { Draft } from './Draft'; export type { Email } from './Email'; export type { Enquiry } from './Enquiry'; export type { EnquiryIntake } from './EnquiryIntake'; @@ -27,7 +28,6 @@ export type { PermitType } from './PermitType'; export type { StatisticsFilters } from './StatisticsFilters'; export type { Submission } from './Submission'; export type { SubmissionIntake } from './SubmissionIntake'; -export type { SubmissionDraft } from './SubmissionDraft'; export type { SubmissionSearchParameters } from './SubmissionSearchParameters'; export type { User } from './User'; export type { UserAccessRequest } from './UserAccessRequest'; diff --git a/app/src/utils/enums/housing.ts b/app/src/utils/enums/housing.ts index cc64acb8..3677fa1c 100644 --- a/app/src/utils/enums/housing.ts +++ b/app/src/utils/enums/housing.ts @@ -20,6 +20,10 @@ export enum ContactPreference { EITHER = 'Either' } +export enum DraftCode { + SUBMISSION = 'SUBMISSION' +} + export enum IntakeFormCategory { APPLICANT = 'applicant', BASIC = 'basic', diff --git a/app/src/validators/submission.ts b/app/src/validators/submission.ts index 0e36ab9c..a73d9fd2 100644 --- a/app/src/validators/submission.ts +++ b/app/src/validators/submission.ts @@ -19,14 +19,9 @@ import { BasicResponse } from '../utils/enums/application'; import { IntakeStatus } from '../utils/enums/housing'; const schema = { - createDraft: { - body: Joi.object({ - contact: contacts - }) - }, createSubmission: { body: Joi.object({ - submissionDraftId: uuidv4.allow(null), + draftId: uuidv4.allow(null), activityId: Joi.string().min(8).max(8).allow(null), contacts: contacts, appliedPermits: Joi.array().items(appliedPermit).allow(null), @@ -55,9 +50,9 @@ const schema = { submissionId: uuidv4.required() }) }, - deleteSubmissionDraft: { + deleteDraft: { params: Joi.object({ - submissionDraftId: uuidv4.required() + draftId: uuidv4.required() }) }, getStatistics: { @@ -196,11 +191,10 @@ const schema = { }; export default { - createDraft: validate(schema.createDraft), createSubmission: validate(schema.createSubmission), emailConfirmation: validate(schema.emailConfirmation), deleteSubmission: validate(schema.deleteSubmission), - deleteSubmissionDraft: validate(schema.deleteSubmissionDraft), + deleteDraft: validate(schema.deleteDraft), getStatistics: validate(schema.getStatistics), getSubmission: validate(schema.getSubmission), searchSubmissions: validate(schema.searchSubmissions), diff --git a/app/tests/unit/controllers/submission.spec.ts b/app/tests/unit/controllers/submission.spec.ts index b46600b1..4f82f30f 100644 --- a/app/tests/unit/controllers/submission.spec.ts +++ b/app/tests/unit/controllers/submission.spec.ts @@ -6,10 +6,10 @@ import { contactService, enquiryService, permitService, - submissionDraftService, + draftService, submissionService } from '../../../src/services'; -import type { Permit, Submission, SubmissionDraft } from '../../../src/types'; +import type { Permit, Submission, Draft } from '../../../src/types'; import { ApplicationStatus, IntakeStatus, PermitNeeded, PermitStatus } from '../../../src/utils/enums/housing'; import { AuthType, BasicResponse, Initiative } from '../../../src/utils/enums/application'; @@ -876,8 +876,8 @@ describe('submitDraft', () => { describe('updateDraft', () => { // Mock service calls - const createDraftSpy = jest.spyOn(submissionDraftService, 'createDraft'); - const updateDraftSpy = jest.spyOn(submissionDraftService, 'updateDraft'); + const createDraftSpy = jest.spyOn(draftService, 'createDraft'); + const updateDraftSpy = jest.spyOn(draftService, 'updateDraft'); const createActivitySpy = jest.spyOn(activityService, 'createActivity'); it('creates a new draft', async () => { @@ -903,7 +903,7 @@ describe('updateDraft', () => { const next = jest.fn(); createActivitySpy.mockResolvedValue({ activityId: '00000000', initiativeId: Initiative.HOUSING, isDeleted: false }); - createDraftSpy.mockResolvedValue({ submissionDraftId: '11111111', activityId: '00000000' } as SubmissionDraft); + createDraftSpy.mockResolvedValue({ draftId: '11111111', activityId: '00000000' } as Draft); // eslint-disable-next-line @typescript-eslint/no-explicit-any await submissionController.updateDraft(req as any, res as any, next); @@ -912,18 +912,18 @@ describe('updateDraft', () => { expect(createDraftSpy).toHaveBeenCalledTimes(1); expect(createDraftSpy).toHaveBeenCalledWith( expect.objectContaining({ - submissionDraftId: expect.stringMatching(uuidv4Pattern), + draftId: expect.stringMatching(uuidv4Pattern), activityId: '00000000' }) ); expect(res.status).toHaveBeenCalledWith(201); - expect(res.json).toHaveBeenCalledWith({ submissionDraftId: '11111111', activityId: '00000000' }); + expect(res.json).toHaveBeenCalledWith({ draftId: '11111111', activityId: '00000000' }); }); - it('updates draft with the given submissionDraftId and activityId', async () => { + it('updates draft with the given draftId and activityId', async () => { const req = { body: { - submissionDraftId: '11111111', + draftId: '11111111', activityId: '00000000', contactFirstName: 'test', contactLastName: 'person', @@ -945,7 +945,7 @@ describe('updateDraft', () => { const next = jest.fn(); createActivitySpy.mockResolvedValue({ activityId: '00000000', initiativeId: Initiative.HOUSING, isDeleted: false }); - updateDraftSpy.mockResolvedValue({ submissionDraftId: '11111111', activityId: '00000000' } as SubmissionDraft); + updateDraftSpy.mockResolvedValue({ draftId: '11111111', activityId: '00000000' } as Draft); // eslint-disable-next-line @typescript-eslint/no-explicit-any await submissionController.updateDraft(req as any, res as any, next); @@ -954,11 +954,11 @@ describe('updateDraft', () => { expect(updateDraftSpy).toHaveBeenCalledTimes(1); expect(updateDraftSpy).toHaveBeenCalledWith( expect.objectContaining({ - submissionDraftId: '11111111' + draftId: '11111111' }) ); expect(res.status).toHaveBeenCalledWith(200); - expect(res.json).toHaveBeenCalledWith({ submissionDraftId: '11111111', activityId: '00000000' }); + expect(res.json).toHaveBeenCalledWith({ draftId: '11111111', activityId: '00000000' }); }); }); diff --git a/frontend/src/components/housing/submission/SubmissionDraftListProponent.vue b/frontend/src/components/housing/submission/SubmissionDraftListProponent.vue index b7ccfe36..b26ba75c 100644 --- a/frontend/src/components/housing/submission/SubmissionDraftListProponent.vue +++ b/frontend/src/components/housing/submission/SubmissionDraftListProponent.vue @@ -27,7 +27,7 @@ const selection: Ref = ref(undefined); const confirm = useConfirm(); const toast = useToast(); -function onDelete(submissionDraftId: string) { +function onDelete(draftId: string) { confirm.require({ message: 'Please confirm that you want to delete this draft', header: 'Delete draft?', @@ -36,9 +36,9 @@ function onDelete(submissionDraftId: string) { rejectLabel: 'Cancel', accept: () => { submissionService - .deleteSubmissionDraft(submissionDraftId) + .deleteDraft(draftId) .then(() => { - emit('submissionDraft:delete', submissionDraftId); + emit('submissionDraft:delete', draftId); toast.success('Draft deleted'); }) .catch((e: any) => toast.error('Failed to delete draft', e.message)); @@ -79,11 +79,11 @@ function onDelete(submissionDraftId: string) { frozen >