@gov-cy/govcy-express-services 1.3.0-alpha.1 → 1.3.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +250 -371
- package/package.json +2 -2
- package/src/index.mjs +11 -1
- package/src/middleware/govcyFileDeleteHandler.mjs +8 -0
- package/src/middleware/govcyFileViewHandler.mjs +5 -0
- package/src/middleware/govcyMultipleThingsDeleteHandler.mjs +2 -2
- package/src/middleware/govcyMultipleThingsHubHandler.mjs +0 -1
- package/src/middleware/govcyPageHandler.mjs +11 -4
- package/src/middleware/govcyReviewPostHandler.mjs +24 -3
- package/src/middleware/govcyUpdateMyDetails.mjs +744 -0
- package/src/public/css/govcyExpress.css +4 -0
- package/src/resources/govcyResources.mjs +471 -95
- package/src/utils/govcyConstants.mjs +13 -1
- package/src/utils/govcyHandleFiles.mjs +10 -0
- package/src/utils/govcySubmitData.mjs +45 -6
- package/src/utils/govcyValidator.mjs +104 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gov-cy/govcy-express-services",
|
|
3
|
-
"version": "1.3.0-alpha.
|
|
3
|
+
"version": "1.3.0-alpha.3",
|
|
4
4
|
"description": "An Express-based system that dynamically renders services using @gov-cy/govcy-frontend-renderer and posts data to a submission API.",
|
|
5
5
|
"author": "DMRID - DSF Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"coverage:badge": "coverage-badges --output ./coverage-badges.svg && npm run coverage:copy"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@gov-cy/dsf-email-templates": "^2.1.
|
|
54
|
+
"@gov-cy/dsf-email-templates": "^2.1.1",
|
|
55
55
|
"@gov-cy/govcy-frontend-renderer": "^1.26.0",
|
|
56
56
|
"axios": "^1.9.0",
|
|
57
57
|
"cookie-parser": "^1.4.7",
|
package/src/index.mjs
CHANGED
|
@@ -29,6 +29,7 @@ import { govcyFileDeletePageHandler, govcyFileDeletePostHandler } from './middle
|
|
|
29
29
|
import { govcyFileViewHandler } from './middleware/govcyFileViewHandler.mjs';
|
|
30
30
|
import { govcyMultipleThingsAddHandler, govcyMultipleThingsEditHandler, govcyMultipleThingsAddPostHandler, govcyMultipleThingsEditPostHandler } from './middleware/govcyMultipleThingsItemPage.mjs';
|
|
31
31
|
import { govcyMultipleThingsDeletePageHandler, govcyMultipleThingsDeletePostHandler } from './middleware/govcyMultipleThingsDeleteHandler.mjs';
|
|
32
|
+
import { govcyUpdateMyDetailsPostHandler } from './middleware/govcyUpdateMyDetails.mjs';
|
|
32
33
|
import { isProdOrStaging, getEnvVariable, whatsIsMyEnvironment } from './utils/govcyEnvVariables.mjs';
|
|
33
34
|
import { logger } from "./utils/govcyLogger.mjs";
|
|
34
35
|
|
|
@@ -230,7 +231,6 @@ export default function initializeGovCyExpressService() {
|
|
|
230
231
|
// ✅ -- ROUTE: Add Success Page Route (BEFORE the dynamic route)
|
|
231
232
|
app.get('/:siteId/success', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcySuccessPageHandler(), renderGovcyPage());
|
|
232
233
|
|
|
233
|
-
|
|
234
234
|
// 👀🗃️ -- ROUTE: View file (BEFORE the dynamic route)
|
|
235
235
|
app.get('/:siteId/:pageUrl/view-file/:elementName', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(), govcyLoadSubmissionData(), govcyFileViewHandler());
|
|
236
236
|
|
|
@@ -298,6 +298,16 @@ export default function initializeGovCyExpressService() {
|
|
|
298
298
|
govcyMultipleThingsDeletePostHandler()
|
|
299
299
|
);
|
|
300
300
|
|
|
301
|
+
// ----- `updateMyDetails` handling
|
|
302
|
+
|
|
303
|
+
// 🔀➡️ -- ROUTE coming from incoming update my details /:siteId/:pageUrl/update-my-details-response
|
|
304
|
+
app.post('/:siteId/:pageUrl/update-my-details-response',
|
|
305
|
+
serviceConfigDataMiddleware,
|
|
306
|
+
requireAuth,
|
|
307
|
+
naturalPersonPolicy,
|
|
308
|
+
govcyServiceEligibilityHandler(true),
|
|
309
|
+
govcyUpdateMyDetailsPostHandler());
|
|
310
|
+
// ----- `updateMyDetails` handling
|
|
301
311
|
|
|
302
312
|
// 📝 -- ROUTE: Dynamic route to render pages based on siteId and pageUrl, using govcyPageHandler middleware
|
|
303
313
|
app.get('/:siteId/:pageUrl', serviceConfigDataMiddleware, requireAuth, naturalPersonPolicy, govcyServiceEligibilityHandler(true), govcyLoadSubmissionData(), govcyPageHandler(), renderGovcyPage());
|
|
@@ -132,6 +132,10 @@ export function govcyFileDeletePageHandler() {
|
|
|
132
132
|
} else {
|
|
133
133
|
// normal page
|
|
134
134
|
actionPath = `${pageUrl}/delete-file/${elementName}`;
|
|
135
|
+
// if normal page but has multipleThings, block it
|
|
136
|
+
if (page?.multipleThings) {
|
|
137
|
+
return handleMiddlewareError(`Single mode delete file not allowed on multipleThings pages`, 404, next)
|
|
138
|
+
}
|
|
135
139
|
}
|
|
136
140
|
// Construct submit button
|
|
137
141
|
const formElement = {
|
|
@@ -243,6 +247,10 @@ export function govcyFileDeletePostHandler() {
|
|
|
243
247
|
} else {
|
|
244
248
|
// normal page
|
|
245
249
|
actionPath = `${pageUrl}`;
|
|
250
|
+
// if normal page but has multipleThings, block it
|
|
251
|
+
if (page?.multipleThings) {
|
|
252
|
+
return handleMiddlewareError(`Single mode delete file not allowed on multipleThings pages`, 404, next)
|
|
253
|
+
}
|
|
246
254
|
}
|
|
247
255
|
|
|
248
256
|
// the page base return url
|
|
@@ -62,6 +62,11 @@ export function govcyFileViewHandler() {
|
|
|
62
62
|
// return handleMiddlewareError(`Page condition evaluated to true on POST — skipping form save and redirecting`, 404, next);
|
|
63
63
|
// }
|
|
64
64
|
|
|
65
|
+
|
|
66
|
+
// If mode is `single` make sure it has no multipleThings
|
|
67
|
+
if (mode === "single" && page?.multipleThings) {
|
|
68
|
+
return handleMiddlewareError(`Single mode file view not allowed on multipleThings pages`, 404, next)
|
|
69
|
+
}
|
|
65
70
|
// Validate the field: Only allow delete if the page contains a fileInput with the given name
|
|
66
71
|
const fileInputElement = pageContainsFileInput(pageTemplateCopy, elementName);
|
|
67
72
|
if (!fileInputElement) {
|
|
@@ -81,8 +81,8 @@ export function govcyMultipleThingsDeletePageHandler() {
|
|
|
81
81
|
isPageHeading: true,
|
|
82
82
|
classes: "govcy-mb-6",
|
|
83
83
|
items: [
|
|
84
|
-
{ value: "yes", text: govcyResources.staticResources.text.
|
|
85
|
-
{ value: "no", text: govcyResources.staticResources.text.
|
|
84
|
+
{ value: "yes", text: govcyResources.staticResources.text.multipleThingsDeleteYesOption },
|
|
85
|
+
{ value: "no", text: govcyResources.staticResources.text.multipleThingsDeleteNoOption }
|
|
86
86
|
]
|
|
87
87
|
}
|
|
88
88
|
};
|
|
@@ -5,6 +5,7 @@ import * as dataLayer from "../utils/govcyDataLayer.mjs";
|
|
|
5
5
|
import { logger } from "../utils/govcyLogger.mjs";
|
|
6
6
|
import { evaluatePageConditions } from "../utils/govcyExpressions.mjs";
|
|
7
7
|
import { govcyMultipleThingsHubHandler } from "./govcyMultipleThingsHubHandler.mjs";
|
|
8
|
+
import { govcyUpdateMyDetailsHandler } from "./govcyUpdateMyDetails.mjs";
|
|
8
9
|
// import {flattenContext, evaluateExpressionWithFlattening, evaluatePageConditions } from "../utils/govcyExpressions.mjs";
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -12,7 +13,7 @@ import { govcyMultipleThingsHubHandler } from "./govcyMultipleThingsHubHandler.m
|
|
|
12
13
|
* This middleware processes the page template, populates form data, and shows validation errors.
|
|
13
14
|
*/
|
|
14
15
|
export function govcyPageHandler() {
|
|
15
|
-
return (req, res, next) => {
|
|
16
|
+
return async (req, res, next) => {
|
|
16
17
|
try {
|
|
17
18
|
// Extract siteId and pageUrl from request
|
|
18
19
|
let { siteId, pageUrl } = req.params;
|
|
@@ -30,9 +31,6 @@ export function govcyPageHandler() {
|
|
|
30
31
|
// 🔍 Find the page by pageUrl
|
|
31
32
|
const page = getPageConfigData(serviceCopy, pageUrl);
|
|
32
33
|
|
|
33
|
-
// Deep copy pageTemplate to avoid modifying the original
|
|
34
|
-
const pageTemplateCopy = JSON.parse(JSON.stringify(page.pageTemplate));
|
|
35
|
-
|
|
36
34
|
// ----- Conditional logic comes here
|
|
37
35
|
// Check if the page has conditions and apply logic
|
|
38
36
|
const result = evaluatePageConditions(page, req.session, req.params.siteId, req);
|
|
@@ -40,11 +38,20 @@ export function govcyPageHandler() {
|
|
|
40
38
|
return res.redirect(`/${req.params.siteId}/${result.redirect}`);
|
|
41
39
|
}
|
|
42
40
|
|
|
41
|
+
// ----- `updateMyDetails` handling
|
|
42
|
+
if (page.updateMyDetails) {
|
|
43
|
+
return await govcyUpdateMyDetailsHandler(req, res, next, page, serviceCopy);
|
|
44
|
+
}
|
|
45
|
+
// ----- `updateMyDetails` handling
|
|
46
|
+
|
|
43
47
|
// ----- MultipleThings hub handling
|
|
44
48
|
if (page.multipleThings) {
|
|
45
49
|
logger.debug(`Rendering multipleThings hub for pageUrl: ${pageUrl}`, req);
|
|
46
50
|
return govcyMultipleThingsHubHandler(req, res, next, page, serviceCopy);
|
|
47
51
|
}
|
|
52
|
+
|
|
53
|
+
// Deep copy pageTemplate to avoid modifying the original
|
|
54
|
+
const pageTemplateCopy = JSON.parse(JSON.stringify(page.pageTemplate));
|
|
48
55
|
|
|
49
56
|
//⚙️ Process forms before rendering
|
|
50
57
|
pageTemplateCopy.sections.forEach(section => {
|
|
@@ -8,6 +8,7 @@ import { getEnvVariable, getEnvVariableBool } from "../utils/govcyEnvVariables.m
|
|
|
8
8
|
import { handleMiddlewareError } from "../utils/govcyUtils.mjs";
|
|
9
9
|
import { sendEmail } from "../utils/govcyNotification.mjs"
|
|
10
10
|
import { evaluatePageConditions } from "../utils/govcyExpressions.mjs";
|
|
11
|
+
import { createUmdManualPageTemplate } from "./govcyUpdateMyDetails.mjs"
|
|
11
12
|
import { validateMultipleThings } from "../utils/govcyMultipleThingsValidation.mjs";
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -38,9 +39,29 @@ export function govcyReviewPostHandler() {
|
|
|
38
39
|
|
|
39
40
|
// Find the form definition inside `pageTemplate.sections`
|
|
40
41
|
let formElement = null;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
|
|
43
|
+
// ----- `updateMyDetails` handling
|
|
44
|
+
if (page.updateMyDetails) {
|
|
45
|
+
logger.debug("Validating UpdateMyDetails page during review POST", { siteId, pageUrl });
|
|
46
|
+
// Build the manual UMD page template
|
|
47
|
+
const umdTemplate = createUmdManualPageTemplate(siteId, service.site.lang, page, req);
|
|
48
|
+
|
|
49
|
+
// Extract the form element
|
|
50
|
+
formElement = umdTemplate .sections
|
|
51
|
+
.flatMap(section => section.elements)
|
|
52
|
+
.find(el => el.element === "form");
|
|
53
|
+
|
|
54
|
+
if (!formElement) {
|
|
55
|
+
logger.error("🚨 UMD form element not found during review validation", { siteId, pageUrl });
|
|
56
|
+
return handleMiddlewareError("🚨 UMD form element not found during review validation", 500, next);
|
|
57
|
+
}
|
|
58
|
+
// ----- `updateMyDetails` handling
|
|
59
|
+
} else {
|
|
60
|
+
// Normal flow
|
|
61
|
+
for (const section of page.pageTemplate.sections) {
|
|
62
|
+
formElement = section.elements.find(el => el.element === "form");
|
|
63
|
+
if (formElement) break;
|
|
64
|
+
}
|
|
44
65
|
}
|
|
45
66
|
|
|
46
67
|
if (!formElement) continue; // Skip pages without forms
|