diff --git a/src/server/plugins/engine/options.js b/src/server/plugins/engine/options.js index 41d8bce44..768d73a22 100644 --- a/src/server/plugins/engine/options.js +++ b/src/server/plugins/engine/options.js @@ -26,7 +26,8 @@ const pluginRegistrationOptionsSchema = Joi.object({ saveAndExit: Joi.function().optional(), ordnanceSurveyApiKey: Joi.string().optional(), ordnanceSurveyApiSecret: Joi.string().optional(), - getLanguage: Joi.function().optional() + getLanguage: Joi.function().optional(), + generateReferenceNumber: Joi.function().optional() }) /** diff --git a/src/server/plugins/engine/plugin.ts b/src/server/plugins/engine/plugin.ts index 941f63bd6..ca56fc050 100644 --- a/src/server/plugins/engine/plugin.ts +++ b/src/server/plugins/engine/plugin.ts @@ -8,6 +8,7 @@ import { import { type FormModel } from '~/src/server/plugins/engine/models/index.js' import { validatePluginOptions } from '~/src/server/plugins/engine/options.js' +import { generateUniqueReference } from '~/src/server/plugins/engine/referenceNumbers.js' import { getRoutes as getFileUploadStatusRoutes } from '~/src/server/plugins/engine/routes/file-upload.js' import { makeLoadFormPreHandler } from '~/src/server/plugins/engine/routes/index.js' import { getRoutes as getPaymentRoutes } from '~/src/server/plugins/engine/routes/payment.js' @@ -37,6 +38,7 @@ export const plugin = { cache, saveAndExit, getLanguage, + generateReferenceNumber, nunjucks: nunjucksOptions, viewContext, preparePageEventRequestOptions, @@ -80,6 +82,10 @@ export const plugin = { server.expose('cacheService', cacheService) server.expose('saveAndExit', saveAndExit) server.expose('getLanguage', getLanguage) + server.expose( + 'generateReferenceNumber', + generateReferenceNumber ?? generateUniqueReference + ) server.expose('baseUrl', baseUrl) server.expose('services', services) diff --git a/src/server/plugins/engine/referenceNumbers.ts b/src/server/plugins/engine/referenceNumbers.ts index 2b4fde674..b7653916c 100644 --- a/src/server/plugins/engine/referenceNumbers.ts +++ b/src/server/plugins/engine/referenceNumbers.ts @@ -6,6 +6,8 @@ import { englishRecommendedTransformers } from 'obscenity' +export const DEFAULT_REFERENCE_NUMBER = 'XXX-XXX-XXX' + /** * To prevent confusion to users reading the reference number, ambiguous letters and numbers are removed. * @param strCodes - array of binary input values diff --git a/src/server/plugins/engine/routes/index.ts b/src/server/plugins/engine/routes/index.ts index e39d5e555..a17d34cf8 100644 --- a/src/server/plugins/engine/routes/index.ts +++ b/src/server/plugins/engine/routes/index.ts @@ -20,6 +20,7 @@ import { findPage, getCacheService, getPage, + getPluginOptions, getStartPath, proceed } from '~/src/server/plugins/engine/helpers.js' @@ -28,7 +29,7 @@ import { checkSaveAndExitRepeater, copyNotYetValidatedState } from '~/src/server/plugins/engine/pageControllers/helpers/state.js' -import { generateUniqueReference } from '~/src/server/plugins/engine/referenceNumbers.js' +import { DEFAULT_REFERENCE_NUMBER } from '~/src/server/plugins/engine/referenceNumbers.js' import * as defaultServices from '~/src/server/plugins/engine/services/index.js' import { type AnyFormRequest, @@ -54,7 +55,7 @@ export async function redirectOrMakeHandler( context: FormContext ) => ResponseObject | Promise ) { - const { app, params } = request + const { app, params, query } = request const { model } = app if (!model) { @@ -74,7 +75,12 @@ export async function redirectOrMakeHandler( ) } - const referenceNumber = generateUniqueReference(prefix) + const isForce = 'force' in query + const { generateReferenceNumber } = getPluginOptions(request.server) + const referenceNumber = isForce + ? DEFAULT_REFERENCE_NUMBER + : await generateReferenceNumber(prefix) + state = await page.mergeState(request, state, { $$__referenceNumber: referenceNumber }) diff --git a/src/server/plugins/engine/types.ts b/src/server/plugins/engine/types.ts index 76a96349c..b4eea4b95 100644 --- a/src/server/plugins/engine/types.ts +++ b/src/server/plugins/engine/types.ts @@ -483,6 +483,10 @@ export type SaveAndExitHandler = ( export type GetLanguageHandler = (query?: RequestQuery, yar?: Yar) => string +export type GenerateReferenceNumberHandler = ( + prefix?: string +) => Promise + export interface ExternalArgs { component: ComponentDef controller: QuestionPageController @@ -523,6 +527,7 @@ export interface PluginOptions { preparePageEventRequestOptions?: PreparePageEventRequestOptions onRequest?: OnRequestCallback getLanguage?: GetLanguageHandler + generateReferenceNumber?: GenerateReferenceNumberHandler baseUrl: string // base URL of the application, protocol and hostname e.g. "https://myapp.com" ordnanceSurveyApiKey?: string ordnanceSurveyApiSecret?: string diff --git a/src/typings/hapi/index.d.ts b/src/typings/hapi/index.d.ts index e61d5c32f..2cecea6f3 100644 --- a/src/typings/hapi/index.d.ts +++ b/src/typings/hapi/index.d.ts @@ -11,6 +11,7 @@ import { type FormModel } from '~/src/server/plugins/engine/models/index.js' import { type AnyFormRequest, type FormSubmissionError, + type GenerateReferenceNumberHandler, type PluginOptions } from '~/src/server/plugins/engine/types.ts' import { type CacheService } from '~/src/server/services/index.js' @@ -41,6 +42,7 @@ declare module '@hapi/hapi' { getLanguage?: PluginOptions['getLanguage'] baseUrl: string services: PluginOptions['services'] + generateReferenceNumber: GenerateReferenceNumberHandler } } diff --git a/test/form/postcode-lookup.test.js b/test/form/postcode-lookup.test.js index c92de22e2..d05f24373 100644 --- a/test/form/postcode-lookup.test.js +++ b/test/form/postcode-lookup.test.js @@ -72,7 +72,8 @@ describe('Postcode lookup form pages', () => { getFlash: jest.fn().mockReturnValue(undefined), setFlash: jest.fn() }, - saveAndExit: undefined + saveAndExit: undefined, + generateReferenceNumber: jest.fn().mockReturnValue('XXX-XXX-XXX') }) })