@dwp/govuk-casa 7.0.6 → 8.0.0-alpha1
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 +22 -17
- package/dist/{casa → assets}/css/casa-ie8.css +1 -1
- package/dist/assets/css/casa.css +1 -0
- package/dist/casa.d.ts +10 -0
- package/dist/casa.js +44 -0
- package/dist/lib/CasaTemplateLoader.d.ts +19 -0
- package/dist/lib/CasaTemplateLoader.js +57 -0
- package/dist/lib/JourneyContext.d.ts +255 -0
- package/dist/lib/JourneyContext.js +681 -0
- package/dist/lib/MutableRouter.d.ts +155 -0
- package/dist/lib/MutableRouter.js +272 -0
- package/dist/lib/Plan.d.ts +119 -0
- package/dist/lib/Plan.js +382 -0
- package/dist/lib/ValidationError.d.ts +70 -0
- package/dist/lib/ValidationError.js +156 -0
- package/dist/lib/ValidatorFactory.d.ts +24 -0
- package/dist/lib/ValidatorFactory.js +87 -0
- package/dist/lib/configure.d.ts +205 -0
- package/dist/lib/configure.js +215 -0
- package/dist/lib/dirname.cjs +1 -0
- package/dist/lib/end-session.d.ts +12 -0
- package/dist/lib/end-session.js +24 -0
- package/dist/lib/field.d.ts +79 -0
- package/dist/lib/field.js +223 -0
- package/dist/lib/logger.d.ts +8 -0
- package/dist/lib/logger.js +19 -0
- package/dist/lib/nunjucks-filters.d.ts +26 -0
- package/dist/lib/nunjucks-filters.js +112 -0
- package/dist/lib/nunjucks.d.ts +22 -0
- package/dist/lib/nunjucks.js +49 -0
- package/dist/lib/utils.d.ts +22 -0
- package/dist/lib/utils.js +44 -0
- package/dist/lib/validators/dateObject.d.ts +4 -0
- package/dist/lib/validators/dateObject.js +135 -0
- package/dist/lib/validators/email.d.ts +4 -0
- package/dist/lib/validators/email.js +46 -0
- package/dist/lib/validators/inArray.d.ts +4 -0
- package/dist/lib/validators/inArray.js +60 -0
- package/dist/lib/validators/index.d.ts +21 -0
- package/dist/lib/validators/index.js +47 -0
- package/dist/lib/validators/nino.d.ts +4 -0
- package/dist/lib/validators/nino.js +46 -0
- package/dist/lib/validators/postalAddressObject.d.ts +4 -0
- package/dist/lib/validators/postalAddressObject.js +123 -0
- package/dist/lib/validators/regex.d.ts +4 -0
- package/dist/lib/validators/regex.js +40 -0
- package/dist/lib/validators/required.d.ts +4 -0
- package/dist/lib/validators/required.js +56 -0
- package/dist/lib/validators/strlen.d.ts +4 -0
- package/dist/lib/validators/strlen.js +51 -0
- package/dist/lib/validators/wordCount.d.ts +5 -0
- package/dist/lib/validators/wordCount.js +54 -0
- package/dist/lib/waypoint-url.d.ts +17 -0
- package/dist/lib/waypoint-url.js +46 -0
- package/dist/middleware/body-parser.d.ts +1 -0
- package/dist/middleware/body-parser.js +24 -0
- package/dist/middleware/csrf.d.ts +1 -0
- package/dist/middleware/csrf.js +31 -0
- package/dist/middleware/data.d.ts +6 -0
- package/dist/middleware/data.js +53 -0
- package/dist/middleware/dirname.cjs +1 -0
- package/dist/middleware/gather-fields.d.ts +5 -0
- package/dist/middleware/gather-fields.js +39 -0
- package/dist/middleware/i18n.d.ts +4 -0
- package/dist/middleware/i18n.js +87 -0
- package/dist/middleware/post.d.ts +1 -0
- package/dist/middleware/post.js +42 -0
- package/dist/middleware/pre.d.ts +3 -0
- package/dist/middleware/pre.js +38 -0
- package/dist/middleware/progress-journey.d.ts +6 -0
- package/dist/middleware/progress-journey.js +82 -0
- package/dist/middleware/sanitise-fields.d.ts +5 -0
- package/dist/middleware/sanitise-fields.js +48 -0
- package/dist/middleware/session.d.ts +10 -0
- package/dist/middleware/session.js +115 -0
- package/dist/middleware/skip-waypoint.d.ts +5 -0
- package/dist/middleware/skip-waypoint.js +40 -0
- package/dist/middleware/steer-journey.d.ts +6 -0
- package/dist/middleware/steer-journey.js +44 -0
- package/dist/middleware/validate-fields.d.ts +7 -0
- package/dist/middleware/validate-fields.js +76 -0
- package/dist/mjs/esm-wrapper.js +10 -0
- package/dist/mjs/package.json +3 -0
- package/dist/package.json +3 -0
- package/dist/routes/ancillary.d.ts +4 -0
- package/dist/routes/ancillary.js +19 -0
- package/dist/routes/dirname.cjs +1 -0
- package/dist/routes/journey.d.ts +8 -0
- package/dist/routes/journey.js +130 -0
- package/dist/routes/static.d.ts +26 -0
- package/dist/routes/static.js +67 -0
- package/package.json +45 -86
- package/views/casa/components/checkboxes/template.njk +4 -1
- package/views/casa/components/date-input/template.njk +3 -3
- package/views/casa/components/journey-form/README.md +3 -1
- package/views/casa/components/journey-form/template.njk +1 -1
- package/views/casa/components/postal-address-object/template.njk +5 -5
- package/views/casa/components/radios/template.njk +1 -1
- package/views/casa/layouts/journey.njk +26 -9
- package/views/casa/layouts/main.njk +6 -19
- package/views/casa/partials/scripts.njk +8 -3
- package/views/casa/partials/styles.njk +2 -2
- package/casa.js +0 -208
- package/definitions/review-page.js +0 -60
- package/dist/casa/css/casa.css +0 -1
- package/dist/casa/js/casa.js +0 -1
- package/index.d.ts +0 -121
- package/lib/ConfigIngestor.js +0 -588
- package/lib/GatherModifier.js +0 -14
- package/lib/I18n.js +0 -160
- package/lib/JourneyContext.d.ts +0 -97
- package/lib/JourneyContext.js +0 -552
- package/lib/JourneyMap.js +0 -233
- package/lib/JourneyRoad.js +0 -330
- package/lib/Logger.js +0 -59
- package/lib/PageDictionary.d.ts +0 -11
- package/lib/PageDirectory.js +0 -77
- package/lib/Plan.js +0 -423
- package/lib/RoadConverter.js +0 -153
- package/lib/UserJourney.js +0 -8
- package/lib/Util.js +0 -227
- package/lib/Validation.js +0 -20
- package/lib/bootstrap/end-session.js +0 -44
- package/lib/bootstrap/load-definitions.js +0 -64
- package/lib/commonBodyParser.js +0 -15
- package/lib/enums.js +0 -6
- package/lib/gather-modifiers/index.js +0 -7
- package/lib/gather-modifiers/trimPostalAddressObject.js +0 -75
- package/lib/gather-modifiers/trimWhitespace.js +0 -16
- package/lib/utils/createGetRequest.d.ts +0 -5
- package/lib/utils/createGetRequest.js +0 -59
- package/lib/utils/index.js +0 -11
- package/lib/utils/parseRequest.d.ts +0 -5
- package/lib/utils/parseRequest.js +0 -72
- package/lib/utils/sanitise.js +0 -74
- package/lib/utils/validate.js +0 -32
- package/lib/validation/ArrayObjectField.js +0 -49
- package/lib/validation/ObjectField.js +0 -53
- package/lib/validation/SimpleField.d.ts +0 -11
- package/lib/validation/SimpleField.js +0 -46
- package/lib/validation/ValidationError.d.ts +0 -14
- package/lib/validation/ValidationError.js +0 -170
- package/lib/validation/ValidatorFactory.d.ts +0 -32
- package/lib/validation/ValidatorFactory.js +0 -91
- package/lib/validation/index.js +0 -22
- package/lib/validation/processor/flattenErrorArray.js +0 -24
- package/lib/validation/processor/queue.js +0 -214
- package/lib/validation/processor.js +0 -84
- package/lib/validation/rules/README.md +0 -3
- package/lib/validation/rules/ValidationRules.d.ts +0 -22
- package/lib/validation/rules/dateObject.js +0 -156
- package/lib/validation/rules/email.js +0 -44
- package/lib/validation/rules/inArray.js +0 -61
- package/lib/validation/rules/index.js +0 -23
- package/lib/validation/rules/nino.js +0 -48
- package/lib/validation/rules/optional.js +0 -14
- package/lib/validation/rules/postalAddressObject.js +0 -142
- package/lib/validation/rules/regex.js +0 -39
- package/lib/validation/rules/required.js +0 -57
- package/lib/validation/rules/strlen.js +0 -57
- package/lib/validation/rules/wordCount.js +0 -61
- package/lib/view-filters/formatDateObject.js +0 -35
- package/lib/view-filters/includes.js +0 -10
- package/lib/view-filters/index.js +0 -23
- package/lib/view-filters/mergeObjectsDeep.js +0 -21
- package/lib/view-filters/renderAsAttributes.js +0 -33
- package/middleware/errors/404.js +0 -12
- package/middleware/errors/catch-all.js +0 -27
- package/middleware/errors/index.js +0 -9
- package/middleware/headers/config-defaults.js +0 -57
- package/middleware/headers/headers.js +0 -40
- package/middleware/headers/index.js +0 -9
- package/middleware/i18n/i18n.js +0 -56
- package/middleware/i18n/index.js +0 -16
- package/middleware/index.js +0 -55
- package/middleware/mount/index.js +0 -9
- package/middleware/mount/mount.js +0 -10
- package/middleware/nunjucks/environment.js +0 -57
- package/middleware/nunjucks/index.js +0 -8
- package/middleware/page/csrf.js +0 -37
- package/middleware/page/edit-mode.js +0 -52
- package/middleware/page/gather.js +0 -75
- package/middleware/page/index.js +0 -103
- package/middleware/page/journey-continue.js +0 -157
- package/middleware/page/journey-rails.js +0 -102
- package/middleware/page/prepare-request.js +0 -77
- package/middleware/page/render.js +0 -75
- package/middleware/page/skip.js +0 -72
- package/middleware/page/utils.js +0 -206
- package/middleware/page/validate.js +0 -67
- package/middleware/session/expiry.js +0 -95
- package/middleware/session/genid.js +0 -18
- package/middleware/session/index.js +0 -18
- package/middleware/session/init.js +0 -25
- package/middleware/session/seed.js +0 -50
- package/middleware/session/timeout.js +0 -5
- package/middleware/static/asset-versions.js +0 -23
- package/middleware/static/index.js +0 -104
- package/middleware/static/prepare-assets.js +0 -51
- package/middleware/static/serve-assets.js +0 -58
- package/middleware/variables/index.js +0 -12
- package/middleware/variables/variables.js +0 -35
- package/src/browserconfig.xml +0 -5
- package/src/js/casa.js +0 -132
- package/src/scss/_casaElements.scss +0 -11
- package/src/scss/_casaGovukTemplateJinjaPolyfill.scss +0 -39
- package/src/scss/_casaMountUrl.scss +0 -8
- package/src/scss/casa-ie8.scss +0 -3
- package/src/scss/casa.scss +0 -14
- package/test/unit/templates/README.md +0 -5
- package/test/utils/BaseTestWaypoint.js +0 -106
- package/test/utils/concatWaypoints.js +0 -26
- package/test/utils/index.js +0 -6
- package/test/utils/testTraversal.js +0 -90
- package/views/casa/partials/cookie_message.njk +0 -3
- package/views/casa/partials/phase_banner_alpha.njk +0 -8
- package/views/casa/partials/phase_banner_beta.njk +0 -8
- package/views/casa/review/page-block.njk +0 -8
- package/views/casa/review/review.njk +0 -47
package/middleware/i18n/i18n.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configure multi-lingual support.
|
|
3
|
-
*
|
|
4
|
-
* This middleware will determine the language to use for each request, by
|
|
5
|
-
* inspecting the query and existing session.
|
|
6
|
-
*
|
|
7
|
-
* Enhances `req` with:
|
|
8
|
-
* string language = The language code to use (ISO 639-1).
|
|
9
|
-
* Function i18nTranslator = A class instance to translate for the current req.
|
|
10
|
-
*
|
|
11
|
-
* Enhances `req.session` with:
|
|
12
|
-
* string language = The language code to use (ISO 639-1).
|
|
13
|
-
*
|
|
14
|
-
* Enhances `req.casa.journeyContext.nav` with
|
|
15
|
-
* string language = The language code to use (ISO 639-1).
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
module.exports = (logger, supportedLocales = [], translatorFactory) => (req, res, next) => {
|
|
19
|
-
const currentSessionLanguage = (req.session || Object.create(null)).language;
|
|
20
|
-
|
|
21
|
-
// Language pulled from query first, then session, then default
|
|
22
|
-
let language = req.query.lang || currentSessionLanguage || supportedLocales[0];
|
|
23
|
-
if (!supportedLocales.includes(language)) {
|
|
24
|
-
[language] = supportedLocales;
|
|
25
|
-
}
|
|
26
|
-
req.language = language;
|
|
27
|
-
|
|
28
|
-
// Update the journey context
|
|
29
|
-
if (req.casa && req.casa.journeyContext) {
|
|
30
|
-
req.casa.journeyContext.setNavigationLanguage(req.language);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Create usable references to the translation function
|
|
34
|
-
req.i18nTranslator = translatorFactory(req.language);
|
|
35
|
-
res.locals.t = req.i18nTranslator.t.bind(req.i18nTranslator);
|
|
36
|
-
res.locals.locale = req.language;
|
|
37
|
-
|
|
38
|
-
// This is used by the GOVUK layout template
|
|
39
|
-
res.locals.htmlLang = req.language;
|
|
40
|
-
|
|
41
|
-
// When updating the session, we need to explicitly save before sending
|
|
42
|
-
// response because - depending on the session store - this operation may
|
|
43
|
-
// otherwise overlap with subsequent requests from the user.
|
|
44
|
-
if (req.session && req.language !== currentSessionLanguage) {
|
|
45
|
-
req.session.language = req.language;
|
|
46
|
-
logger.debug('saving new language (%s) to session', req.session.language)
|
|
47
|
-
req.session.save((err) => {
|
|
48
|
-
if (err) {
|
|
49
|
-
logger.error('Failed to save language to session. Error: %s', err.message);
|
|
50
|
-
}
|
|
51
|
-
next(err);
|
|
52
|
-
});
|
|
53
|
-
} else {
|
|
54
|
-
next();
|
|
55
|
-
}
|
|
56
|
-
};
|
package/middleware/i18n/index.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const logger = require('../../lib/Logger.js')('i18n');
|
|
2
|
-
|
|
3
|
-
const mwI18n = require('./i18n.js');
|
|
4
|
-
|
|
5
|
-
module.exports = (app, supportedLocales = [], I18nUtility) => {
|
|
6
|
-
if (!Array.isArray(supportedLocales) || !supportedLocales.length) {
|
|
7
|
-
throw new TypeError('At least one supported locale is required');
|
|
8
|
-
}
|
|
9
|
-
if (typeof I18nUtility !== 'object') {
|
|
10
|
-
throw new TypeError('An instance of the I18n utility is required');
|
|
11
|
-
} else if (typeof I18nUtility.Translator !== 'function') {
|
|
12
|
-
throw new TypeError('Provided I18n utility is an invalid type');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
app.use(mwI18n(logger, supportedLocales, (lang) => (new I18nUtility.Translator(lang))));
|
|
16
|
-
};
|
package/middleware/index.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
const errors = require('./errors/index.js');
|
|
2
|
-
const errors404 = require('./errors/404.js');
|
|
3
|
-
const errorsCatchAll = require('./errors/catch-all.js');
|
|
4
|
-
|
|
5
|
-
const headers = require('./headers/index.js');
|
|
6
|
-
const headersApply = require('./headers/headers.js');
|
|
7
|
-
|
|
8
|
-
const i18n = require('./i18n/index.js');
|
|
9
|
-
const i18nSetLanguage = require('./i18n/i18n.js');
|
|
10
|
-
|
|
11
|
-
const mount = require('./mount/index.js');
|
|
12
|
-
const mountRedirect = require('./mount/mount.js');
|
|
13
|
-
|
|
14
|
-
const nunjucks = require('./nunjucks/index.js');
|
|
15
|
-
const nunjucksEnvironment = require('./nunjucks/environment.js');
|
|
16
|
-
|
|
17
|
-
const page = require('./page/index.js');
|
|
18
|
-
const pageCsrf = require('./page/csrf.js');
|
|
19
|
-
const pageEditMode = require('./page/edit-mode.js');
|
|
20
|
-
const pageGather = require('./page/gather.js');
|
|
21
|
-
const pageJourneyContinue = require('./page/journey-continue.js');
|
|
22
|
-
const pageJourneyRails = require('./page/journey-rails.js');
|
|
23
|
-
const pagePrepareRequest = require('./page/prepare-request.js');
|
|
24
|
-
const pageRender = require('./page/render.js');
|
|
25
|
-
const pageSkip = require('./page/skip.js');
|
|
26
|
-
const pageValidate = require('./page/validate.js');
|
|
27
|
-
|
|
28
|
-
module.exports = {
|
|
29
|
-
errors,
|
|
30
|
-
errors404,
|
|
31
|
-
errorsCatchAll,
|
|
32
|
-
|
|
33
|
-
headers,
|
|
34
|
-
headersApply,
|
|
35
|
-
|
|
36
|
-
i18n,
|
|
37
|
-
i18nSetLanguage,
|
|
38
|
-
|
|
39
|
-
mount,
|
|
40
|
-
mountRedirect,
|
|
41
|
-
|
|
42
|
-
nunjucks,
|
|
43
|
-
nunjucksEnvironment,
|
|
44
|
-
|
|
45
|
-
page,
|
|
46
|
-
pageCsrf,
|
|
47
|
-
pageEditMode,
|
|
48
|
-
pageGather,
|
|
49
|
-
pageJourneyContinue,
|
|
50
|
-
pageJourneyRails,
|
|
51
|
-
pagePrepareRequest,
|
|
52
|
-
pageRender,
|
|
53
|
-
pageSkip,
|
|
54
|
-
pageValidate,
|
|
55
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
const logger = require('../../lib/Logger.js')('journey');
|
|
2
|
-
const mwMount = require('./mount.js');
|
|
3
|
-
|
|
4
|
-
module.exports = (app, mountUrl = '/') => {
|
|
5
|
-
if (mountUrl !== '/') {
|
|
6
|
-
logger.info('Attaching mount redirection for %s', mountUrl);
|
|
7
|
-
app.all('/', mwMount(logger, mountUrl));
|
|
8
|
-
}
|
|
9
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Redirect all requests to the configured mount point. This should only be
|
|
3
|
-
* added to the `/` route, and only when a mount url other than "/" is
|
|
4
|
-
* configured.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
module.exports = (logger, mountUrl) => (req, res) => {
|
|
8
|
-
logger.trace('Redirecting to mountUrl %s', mountUrl);
|
|
9
|
-
res.status(302).redirect(mountUrl);
|
|
10
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configures view template engine (Nunjucks). Note that we do not set a
|
|
3
|
-
* specific `view engine` setting, preferring to use explicit template file
|
|
4
|
-
* extensions instead.
|
|
5
|
-
*
|
|
6
|
-
* This creates a `render()` method on the HTTP response object. To render a
|
|
7
|
-
* template, `res.render('name-of-template', varsObject)`.
|
|
8
|
-
*
|
|
9
|
-
* Enhances `res` with:
|
|
10
|
-
* function render = Function to render and return a template response
|
|
11
|
-
* Environment nunjucksEnvironment = Nunjucks environment for this request.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const nunjucks = require('nunjucks');
|
|
15
|
-
const path = require('path');
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* `govukFrontendDir` must be the path to the layout template file template.njk
|
|
19
|
-
* which would typically be passed in from the result of:
|
|
20
|
-
* require.resolve('govuk-frontend')
|
|
21
|
-
*
|
|
22
|
-
* @param {object} logger Logger.
|
|
23
|
-
* @param {Function} app Express app.
|
|
24
|
-
* @param {Array} viewDirs List of view directories to register with Nunjucks.
|
|
25
|
-
* @param {string} govukFrontendDir Path to `govuk-frontend` module.
|
|
26
|
-
* @returns {nunjucks.Environment} Configured environment.
|
|
27
|
-
*/
|
|
28
|
-
module.exports = (logger, app, viewDirs = [], govukFrontendDir = '') => {
|
|
29
|
-
// Resolve all application template search paths, and add CASA-specific dirs.
|
|
30
|
-
// Resolove priority: userland template > CASA templates > GOVUK templates
|
|
31
|
-
const dirViews = viewDirs.map((dir) => path.resolve(dir)).concat([
|
|
32
|
-
path.resolve(__dirname, '..', '..', 'views'),
|
|
33
|
-
path.resolve(govukFrontendDir),
|
|
34
|
-
]);
|
|
35
|
-
|
|
36
|
-
// Prepare a single Nunjucks environment for all responses to use. Note that
|
|
37
|
-
// we cannot prepare response-specific global functions/filters if we use a
|
|
38
|
-
// single environment, but the performance gains of doing so are significant.
|
|
39
|
-
const loader = new nunjucks.FileSystemLoader(dirViews, {
|
|
40
|
-
watch: false,
|
|
41
|
-
noCache: false,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const env = new nunjucks.Environment(loader, {
|
|
45
|
-
autoescape: true,
|
|
46
|
-
throwOnUndefined: false,
|
|
47
|
-
trimBlocks: false,
|
|
48
|
-
lstripBlocks: false,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Apply Nunjucks to Express and set as the default rendering engine
|
|
52
|
-
env.express(app);
|
|
53
|
-
app.set('view engine', 'njk');
|
|
54
|
-
|
|
55
|
-
logger.info('Nunjucks configured');
|
|
56
|
-
return env;
|
|
57
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
const logger = require('../../lib/Logger.js')('nunjucks');
|
|
2
|
-
const mwEnvironment = require('./environment.js');
|
|
3
|
-
const loadViewFilters = require('../../lib/view-filters/index.js');
|
|
4
|
-
|
|
5
|
-
module.exports = (app, viewDirs = [], govukFrontendDir = '') => {
|
|
6
|
-
const env = mwEnvironment(logger, app, viewDirs, govukFrontendDir);
|
|
7
|
-
loadViewFilters(env);
|
|
8
|
-
}
|
package/middleware/page/csrf.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate CSRF protection to use on all mutating (POST) requests. The
|
|
3
|
-
* `csrfSupplyToken` function will make the current token available to views
|
|
4
|
-
* via the `casa.csrfToken` variable, which you can use as so:
|
|
5
|
-
* <input type="hidden" name="_csrf" value="{{ casa.csrfToken }}">.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const csrf = require('csurf');
|
|
9
|
-
const commonBodyParser = require('../../lib/commonBodyParser.js');
|
|
10
|
-
|
|
11
|
-
const mwCsrfProtection = csrf({
|
|
12
|
-
cookie: false,
|
|
13
|
-
sessionKey: 'session',
|
|
14
|
-
value: (req) => {
|
|
15
|
-
/* eslint-disable no-underscore-dangle */
|
|
16
|
-
// Here we clear the token after extracting to maintain cleaner data. It
|
|
17
|
-
// is only used for this CSRF purpose.
|
|
18
|
-
const token = String(req.body._csrf);
|
|
19
|
-
delete req.body._csrf;
|
|
20
|
-
return token;
|
|
21
|
-
/* eslint-enable no-underscore-dangle */
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const mwCsrfSupplyToken = (req, res, next) => {
|
|
26
|
-
res.locals.casa.csrfToken = req.csrfToken();
|
|
27
|
-
next();
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// All of these middleware are required to run in this sequence, so for
|
|
31
|
-
// convenience they are returned as an array so they can be added to Express
|
|
32
|
-
// middleware chain as one entity.
|
|
33
|
-
module.exports = [
|
|
34
|
-
commonBodyParser,
|
|
35
|
-
mwCsrfProtection,
|
|
36
|
-
mwCsrfSupplyToken,
|
|
37
|
-
];
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Set `req.inEditMode`, `req.editOriginUrl`, and `req.editSearchParams`
|
|
3
|
-
* attributes.
|
|
4
|
-
*
|
|
5
|
-
* Note `req.{query|body}.*` are all uri-decoded prior to this point.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { createGetRequest, parseRequest } = require('../../lib/utils/index.js');
|
|
9
|
-
const logger = require('../../lib/Logger')('page.edit-mode');
|
|
10
|
-
|
|
11
|
-
module.exports = (mountUrl, allowPageEdit) => (req, res, next) => {
|
|
12
|
-
// Parse the request
|
|
13
|
-
const request = parseRequest(req);
|
|
14
|
-
const defaultEditOrigin = createGetRequest({
|
|
15
|
-
mountUrl,
|
|
16
|
-
...request,
|
|
17
|
-
editMode: false,
|
|
18
|
-
editOrigin: '',
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// Store edit information on request
|
|
22
|
-
req.editOriginUrl = allowPageEdit ? (request.editOrigin || defaultEditOrigin) : '';
|
|
23
|
-
req.inEditMode = allowPageEdit && request.editMode;
|
|
24
|
-
logger.trace('Set edit mode: %s (origin = %s)', req.inEditMode, req.editOriginUrl);
|
|
25
|
-
|
|
26
|
-
// Create a urlencoded string of the parameters for use in custom URLs
|
|
27
|
-
req.editSearchParams = req.inEditMode ? createGetRequest({
|
|
28
|
-
...request,
|
|
29
|
-
mountUrl: undefined,
|
|
30
|
-
waypoint: undefined,
|
|
31
|
-
editMode: req.inEditMode,
|
|
32
|
-
editOrigin: req.editOriginUrl,
|
|
33
|
-
}) : '';
|
|
34
|
-
|
|
35
|
-
// Clean up
|
|
36
|
-
// We're no longer interested in these parameters, so declutter
|
|
37
|
-
if (req.query && 'edit' in req.query) {
|
|
38
|
-
delete req.query.edit;
|
|
39
|
-
}
|
|
40
|
-
if (req.body && 'edit' in req.body) {
|
|
41
|
-
delete req.body.edit;
|
|
42
|
-
}
|
|
43
|
-
if (req.query && 'editorigin' in req.query) {
|
|
44
|
-
delete req.query.editorigin;
|
|
45
|
-
}
|
|
46
|
-
if (req.body && 'editorigin' in req.body) {
|
|
47
|
-
delete req.body.editorigin;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Next middleware
|
|
51
|
-
next();
|
|
52
|
-
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
const commonBodyParser = require('../../lib/commonBodyParser.js');
|
|
2
|
-
const createLogger = require('../../lib/Logger.js');
|
|
3
|
-
const JourneyContext = require('../../lib/JourneyContext.js');
|
|
4
|
-
const { executeHook, extractSessionableData, runGatherModifiers } = require('./utils.js');
|
|
5
|
-
|
|
6
|
-
module.exports = (pageMeta = {}) => [commonBodyParser, (req, res, next) => {
|
|
7
|
-
const logger = createLogger('page.gather');
|
|
8
|
-
logger.setSessionId(req.session.id);
|
|
9
|
-
|
|
10
|
-
req.casa = req.casa || Object.create(null);
|
|
11
|
-
|
|
12
|
-
const pageId = pageMeta.id;
|
|
13
|
-
const { journeyOrigin, plan: journey } = req.casa;
|
|
14
|
-
|
|
15
|
-
// Take a traversal snapshot of the journey before we mutate the data/error
|
|
16
|
-
// context
|
|
17
|
-
logger.trace('Take pre-gather traversal snapshot');
|
|
18
|
-
req.casa.preGatherTraversalSnapshot = journey.traverse(req.casa.journeyContext, {
|
|
19
|
-
startWaypoint: journeyOrigin.waypoint,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Store data in request, clearing validation flags prior to validation.
|
|
24
|
-
*
|
|
25
|
-
* @param {object} data Data to store.
|
|
26
|
-
* @returns {void}
|
|
27
|
-
*/
|
|
28
|
-
function storeSessionData(data) {
|
|
29
|
-
// Store gathered journey data, and clear any cached validation state for
|
|
30
|
-
// the page. Removing the validation state will prevent onward traversal
|
|
31
|
-
// from this page unil its new content has been validated (by the next
|
|
32
|
-
// middleware in the chain).
|
|
33
|
-
logger.trace('Storing session data for %s', pageId);
|
|
34
|
-
req.casa.journeyContext.setDataForPage(pageMeta, data);
|
|
35
|
-
req.casa.journeyContext.removeValidationStateForPage(pageId);
|
|
36
|
-
JourneyContext.putContext(req.session, req.casa.journeyContext);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Promise
|
|
40
|
-
return executeHook(logger, req, res, pageMeta, 'pregather')
|
|
41
|
-
.then(() => {
|
|
42
|
-
// Only data that has matching validators defined in the page meta will be
|
|
43
|
-
// gathered and stored in the session
|
|
44
|
-
const preparedData = extractSessionableData(
|
|
45
|
-
logger,
|
|
46
|
-
pageMeta,
|
|
47
|
-
req.body,
|
|
48
|
-
req.casa.journeyContext,
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
// Run this page's "gather modifiers" against each prepared data item
|
|
52
|
-
if (Object.prototype.toString.call(pageMeta.fieldGatherModifiers) === '[object Object]') {
|
|
53
|
-
Object.keys(pageMeta.fieldGatherModifiers).forEach((fieldName) => {
|
|
54
|
-
logger.trace('Run gather-modifier for field %s on waypoint %s', fieldName, pageId);
|
|
55
|
-
const modifiedValue = runGatherModifiers(
|
|
56
|
-
preparedData[fieldName],
|
|
57
|
-
pageMeta.fieldGatherModifiers[fieldName],
|
|
58
|
-
);
|
|
59
|
-
preparedData[fieldName] = modifiedValue;
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Store all modified data back to req.body so downstream handlers have
|
|
64
|
-
// access to the modified data.
|
|
65
|
-
req.body = Object.assign(Object.create(null), req.body, preparedData);
|
|
66
|
-
return preparedData;
|
|
67
|
-
})
|
|
68
|
-
.then((modifiedData) => (storeSessionData(modifiedData)))
|
|
69
|
-
.then(() => {
|
|
70
|
-
next();
|
|
71
|
-
})
|
|
72
|
-
.catch((err) => {
|
|
73
|
-
next(err);
|
|
74
|
-
});
|
|
75
|
-
}]
|
package/middleware/page/index.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default Page route.
|
|
3
|
-
*
|
|
4
|
-
* The logic in this route caters for 95% of use cases in this data-gathering
|
|
5
|
-
* application. However, to there are a few options available that will allow
|
|
6
|
-
* you to override or thread page-specific logic with this default behaviour if
|
|
7
|
-
* needed:
|
|
8
|
-
*
|
|
9
|
-
* "Hooks":
|
|
10
|
-
* --------
|
|
11
|
-
* Most pages follow the "gather > save > validate > render" pathway, but might
|
|
12
|
-
* need to do something a little different at stages in that pathway. Hooks can
|
|
13
|
-
* be used to achieve this. Define hooks in the page meta object, e.g:
|
|
14
|
-
* pages['my-page'] = {
|
|
15
|
-
* hooks: {
|
|
16
|
-
* pregather: function(req, res, next) {},
|
|
17
|
-
* postvalidate: function(req, res, next) {},
|
|
18
|
-
* prerender: function(req, res, next) {}.
|
|
19
|
-
* }.
|
|
20
|
-
* }.
|
|
21
|
-
*
|
|
22
|
-
* The `next()` function takes an optional error object containing an array of
|
|
23
|
-
* errors for each field, e.g:
|
|
24
|
-
* next({
|
|
25
|
-
* <fieldName>: [{inline: '...', summary: '...'}, ...],
|
|
26
|
-
* ...
|
|
27
|
-
* }).
|
|
28
|
-
*
|
|
29
|
-
* "Override":
|
|
30
|
-
* -----------
|
|
31
|
-
* To completely override the behaviour of a POST or GET route, define
|
|
32
|
-
* appropriate handlers in the page's meta object. E.g:
|
|
33
|
-
* pages['my-page'] = {
|
|
34
|
-
* handlers: {
|
|
35
|
-
* get: function(req, res, next) {},
|
|
36
|
-
* post: function(req, res, next) {}
|
|
37
|
-
* }
|
|
38
|
-
* };.
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
const mwBodyParser = require('../../lib/commonBodyParser.js');
|
|
42
|
-
const mwPrepare = require('./prepare-request.js');
|
|
43
|
-
const mwSkip = require('./skip.js');
|
|
44
|
-
const mwJourneyRails = require('./journey-rails.js');
|
|
45
|
-
const mwJourneyContinue = require('./journey-continue.js');
|
|
46
|
-
const mwCsrfProtection = require('./csrf.js');
|
|
47
|
-
const mwDetectEditMode = require('./edit-mode.js');
|
|
48
|
-
const mwGatherData = require('./gather.js');
|
|
49
|
-
const mwValidateData = require('./validate.js');
|
|
50
|
-
const mwRenderPage = require('./render.js');
|
|
51
|
-
|
|
52
|
-
module.exports = function routePages(
|
|
53
|
-
mountUrl,
|
|
54
|
-
router,
|
|
55
|
-
pages,
|
|
56
|
-
plan,
|
|
57
|
-
allowPageEdit,
|
|
58
|
-
useStickyEdit,
|
|
59
|
-
) {
|
|
60
|
-
const pageMetaKeys = pages.getAllPageIds();
|
|
61
|
-
const origins = plan.getOrigins();
|
|
62
|
-
|
|
63
|
-
// If there's only one origin waypoint, we won't bother prefixing urls with the
|
|
64
|
-
// origin id
|
|
65
|
-
let routePrefix = '/';
|
|
66
|
-
if (!origins.length) {
|
|
67
|
-
throw new ReferenceError('No origin waypoints have been defined. Cannot start plan traversal.');
|
|
68
|
-
} else if (origins.length > 1) {
|
|
69
|
-
routePrefix = `/(${origins.map((o) => o.originId).join('|')})`;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
plan.getWaypoints().filter((w) => pageMetaKeys.includes(w)).forEach((waypoint) => {
|
|
73
|
-
const routeUrl = new RegExp(`^${routePrefix}/${waypoint}$`.replace(/\/+/g, '/'));
|
|
74
|
-
const pageMeta = pages.getPageMeta(waypoint);
|
|
75
|
-
|
|
76
|
-
router.get(
|
|
77
|
-
routeUrl,
|
|
78
|
-
mwBodyParser,
|
|
79
|
-
mwPrepare(mountUrl, plan),
|
|
80
|
-
mwDetectEditMode(mountUrl, allowPageEdit),
|
|
81
|
-
mwJourneyRails(mountUrl, plan),
|
|
82
|
-
mwCsrfProtection,
|
|
83
|
-
mwSkip(mountUrl),
|
|
84
|
-
// TODO: Maybe put the hook executions at this level? e.g.
|
|
85
|
-
// mwExecutePageHooks(pageMeta, 'prerender')
|
|
86
|
-
// because then custom routes could choose to include them or not
|
|
87
|
-
mwRenderPage(pageMeta),
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
router.post(
|
|
91
|
-
routeUrl,
|
|
92
|
-
mwBodyParser,
|
|
93
|
-
mwPrepare(mountUrl, plan),
|
|
94
|
-
mwDetectEditMode(mountUrl, allowPageEdit),
|
|
95
|
-
mwJourneyRails(mountUrl, plan),
|
|
96
|
-
mwCsrfProtection,
|
|
97
|
-
mwGatherData(pageMeta),
|
|
98
|
-
mwValidateData(pageMeta),
|
|
99
|
-
mwJourneyContinue(pageMeta, mountUrl, useStickyEdit),
|
|
100
|
-
mwRenderPage(pageMeta),
|
|
101
|
-
);
|
|
102
|
-
});
|
|
103
|
-
};
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
const createLogger = require('../../lib/Logger.js');
|
|
2
|
-
const { executeHook } = require('./utils.js');
|
|
3
|
-
const { parseRequest, createGetRequest } = require('../../lib/utils/index.js');
|
|
4
|
-
|
|
5
|
-
module.exports = (pageMeta = {}, mountUrl = '/', useStickyEdit = false) => (req, res, next) => {
|
|
6
|
-
const logger = createLogger('page.journey-continue');
|
|
7
|
-
logger.setSessionId(req.session.id);
|
|
8
|
-
const pageId = pageMeta.id;
|
|
9
|
-
|
|
10
|
-
req.casa = req.casa || Object.create(null);
|
|
11
|
-
|
|
12
|
-
// If the page has errors, traversal must stop here until those errors are
|
|
13
|
-
// resolved. It is the responsibility of the next middleware to deal with
|
|
14
|
-
// these errors (usually `middleware/page/render.js`)
|
|
15
|
-
if (req.casa.journeyContext.hasValidationErrorsForPage(pageId)) {
|
|
16
|
-
logger.trace('Page %s has errors, not progressing journey. Passthrough to next middleware', pageId);
|
|
17
|
-
return next();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const { journeyOrigin, plan: journey } = req.casa;
|
|
21
|
-
|
|
22
|
-
const commonRedirectAttributes = {
|
|
23
|
-
// undefined because we're including the mountUrl in the waypoint portion of the request builder
|
|
24
|
-
mountUrl: undefined,
|
|
25
|
-
editOrigin: req.editOriginUrl,
|
|
26
|
-
contextId: req.casa.journeyContext.identity.id,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
function calculateNextWaypoint() {
|
|
30
|
-
let nextWaypoint;
|
|
31
|
-
|
|
32
|
-
if (req.inEditMode) {
|
|
33
|
-
// Extract just the waypoint portion of the editOriginUrl, for comparison
|
|
34
|
-
// to waypoint during traversal. This will include the mountUrl.
|
|
35
|
-
const editOriginWaypoint = req.inEditMode && req.editOriginUrl ? `/${parseRequest({
|
|
36
|
-
method: req.method,
|
|
37
|
-
url: req.editOriginUrl,
|
|
38
|
-
query: {},
|
|
39
|
-
body: {},
|
|
40
|
-
}).waypoint}` : '';
|
|
41
|
-
|
|
42
|
-
// When in edit mode, the user should be redirected back to
|
|
43
|
-
// `req.editOriginUrl` after submitting their update unless - due to the
|
|
44
|
-
// journey data being altered - the waypoints along the journey have
|
|
45
|
-
// changed. If the user hasn't yet reached the edit origin url, the
|
|
46
|
-
// 'rails' middleware will ensure they are redirected back to the
|
|
47
|
-
// correct next waypoint.
|
|
48
|
-
let nextOrigin = journeyOrigin.originId || '';
|
|
49
|
-
nextWaypoint = editOriginWaypoint;
|
|
50
|
-
logger.trace('Comparing pre-gather traversal snapshot (starting from origin %s)', nextOrigin);
|
|
51
|
-
|
|
52
|
-
// Grab the list of traversed waypoints as it was before gathering, and
|
|
53
|
-
// generate a new list of traversed waypoints based on the new context.
|
|
54
|
-
const { preGatherTraversalSnapshot = [] } = req.casa || Object.create(null);
|
|
55
|
-
const currentTraversalSnapshot = journey.traverseNextRoutes(req.casa.journeyContext, {
|
|
56
|
-
startWaypoint: journeyOrigin.waypoint,
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Compare the two snapshots. Some rules:
|
|
60
|
-
// `a, b, c` vs `a, b, x, c` <- should stop at `x` (`x` was inserted) <- [..++..]
|
|
61
|
-
// `a, b, c, d` vs `a, b, d` <- should stop at `d` (`c` was removed) <- [..-.]
|
|
62
|
-
// `a, b, c, d` vs `a, c, d` <- should stop at `d` (`b` was removed) <- [.-..]
|
|
63
|
-
// `a, b, c` vs `a, c, d` <- should stop at `d` (`b` was removed, `d` was added) <- [.-..+]
|
|
64
|
-
let compareIndex = 0;
|
|
65
|
-
const compareIndexMax = preGatherTraversalSnapshot.length - 1;
|
|
66
|
-
for (let i = 0, l = currentTraversalSnapshot.length; i < l; i++) {
|
|
67
|
-
// Build waypoint URL for the current waypoint
|
|
68
|
-
const waypointUrl = `${mountUrl}/${currentTraversalSnapshot[i].label.sourceOrigin || nextOrigin}/${currentTraversalSnapshot[i].source}`.replace(/\/+/g, '/');
|
|
69
|
-
|
|
70
|
-
// Stop testing if we've arrived at the edit origin waypoint
|
|
71
|
-
if (editOriginWaypoint === waypointUrl) {
|
|
72
|
-
nextWaypoint = editOriginWaypoint;
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Find a match for the current waypoint in the previous snapshot.
|
|
77
|
-
// And track a change in origin, assuming that all subsequent matches
|
|
78
|
-
// (until the next change of origin) are accessed from that origin.
|
|
79
|
-
while (compareIndex <= compareIndexMax) {
|
|
80
|
-
nextWaypoint = waypointUrl;
|
|
81
|
-
nextOrigin = currentTraversalSnapshot[i].label.targetOrigin || nextOrigin;
|
|
82
|
-
if (currentTraversalSnapshot[i].source === preGatherTraversalSnapshot[compareIndex++]) {
|
|
83
|
-
// The current snapshot may include more waypoints than than the
|
|
84
|
-
// previous. In this case, if we've exhausted the list of previous
|
|
85
|
-
// waypoints, with the last one being a match, we must leave the user on
|
|
86
|
-
// the next waypoint in the current snapshot. Otherwise, the user will
|
|
87
|
-
// be left on the same after submitting the form.
|
|
88
|
-
if ((compareIndex > compareIndexMax) && (i < l - 1)) {
|
|
89
|
-
nextWaypoint = `${mountUrl}/${nextOrigin}/${currentTraversalSnapshot[i + 1].source}`.replace(/\/+/g, '/');
|
|
90
|
-
nextOrigin = currentTraversalSnapshot[i + 1].label.targetOrigin || nextOrigin;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Ensure the user remains in edit mode after redirecting, unless they're
|
|
99
|
-
// being sent back to the edit origin anyway
|
|
100
|
-
nextWaypoint = createGetRequest({
|
|
101
|
-
...commonRedirectAttributes,
|
|
102
|
-
waypoint: nextWaypoint,
|
|
103
|
-
editMode: useStickyEdit && nextWaypoint !== editOriginWaypoint,
|
|
104
|
-
});
|
|
105
|
-
} else if (journey.containsWaypoint(pageId)) {
|
|
106
|
-
logger.trace('Check waypoint %s can be reached (journey guid = %s)', pageId, journeyOrigin.originId);
|
|
107
|
-
const routes = journey.traverseNextRoutes(req.casa.journeyContext, {
|
|
108
|
-
startWaypoint: journeyOrigin.waypoint,
|
|
109
|
-
});
|
|
110
|
-
const waypoints = routes.map((e) => e.source);
|
|
111
|
-
|
|
112
|
-
const positionInJourney = Math.min(
|
|
113
|
-
waypoints.indexOf(pageId),
|
|
114
|
-
waypoints.length - 2,
|
|
115
|
-
);
|
|
116
|
-
if (positionInJourney > -1) {
|
|
117
|
-
const route = routes[positionInJourney];
|
|
118
|
-
nextWaypoint = `${mountUrl}/${route.label.targetOrigin || journeyOrigin.originId || ''}/${waypoints[positionInJourney + 1]}`.replace(/\/+/g, '/');
|
|
119
|
-
} else {
|
|
120
|
-
nextWaypoint = req.originalUrl;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
nextWaypoint = createGetRequest({
|
|
124
|
-
...commonRedirectAttributes,
|
|
125
|
-
waypoint: nextWaypoint,
|
|
126
|
-
editMode: false,
|
|
127
|
-
});
|
|
128
|
-
} else {
|
|
129
|
-
logger.trace('Waypoint %s not in journey %s. Returning to original url', pageId, journeyOrigin.originId);
|
|
130
|
-
nextWaypoint = req.originalUrl;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return nextWaypoint;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function redirect(url) {
|
|
137
|
-
// Because the hash fragment persists over a redirect, we reset it here.
|
|
138
|
-
// Session does not reliably persist when issuing a redirect, so here we
|
|
139
|
-
// save explicitly.
|
|
140
|
-
req.session.save((err) => {
|
|
141
|
-
if (err) {
|
|
142
|
-
logger.error('Failed to save session prior to redirect. %s', err.message);
|
|
143
|
-
next(err);
|
|
144
|
-
} else {
|
|
145
|
-
logger.trace('Redirect: %s -> %s', pageId, url);
|
|
146
|
-
res.status(302).redirect(`${url}#`);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return executeHook(logger, req, res, pageMeta, 'preredirect')
|
|
152
|
-
.then(calculateNextWaypoint)
|
|
153
|
-
.then(redirect)
|
|
154
|
-
.catch((err) => {
|
|
155
|
-
next(err);
|
|
156
|
-
});
|
|
157
|
-
}
|