@dwp/govuk-casa 8.16.1 → 8.16.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/dist/assets/css/casa-ie8.css +1 -1
- package/dist/assets/css/casa.css +1 -1
- package/dist/casa.d.ts +13 -13
- package/dist/casa.js +17 -7
- package/dist/casa.js.map +1 -1
- package/dist/lib/CasaTemplateLoader.d.ts +1 -1
- package/dist/lib/CasaTemplateLoader.js +13 -14
- package/dist/lib/CasaTemplateLoader.js.map +1 -1
- package/dist/lib/JourneyContext.d.ts +10 -4
- package/dist/lib/JourneyContext.js +57 -47
- package/dist/lib/JourneyContext.js.map +1 -1
- package/dist/lib/MutableRouter.d.ts +1 -1
- package/dist/lib/MutableRouter.js +22 -23
- package/dist/lib/MutableRouter.js.map +1 -1
- package/dist/lib/Plan.d.ts +5 -5
- package/dist/lib/Plan.js +49 -36
- package/dist/lib/Plan.js.map +1 -1
- package/dist/lib/ValidationError.d.ts +1 -1
- package/dist/lib/ValidationError.js +9 -9
- package/dist/lib/ValidationError.js.map +1 -1
- package/dist/lib/ValidatorFactory.js +4 -7
- package/dist/lib/ValidatorFactory.js.map +1 -1
- package/dist/lib/configuration-ingestor.d.ts +75 -14
- package/dist/lib/configuration-ingestor.js +156 -64
- package/dist/lib/configuration-ingestor.js.map +1 -1
- package/dist/lib/configure.js +11 -10
- package/dist/lib/configure.js.map +1 -1
- package/dist/lib/constants.js +8 -8
- package/dist/lib/context-id-generators.d.ts +1 -1
- package/dist/lib/context-id-generators.js +7 -4
- package/dist/lib/context-id-generators.js.map +1 -1
- package/dist/lib/end-session.js +2 -2
- package/dist/lib/field.d.ts +6 -6
- package/dist/lib/field.js +15 -21
- package/dist/lib/field.js.map +1 -1
- package/dist/lib/index.d.ts +13 -13
- package/dist/lib/index.js +17 -7
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/logger.js +7 -7
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/mount.js +3 -3
- package/dist/lib/mount.js.map +1 -1
- package/dist/lib/nunjucks-filters.d.ts +5 -1
- package/dist/lib/nunjucks-filters.js +37 -23
- package/dist/lib/nunjucks-filters.js.map +1 -1
- package/dist/lib/nunjucks.d.ts +2 -2
- package/dist/lib/nunjucks.js +6 -7
- package/dist/lib/nunjucks.js.map +1 -1
- package/dist/lib/utils.js +52 -42
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/validators/dateObject.d.ts +3 -3
- package/dist/lib/validators/dateObject.js +44 -37
- package/dist/lib/validators/dateObject.js.map +1 -1
- package/dist/lib/validators/email.d.ts +2 -2
- package/dist/lib/validators/email.js +4 -5
- package/dist/lib/validators/email.js.map +1 -1
- package/dist/lib/validators/inArray.d.ts +2 -2
- package/dist/lib/validators/inArray.js +5 -6
- package/dist/lib/validators/inArray.js.map +1 -1
- package/dist/lib/validators/index.d.ts +10 -10
- package/dist/lib/validators/index.js.map +1 -1
- package/dist/lib/validators/nino.d.ts +2 -2
- package/dist/lib/validators/nino.js +10 -7
- package/dist/lib/validators/nino.js.map +1 -1
- package/dist/lib/validators/postalAddressObject.d.ts +2 -2
- package/dist/lib/validators/postalAddressObject.js +52 -39
- package/dist/lib/validators/postalAddressObject.js.map +1 -1
- package/dist/lib/validators/range.d.ts +2 -2
- package/dist/lib/validators/range.js +6 -7
- package/dist/lib/validators/range.js.map +1 -1
- package/dist/lib/validators/regex.d.ts +2 -2
- package/dist/lib/validators/regex.js +4 -5
- package/dist/lib/validators/regex.js.map +1 -1
- package/dist/lib/validators/required.d.ts +2 -2
- package/dist/lib/validators/required.js +6 -9
- package/dist/lib/validators/required.js.map +1 -1
- package/dist/lib/validators/strlen.d.ts +2 -2
- package/dist/lib/validators/strlen.js +8 -9
- package/dist/lib/validators/strlen.js.map +1 -1
- package/dist/lib/validators/wordCount.d.ts +2 -2
- package/dist/lib/validators/wordCount.js +10 -9
- package/dist/lib/validators/wordCount.js.map +1 -1
- package/dist/lib/waypoint-url.d.ts +4 -4
- package/dist/lib/waypoint-url.js +23 -23
- package/dist/lib/waypoint-url.js.map +1 -1
- package/dist/middleware/body-parser.d.ts +27 -5
- package/dist/middleware/body-parser.js +37 -6
- package/dist/middleware/body-parser.js.map +1 -1
- package/dist/middleware/csrf.d.ts +3 -0
- package/dist/middleware/csrf.js +3 -0
- package/dist/middleware/csrf.js.map +1 -1
- package/dist/middleware/data.d.ts +22 -5
- package/dist/middleware/data.js +37 -7
- package/dist/middleware/data.js.map +1 -1
- package/dist/middleware/gather-fields.d.ts +1 -1
- package/dist/middleware/gather-fields.js +4 -3
- package/dist/middleware/gather-fields.js.map +1 -1
- package/dist/middleware/i18n.d.ts +11 -2
- package/dist/middleware/i18n.js +26 -17
- package/dist/middleware/i18n.js.map +1 -1
- package/dist/middleware/post.d.ts +3 -1
- package/dist/middleware/post.js +35 -18
- package/dist/middleware/post.js.map +1 -1
- package/dist/middleware/pre.d.ts +1 -1
- package/dist/middleware/pre.js +44 -21
- package/dist/middleware/pre.js.map +1 -1
- package/dist/middleware/progress-journey.d.ts +1 -1
- package/dist/middleware/progress-journey.js +5 -5
- package/dist/middleware/progress-journey.js.map +1 -1
- package/dist/middleware/sanitise-fields.d.ts +2 -2
- package/dist/middleware/sanitise-fields.js +13 -11
- package/dist/middleware/sanitise-fields.js.map +1 -1
- package/dist/middleware/serve-first-waypoint.d.ts +1 -1
- package/dist/middleware/serve-first-waypoint.js +6 -4
- package/dist/middleware/serve-first-waypoint.js.map +1 -1
- package/dist/middleware/session.d.ts +27 -8
- package/dist/middleware/session.js +53 -25
- package/dist/middleware/session.js.map +1 -1
- package/dist/middleware/skip-waypoint.d.ts +1 -1
- package/dist/middleware/skip-waypoint.js +3 -3
- package/dist/middleware/skip-waypoint.js.map +1 -1
- package/dist/middleware/steer-journey.d.ts +1 -1
- package/dist/middleware/steer-journey.js +15 -13
- package/dist/middleware/steer-journey.js.map +1 -1
- package/dist/middleware/strip-proxy-path.d.ts +1 -1
- package/dist/middleware/strip-proxy-path.js +3 -3
- package/dist/middleware/strip-proxy-path.js.map +1 -1
- package/dist/middleware/validate-fields.d.ts +2 -2
- package/dist/middleware/validate-fields.js +2 -5
- package/dist/middleware/validate-fields.js.map +1 -1
- package/dist/routes/ancillary.d.ts +2 -2
- package/dist/routes/ancillary.js +3 -3
- package/dist/routes/ancillary.js.map +1 -1
- package/dist/routes/journey.d.ts +1 -1
- package/dist/routes/journey.js +85 -31
- package/dist/routes/journey.js.map +1 -1
- package/dist/routes/static.d.ts +2 -2
- package/dist/routes/static.js +18 -18
- package/dist/routes/static.js.map +1 -1
- package/package.json +39 -42
- package/src/casa.js +13 -13
- package/src/lib/CasaTemplateLoader.js +21 -17
- package/src/lib/JourneyContext.js +118 -79
- package/src/lib/MutableRouter.js +30 -26
- package/src/lib/Plan.js +109 -62
- package/src/lib/ValidationError.js +13 -10
- package/src/lib/ValidatorFactory.js +7 -8
- package/src/lib/configuration-ingestor.js +200 -74
- package/src/lib/configure.js +31 -30
- package/src/lib/constants.js +8 -8
- package/src/lib/context-id-generators.js +39 -38
- package/src/lib/end-session.js +3 -3
- package/src/lib/field.js +48 -32
- package/src/lib/index.js +12 -12
- package/src/lib/logger.js +9 -9
- package/src/lib/mount.js +68 -73
- package/src/lib/nunjucks-filters.js +57 -44
- package/src/lib/nunjucks.js +20 -16
- package/src/lib/utils.js +69 -44
- package/src/lib/validators/dateObject.js +57 -48
- package/src/lib/validators/email.js +8 -9
- package/src/lib/validators/inArray.js +8 -9
- package/src/lib/validators/index.js +11 -11
- package/src/lib/validators/nino.js +25 -12
- package/src/lib/validators/postalAddressObject.js +73 -55
- package/src/lib/validators/range.js +9 -11
- package/src/lib/validators/regex.js +7 -8
- package/src/lib/validators/required.js +13 -14
- package/src/lib/validators/strlen.js +11 -12
- package/src/lib/validators/wordCount.js +17 -12
- package/src/lib/waypoint-url.js +48 -33
- package/src/middleware/body-parser.js +44 -10
- package/src/middleware/csrf.js +4 -1
- package/src/middleware/data.js +62 -25
- package/src/middleware/gather-fields.js +8 -8
- package/src/middleware/i18n.js +49 -39
- package/src/middleware/post.js +47 -21
- package/src/middleware/pre.js +60 -35
- package/src/middleware/progress-journey.js +32 -18
- package/src/middleware/sanitise-fields.js +43 -20
- package/src/middleware/serve-first-waypoint.js +12 -10
- package/src/middleware/session.js +97 -65
- package/src/middleware/skip-waypoint.js +7 -9
- package/src/middleware/steer-journey.js +39 -27
- package/src/middleware/strip-proxy-path.js +8 -7
- package/src/middleware/validate-fields.js +5 -12
- package/src/routes/ancillary.js +4 -6
- package/src/routes/journey.js +158 -78
- package/src/routes/static.js +61 -28
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// This sits in front of all other middleware and prevents the user from
|
|
2
2
|
// "jumping ahead" in the Plan.
|
|
3
3
|
|
|
4
|
-
import waypointUrl from
|
|
5
|
-
import logger from
|
|
4
|
+
import waypointUrl from "../lib/waypoint-url.js";
|
|
5
|
+
import logger from "../lib/logger.js";
|
|
6
6
|
|
|
7
|
-
const log = logger(
|
|
7
|
+
const log = logger("middleware:steer-journey");
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @access private
|
|
@@ -20,10 +20,7 @@ const log = logger('middleware:steer-journey');
|
|
|
20
20
|
* @param {Plan} obj.plan CASA Plan
|
|
21
21
|
* @returns {void}
|
|
22
22
|
*/
|
|
23
|
-
export default ({
|
|
24
|
-
waypoint,
|
|
25
|
-
plan,
|
|
26
|
-
}) => [
|
|
23
|
+
export default ({ waypoint, plan }) => [
|
|
27
24
|
(req, res, next) => {
|
|
28
25
|
const mountUrl = `${req.baseUrl}/`;
|
|
29
26
|
|
|
@@ -32,25 +29,38 @@ export default ({
|
|
|
32
29
|
const traversed = plan.traverse(req.casa.journeyContext);
|
|
33
30
|
if (traversed.indexOf(waypoint) === -1) {
|
|
34
31
|
const redirectTo = traversed[traversed.length - 1];
|
|
35
|
-
log.trace(
|
|
32
|
+
log.trace(
|
|
33
|
+
`Attempted to access "${waypoint}" when not in the journey; redirecting to "${redirectTo}"`,
|
|
34
|
+
);
|
|
36
35
|
|
|
37
|
-
return res.redirect(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
return res.redirect(
|
|
37
|
+
302,
|
|
38
|
+
waypointUrl({
|
|
39
|
+
waypoint: redirectTo,
|
|
40
|
+
mountUrl,
|
|
41
|
+
journeyContext: req.casa.journeyContext,
|
|
42
|
+
edit: req.casa.editMode,
|
|
43
|
+
editOrigin: req.casa.editOrigin,
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
// Edit mode
|
|
47
49
|
// Cannot be in edit mode if we're already on the `editorigin` URL
|
|
48
50
|
if (req.casa.editMode) {
|
|
49
|
-
const { pathname: currentPathname } = new URL(
|
|
50
|
-
|
|
51
|
+
const { pathname: currentPathname } = new URL(
|
|
52
|
+
req.originalUrl,
|
|
53
|
+
"https://placeholder.test/",
|
|
54
|
+
);
|
|
55
|
+
const { pathname: editOriginPathname } = new URL(
|
|
56
|
+
req.casa.editOrigin,
|
|
57
|
+
"https://placeholder.test/",
|
|
58
|
+
);
|
|
51
59
|
|
|
52
60
|
if (editOriginPathname === currentPathname) {
|
|
53
|
-
log.debug(
|
|
61
|
+
log.debug(
|
|
62
|
+
`Disabling edit mode as we are on the edit origin (${req.casa.editOrigin})`,
|
|
63
|
+
);
|
|
54
64
|
req.casa.editMode = false;
|
|
55
65
|
req.casa.editOrigin = undefined;
|
|
56
66
|
}
|
|
@@ -64,16 +74,18 @@ export default ({
|
|
|
64
74
|
// Calculate URL for the "back" link
|
|
65
75
|
const [prevRoute] = plan.traversePrevRoutes(req.casa.journeyContext, {
|
|
66
76
|
startWaypoint: waypoint,
|
|
67
|
-
stopCondition: () =>
|
|
77
|
+
stopCondition: () => true, // stop at the first one
|
|
68
78
|
});
|
|
69
|
-
res.locals.casa.journeyPreviousUrl = prevRoute.target
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
res.locals.casa.journeyPreviousUrl = prevRoute.target
|
|
80
|
+
? waypointUrl({
|
|
81
|
+
mountUrl,
|
|
82
|
+
journeyContext: req.casa.journeyContext,
|
|
83
|
+
waypoint: prevRoute.target,
|
|
84
|
+
routeName: "prev",
|
|
85
|
+
edit: req.casa.editMode,
|
|
86
|
+
editOrigin: req.casa.editOrigin,
|
|
87
|
+
})
|
|
88
|
+
: undefined;
|
|
77
89
|
|
|
78
90
|
return next();
|
|
79
91
|
},
|
|
@@ -14,13 +14,11 @@
|
|
|
14
14
|
//
|
|
15
15
|
// See docs in `docs/guides/setup-behind-a-proxy.md`
|
|
16
16
|
|
|
17
|
-
import logger from
|
|
17
|
+
import logger from "../lib/logger.js";
|
|
18
18
|
|
|
19
|
-
const log = logger(
|
|
19
|
+
const log = logger("casa:middleware:strip-proxy-path");
|
|
20
20
|
|
|
21
|
-
export default ({
|
|
22
|
-
mountUrl = '/',
|
|
23
|
-
}) => [
|
|
21
|
+
export default ({ mountUrl = "/" }) => [
|
|
24
22
|
(req, res, next) => {
|
|
25
23
|
// TODO:
|
|
26
24
|
// We _may_ have to start tracking the various prefix in order to differentiate
|
|
@@ -28,7 +26,7 @@ export default ({
|
|
|
28
26
|
|
|
29
27
|
// Assume everything before `mountUrl` is the proxy path prefix and remove it
|
|
30
28
|
req.originalBaseUrl = req.originalBaseUrl ?? req.baseUrl;
|
|
31
|
-
req.baseUrl = mountUrl.replace(/\/$/,
|
|
29
|
+
req.baseUrl = mountUrl.replace(/\/$/, "");
|
|
32
30
|
|
|
33
31
|
// If the app has been mounted directly on the specific `mountUrl`, then
|
|
34
32
|
// there's nothing we need to do and can let this request pass-through.
|
|
@@ -43,7 +41,10 @@ export default ({
|
|
|
43
41
|
// req.url will already have the proxy prefix and mountUrl removed.
|
|
44
42
|
/* eslint-disable security/detect-non-literal-regexp */
|
|
45
43
|
log.trace(`req.originalUrl before proxy stripping: ${req.originalUrl}`);
|
|
46
|
-
req.originalUrl = req.originalUrl.replace(
|
|
44
|
+
req.originalUrl = req.originalUrl.replace(
|
|
45
|
+
new RegExp(`^/.+?${mountUrl}`),
|
|
46
|
+
mountUrl,
|
|
47
|
+
);
|
|
47
48
|
log.trace(`req.originalUrl after proxy stripping: ${req.originalUrl}`);
|
|
48
49
|
/* eslint-enable security/detect-non-literal-regexp */
|
|
49
50
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Validate the data captured in the journey context
|
|
2
|
-
import JourneyContext from
|
|
3
|
-
import { REQUEST_PHASE_VALIDATE } from
|
|
2
|
+
import JourneyContext from "../lib/JourneyContext.js";
|
|
3
|
+
import { REQUEST_PHASE_VALIDATE } from "../lib/constants.js";
|
|
4
4
|
|
|
5
5
|
const updateContext = ({
|
|
6
6
|
waypoint,
|
|
@@ -21,13 +21,9 @@ const updateContext = ({
|
|
|
21
21
|
casaRequestPhase: REQUEST_PHASE_VALIDATE,
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
|
-
}
|
|
24
|
+
};
|
|
25
25
|
|
|
26
|
-
export default ({
|
|
27
|
-
waypoint,
|
|
28
|
-
fields = [],
|
|
29
|
-
plan,
|
|
30
|
-
}) => [
|
|
26
|
+
export default ({ waypoint, fields = [], plan }) => [
|
|
31
27
|
(req, res, next) => {
|
|
32
28
|
const mountUrl = `${req.baseUrl}/`;
|
|
33
29
|
|
|
@@ -50,10 +46,7 @@ export default ({
|
|
|
50
46
|
};
|
|
51
47
|
/* eslint-enable security/detect-object-injection */
|
|
52
48
|
|
|
53
|
-
errors = [
|
|
54
|
-
...errors,
|
|
55
|
-
...field.runValidators(fieldValue, context),
|
|
56
|
-
];
|
|
49
|
+
errors = [...errors, ...field.runValidators(fieldValue, context)];
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
// Validation passed with no errors
|
package/src/routes/ancillary.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import MutableRouter from
|
|
1
|
+
import MutableRouter from "../lib/MutableRouter.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @typedef {object} AncillaryRouterOptions Options to configure static router
|
|
@@ -12,15 +12,13 @@ import MutableRouter from '../lib/MutableRouter.js';
|
|
|
12
12
|
* @param {AncillaryRouterOptions} options Options
|
|
13
13
|
* @returns {MutableRouter} ExpressJS Router instance
|
|
14
14
|
*/
|
|
15
|
-
export default function ancillaryRouter({
|
|
16
|
-
sessionTtl,
|
|
17
|
-
}) {
|
|
15
|
+
export default function ancillaryRouter({ sessionTtl }) {
|
|
18
16
|
// Router
|
|
19
17
|
const router = new MutableRouter();
|
|
20
18
|
|
|
21
19
|
// Session timeout
|
|
22
|
-
router.all(
|
|
23
|
-
res.render(
|
|
20
|
+
router.all("/session-timeout", (req, res) => {
|
|
21
|
+
res.render("casa/session-timeout.njk", {
|
|
24
22
|
sessionTtl: Math.floor(sessionTtl / 60),
|
|
25
23
|
});
|
|
26
24
|
});
|
package/src/routes/journey.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import MutableRouter from "../lib/MutableRouter.js";
|
|
2
|
+
import skipWaypointMiddlewareFactory from "../middleware/skip-waypoint.js";
|
|
3
|
+
import steerJourneyMiddlewareFactory from "../middleware/steer-journey.js";
|
|
4
|
+
import sanitiseFieldsMiddlewareFactory from "../middleware/sanitise-fields.js";
|
|
5
|
+
import gatherFieldsMiddlewareFactory from "../middleware/gather-fields.js";
|
|
6
|
+
import validateFieldsMiddlewareFactory from "../middleware/validate-fields.js";
|
|
7
|
+
import progressJourneyMiddlewareFactory from "../middleware/progress-journey.js";
|
|
8
|
+
import waypointUrl from "../lib/waypoint-url.js";
|
|
9
|
+
import logger from "../lib/logger.js";
|
|
10
|
+
import { resolveMiddlewareHooks } from "../lib/utils.js";
|
|
11
|
+
import { CONFIG_ERROR_VISIBILITY_ALWAYS } from "../lib/constants.js";
|
|
12
|
+
|
|
13
|
+
const log = logger("routes:journey");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @access private
|
|
17
|
+
* @param {import('express').RequestHandler} RequestHandler
|
|
18
|
+
*/
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
21
|
* @access private
|
|
@@ -38,20 +42,27 @@ const log = logger('routes:journey');
|
|
|
38
42
|
|
|
39
43
|
const renderMiddlewareFactory = (view, contextFactory) => [
|
|
40
44
|
(req, res, next) => {
|
|
41
|
-
res.render(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
45
|
+
res.render(
|
|
46
|
+
view,
|
|
47
|
+
{
|
|
48
|
+
// Common template variables for both GET and POST requests
|
|
49
|
+
inEditMode: req.casa.editMode,
|
|
50
|
+
editOriginUrl: req.casa.editOrigin,
|
|
51
|
+
editCancelUrl: generateEditCancelUrl(
|
|
52
|
+
req.casa.editOrigin,
|
|
53
|
+
req.casa.waypoint,
|
|
54
|
+
),
|
|
55
|
+
activeContextId: req.casa.journeyContext.identity.id,
|
|
56
|
+
...contextFactory(req),
|
|
57
|
+
},
|
|
58
|
+
(err, templateString) => {
|
|
59
|
+
if (err) {
|
|
60
|
+
next(err);
|
|
61
|
+
} else {
|
|
62
|
+
res.send(templateString);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
);
|
|
55
66
|
},
|
|
56
67
|
];
|
|
57
68
|
|
|
@@ -62,25 +73,29 @@ const renderMiddlewareFactory = (view, contextFactory) => [
|
|
|
62
73
|
* @param {object} req casa request object
|
|
63
74
|
* @returns {object[]} array of error objects
|
|
64
75
|
*/
|
|
65
|
-
const generateGovukErrors = (errors, req) =>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
const generateGovukErrors = (errors, req) =>
|
|
77
|
+
Object.values(errors || {}).map(([error]) => ({
|
|
78
|
+
text: req.t(error.summary, error.variables),
|
|
79
|
+
href: error.fieldHref,
|
|
80
|
+
}));
|
|
69
81
|
|
|
70
82
|
const generateEditCancelUrl = (editOrigin, waypoint) => {
|
|
71
|
-
const url = new URL(editOrigin,
|
|
72
|
-
url.searchParams.set(
|
|
83
|
+
const url = new URL(editOrigin, "https://placeholder.test/");
|
|
84
|
+
url.searchParams.set("editcancel", waypoint);
|
|
73
85
|
return `${url.pathname}${url.search}`;
|
|
74
86
|
};
|
|
75
87
|
|
|
76
88
|
/**
|
|
77
89
|
* handle errorVisibility flag and function and return boolean
|
|
78
90
|
*
|
|
91
|
+
* @param {RequestHandler} req casa request object
|
|
79
92
|
* @param {symbol | Function} errorVisibility errorVisibility config option
|
|
80
|
-
* @param {object} req casa request object
|
|
81
93
|
* @returns {boolean} true if errorVisibility is "always" or function condition true
|
|
82
94
|
*/
|
|
83
|
-
const resolveErrorVisibility = (req, errorVisibility) =>
|
|
95
|
+
const resolveErrorVisibility = (req, errorVisibility) =>
|
|
96
|
+
typeof errorVisibility === "function"
|
|
97
|
+
? errorVisibility({ req })
|
|
98
|
+
: errorVisibility === CONFIG_ERROR_VISIBILITY_ALWAYS;
|
|
84
99
|
|
|
85
100
|
/**
|
|
86
101
|
* Create an instance of the router for all waypoints visited during a Journey
|
|
@@ -102,7 +117,7 @@ export default function journeyRouter({
|
|
|
102
117
|
|
|
103
118
|
// Special "_" route which handles redirecting the user between sub-apps
|
|
104
119
|
// /app1/_/?refmount=app2&route=prev
|
|
105
|
-
router.all(
|
|
120
|
+
router.all("/_", (req, res) => {
|
|
106
121
|
const mountUrl = `${req.baseUrl}/`;
|
|
107
122
|
const refmount = req.query?.refmount;
|
|
108
123
|
const route = req.query?.route;
|
|
@@ -112,7 +127,7 @@ export default function journeyRouter({
|
|
|
112
127
|
const fallback = waypointUrl({
|
|
113
128
|
mountUrl,
|
|
114
129
|
waypoint: plan.traverse(req.casa.journeyContext, {
|
|
115
|
-
stopCondition: () =>
|
|
130
|
+
stopCondition: () => true, // we only need one; stop at the first
|
|
116
131
|
})[0],
|
|
117
132
|
});
|
|
118
133
|
|
|
@@ -121,37 +136,49 @@ export default function journeyRouter({
|
|
|
121
136
|
// the user to our Plan and we don't intend to link back.
|
|
122
137
|
if (!plan.getWaypoints().includes(refmount)) {
|
|
123
138
|
redirectTo = fallback;
|
|
124
|
-
} else if (route ===
|
|
125
|
-
const routes = plan.traversePrevRoutes(req.casa.journeyContext, {
|
|
126
|
-
|
|
139
|
+
} else if (route === "prev") {
|
|
140
|
+
const routes = plan.traversePrevRoutes(req.casa.journeyContext, {
|
|
141
|
+
startWaypoint: refmount,
|
|
142
|
+
});
|
|
143
|
+
redirectTo = routes.length
|
|
144
|
+
? waypointUrl({ mountUrl, waypoint: routes[0].target })
|
|
145
|
+
: fallback;
|
|
127
146
|
} else {
|
|
128
|
-
const routes = plan.traverseNextRoutes(req.casa.journeyContext, {
|
|
147
|
+
const routes = plan.traverseNextRoutes(req.casa.journeyContext, {
|
|
148
|
+
startWaypoint: refmount,
|
|
149
|
+
});
|
|
129
150
|
if (routes[0].target !== null) {
|
|
130
|
-
redirectTo = routes.length
|
|
151
|
+
redirectTo = routes.length
|
|
152
|
+
? waypointUrl({ mountUrl, waypoint: routes[0].target })
|
|
153
|
+
: fallback;
|
|
131
154
|
} else {
|
|
132
155
|
redirectTo = fallback;
|
|
133
156
|
}
|
|
134
157
|
}
|
|
135
158
|
|
|
136
159
|
// Carry over any params
|
|
137
|
-
const url = new URL(redirectTo,
|
|
160
|
+
const url = new URL(redirectTo, "https://placeholder.test/");
|
|
138
161
|
const searchParams = new URLSearchParams(req.query);
|
|
139
|
-
searchParams.delete(
|
|
140
|
-
searchParams.delete(
|
|
162
|
+
searchParams.delete("refmount");
|
|
163
|
+
searchParams.delete("route");
|
|
141
164
|
url.search = searchParams.toString();
|
|
142
|
-
redirectTo = `${url.pathname.replace(/\/+/g,
|
|
165
|
+
redirectTo = `${url.pathname.replace(/\/+/g, "/")}${url.search}`;
|
|
143
166
|
|
|
144
167
|
log.trace(`Redirect to ${redirectTo}`);
|
|
145
168
|
return res.redirect(redirectTo);
|
|
146
169
|
});
|
|
147
170
|
|
|
148
171
|
// Create GET / POST routes for each page
|
|
149
|
-
const commonMiddleware = [
|
|
150
|
-
...csrfMiddleware,
|
|
151
|
-
];
|
|
172
|
+
const commonMiddleware = [...csrfMiddleware];
|
|
152
173
|
|
|
153
174
|
pages.forEach((page) => {
|
|
154
|
-
const {
|
|
175
|
+
const {
|
|
176
|
+
waypoint,
|
|
177
|
+
view,
|
|
178
|
+
hooks: pageHooks = [],
|
|
179
|
+
fields,
|
|
180
|
+
errorVisibility,
|
|
181
|
+
} = page;
|
|
155
182
|
const waypointPath = `/${waypoint}`;
|
|
156
183
|
|
|
157
184
|
let commonWaypointMiddleware = [
|
|
@@ -175,22 +202,40 @@ export default function journeyRouter({
|
|
|
175
202
|
...commonMiddleware,
|
|
176
203
|
...commonWaypointMiddleware,
|
|
177
204
|
|
|
178
|
-
...resolveMiddlewareHooks(
|
|
205
|
+
...resolveMiddlewareHooks("journey.presteer", waypointPath, [
|
|
206
|
+
...globalHooks,
|
|
207
|
+
...pageHooks,
|
|
208
|
+
]),
|
|
179
209
|
...steerJourneyMiddlewareFactory({ waypoint, plan }),
|
|
180
|
-
...resolveMiddlewareHooks(
|
|
181
|
-
|
|
182
|
-
|
|
210
|
+
...resolveMiddlewareHooks("journey.poststeer", waypointPath, [
|
|
211
|
+
...globalHooks,
|
|
212
|
+
...pageHooks,
|
|
213
|
+
]),
|
|
214
|
+
|
|
215
|
+
...resolveMiddlewareHooks("journey.prerender", waypointPath, [
|
|
216
|
+
...globalHooks,
|
|
217
|
+
...pageHooks,
|
|
218
|
+
]),
|
|
183
219
|
renderMiddlewareFactory(view, (req) => {
|
|
184
|
-
const displayErrors =
|
|
185
|
-
|
|
220
|
+
const displayErrors =
|
|
221
|
+
resolveErrorVisibility(req, globalErrorVisibility) ||
|
|
222
|
+
resolveErrorVisibility(req, errorVisibility);
|
|
223
|
+
const errors =
|
|
224
|
+
displayErrors &&
|
|
225
|
+
(req.casa.journeyContext.getValidationErrorsForPageByField(
|
|
226
|
+
waypoint,
|
|
227
|
+
) ??
|
|
228
|
+
Object.create(null));
|
|
186
229
|
const govukErrors = displayErrors && generateGovukErrors(errors, req);
|
|
187
230
|
|
|
188
|
-
return
|
|
231
|
+
return {
|
|
189
232
|
formUrl: waypointUrl({ mountUrl: `${req.baseUrl}/`, waypoint }),
|
|
190
233
|
formData: req.casa.journeyContext.getDataForPage(waypoint),
|
|
191
|
-
formErrors:
|
|
192
|
-
|
|
193
|
-
|
|
234
|
+
formErrors:
|
|
235
|
+
Object.keys(errors).length && displayErrors ? errors : null,
|
|
236
|
+
formErrorsGovukArray:
|
|
237
|
+
govukErrors.length && displayErrors ? govukErrors : null,
|
|
238
|
+
};
|
|
194
239
|
}),
|
|
195
240
|
);
|
|
196
241
|
|
|
@@ -199,35 +244,70 @@ export default function journeyRouter({
|
|
|
199
244
|
...commonMiddleware,
|
|
200
245
|
...commonWaypointMiddleware,
|
|
201
246
|
|
|
202
|
-
...resolveMiddlewareHooks(
|
|
247
|
+
...resolveMiddlewareHooks("journey.presteer", waypointPath, [
|
|
248
|
+
...globalHooks,
|
|
249
|
+
...pageHooks,
|
|
250
|
+
]),
|
|
203
251
|
...steerJourneyMiddlewareFactory({ waypoint, plan }),
|
|
204
|
-
...resolveMiddlewareHooks(
|
|
205
|
-
|
|
206
|
-
|
|
252
|
+
...resolveMiddlewareHooks("journey.poststeer", waypointPath, [
|
|
253
|
+
...globalHooks,
|
|
254
|
+
...pageHooks,
|
|
255
|
+
]),
|
|
256
|
+
|
|
257
|
+
...resolveMiddlewareHooks("journey.presanitise", waypointPath, [
|
|
258
|
+
...globalHooks,
|
|
259
|
+
...pageHooks,
|
|
260
|
+
]),
|
|
207
261
|
...sanitiseFieldsMiddlewareFactory({ waypoint, fields }),
|
|
208
|
-
...resolveMiddlewareHooks(
|
|
209
|
-
|
|
210
|
-
|
|
262
|
+
...resolveMiddlewareHooks("journey.postsanitise", waypointPath, [
|
|
263
|
+
...globalHooks,
|
|
264
|
+
...pageHooks,
|
|
265
|
+
]),
|
|
266
|
+
|
|
267
|
+
...resolveMiddlewareHooks("journey.pregather", waypointPath, [
|
|
268
|
+
...globalHooks,
|
|
269
|
+
...pageHooks,
|
|
270
|
+
]),
|
|
211
271
|
...gatherFieldsMiddlewareFactory({ waypoint, fields }),
|
|
212
|
-
...resolveMiddlewareHooks(
|
|
213
|
-
|
|
214
|
-
|
|
272
|
+
...resolveMiddlewareHooks("journey.postgather", waypointPath, [
|
|
273
|
+
...globalHooks,
|
|
274
|
+
...pageHooks,
|
|
275
|
+
]),
|
|
276
|
+
|
|
277
|
+
...resolveMiddlewareHooks("journey.prevalidate", waypointPath, [
|
|
278
|
+
...globalHooks,
|
|
279
|
+
...pageHooks,
|
|
280
|
+
]),
|
|
215
281
|
...validateFieldsMiddlewareFactory({ waypoint, fields, plan }),
|
|
216
|
-
...resolveMiddlewareHooks(
|
|
282
|
+
...resolveMiddlewareHooks("journey.postvalidate", waypointPath, [
|
|
283
|
+
...globalHooks,
|
|
284
|
+
...pageHooks,
|
|
285
|
+
]),
|
|
217
286
|
|
|
218
287
|
// If there were validation errors, jump out of this route and into the
|
|
219
288
|
// next, where the errors will be rendered
|
|
220
|
-
(req, res, next) =>
|
|
221
|
-
|
|
222
|
-
|
|
289
|
+
(req, res, next) =>
|
|
290
|
+
req.casa.journeyContext.hasValidationErrorsForPage(waypoint)
|
|
291
|
+
? next("route")
|
|
292
|
+
: next(),
|
|
293
|
+
|
|
294
|
+
...resolveMiddlewareHooks("journey.preredirect", waypointPath, [
|
|
295
|
+
...globalHooks,
|
|
296
|
+
...pageHooks,
|
|
297
|
+
]),
|
|
223
298
|
...progressJourneyMiddlewareFactory({ waypoint, plan }),
|
|
224
299
|
);
|
|
225
300
|
|
|
226
301
|
router.post(
|
|
227
302
|
waypointPath,
|
|
228
|
-
...resolveMiddlewareHooks(
|
|
303
|
+
...resolveMiddlewareHooks("journey.prerender", waypointPath, [
|
|
304
|
+
...globalHooks,
|
|
305
|
+
...pageHooks,
|
|
306
|
+
]),
|
|
229
307
|
renderMiddlewareFactory(view, (req) => {
|
|
230
|
-
const errors =
|
|
308
|
+
const errors =
|
|
309
|
+
req.casa.journeyContext.getValidationErrorsForPageByField(waypoint) ??
|
|
310
|
+
Object.create(null);
|
|
231
311
|
|
|
232
312
|
// This is a convenience for the template. The `govukErrorSummary` macro
|
|
233
313
|
// requires the errors be in a particular format, so here we provide our
|
|
@@ -236,7 +316,7 @@ export default function journeyRouter({
|
|
|
236
316
|
// first one is shown.
|
|
237
317
|
// Disabling security/detect-object-injection rule because both `errors`
|
|
238
318
|
// and the `k` property are known entities
|
|
239
|
-
const govukErrors = generateGovukErrors(errors, req)
|
|
319
|
+
const govukErrors = generateGovukErrors(errors, req);
|
|
240
320
|
|
|
241
321
|
return {
|
|
242
322
|
formUrl: waypointUrl({ mountUrl: `${req.baseUrl}/`, waypoint }),
|