Skip to content

Commit 09e3063

Browse files
authored
fix/df-789: Fixed guards + plugin bump (#1238)
* Fixed guards + plugin bump * No need for guard here * Amended comments/methodNames as per review suggestions
1 parent 4b53924 commit 09e3063

8 files changed

Lines changed: 83 additions & 52 deletions

File tree

package-lock.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"license": "SEE LICENSE IN LICENSE",
4747
"dependencies": {
4848
"@aws-sdk/client-sns": "^3.997.0",
49-
"@defra/forms-engine-plugin": "^4.20.1",
49+
"@defra/forms-engine-plugin": "^4.21.0",
5050
"@defra/forms-model": "^3.0.681",
5151
"@defra/hapi-tracing": "^1.30.0",
5252
"@elastic/ecs-pino-format": "^1.5.0",

src/server/plugins/error-preview/error-preview.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FormStatus } from '@defra/forms-engine-plugin/types'
22
import Boom from '@hapi/boom'
33

44
import { createErrorPreviewModel } from '~/src/server/plugins/error-preview/error-preview-helper.js'
5-
import { getFormMetadata } from '~/src/server/services/formMetadataGuards.js'
5+
import { getFormMetadataWithoutGuard } from '~/src/server/services/formMetadataGuards.js'
66
import { getFormDefinition } from '~/src/server/services/formsService.js'
77

88
/**
@@ -13,7 +13,7 @@ export async function getErrorPreviewHandler(request, h) {
1313
const { params } = request
1414
const { slug, path, itemId } = params
1515

16-
const metadata = await getFormMetadata(slug)
16+
const metadata = await getFormMetadataWithoutGuard(slug)
1717
const definition = await getFormDefinition(metadata.id, FormStatus.Draft)
1818
if (!definition) {
1919
throw Boom.notFound(

src/server/plugins/router.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
publicRoutes,
3535
saveAndExitRoutes
3636
} from '~/src/server/routes/index.js'
37-
import { getFormMetadata } from '~/src/server/services/formMetadataGuards.js'
37+
import { getFormMetadataWithoutGuard } from '~/src/server/services/formMetadataGuards.js'
3838
import { getFormDefinition } from '~/src/server/services/formsService.js'
3939
import { getFeedbackFormLink } from '~/src/server/utils/utils.js'
4040

@@ -122,7 +122,7 @@ export default {
122122
path: '/help/get-support/{slug}',
123123
async handler(request, h) {
124124
const { slug } = request.params
125-
const form = await getFormMetadata(slug)
125+
const form = await getFormMetadataWithoutGuard(slug)
126126

127127
return h.view('help/get-support', { form })
128128
},
@@ -134,7 +134,7 @@ export default {
134134
path: '/help/privacy/{slug}',
135135
async handler(request, h) {
136136
const { slug } = request.params
137-
const form = await getFormMetadata(slug)
137+
const form = await getFormMetadataWithoutGuard(slug)
138138
// It's most likely that we come into this route from a live version of the form
139139
// so prefer that and fallback to draft if no live version (it is possible to have
140140
// a live version and no draft version, so we cannot just default to 'draft').
@@ -159,7 +159,7 @@ export default {
159159
path: '/help/privacy-specific/{slug}',
160160
async handler(request, h) {
161161
const { slug } = request.params
162-
const form = await getFormMetadata(slug)
162+
const form = await getFormMetadataWithoutGuard(slug)
163163
const formStatus = form.live ? FormStatus.Live : FormStatus.Draft
164164
const definition = await getFormDefinition(form.id, formStatus)
165165

@@ -178,7 +178,7 @@ export default {
178178
path: '/help/cookies/{slug}',
179179
async handler(request, h) {
180180
const { slug } = request.params
181-
await getFormMetadata(slug)
181+
await getFormMetadataWithoutGuard(slug)
182182

183183
const sessionTimeout = config.get('sessionTimeout')
184184

@@ -315,7 +315,7 @@ export default {
315315
path: '/help/accessibility-statement/{slug}',
316316
async handler(request, h) {
317317
const { slug } = request.params
318-
await getFormMetadata(slug)
318+
await getFormMetadataWithoutGuard(slug)
319319

320320
return h.view('help/accessibility-statement')
321321
},

src/server/routes/save-and-exit.js

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
} from '@defra/forms-engine-plugin'
77
import { getCacheService } from '@defra/forms-engine-plugin/engine/helpers.js'
88
import { stateSchema } from '@defra/forms-engine-plugin/schema.js'
9-
import { slugSchema } from '@defra/forms-model'
9+
import { FormStatus, slugSchema } from '@defra/forms-model'
1010
import Boom from '@hapi/boom'
1111
import * as Hoek from '@hapi/hoek'
1212
import { StatusCodes } from 'http-status-codes'
@@ -34,8 +34,8 @@ import {
3434
hasState
3535
} from '~/src/server/routes/save-and-exit-helper.js'
3636
import {
37-
getFormMetadata,
38-
getFormMetadataById
37+
getFormMetadataById,
38+
getFormMetadataWithGuard
3939
} from '~/src/server/services/formMetadataGuards.js'
4040
import {
4141
getSaveAndExitDetails,
@@ -83,7 +83,7 @@ export default [
8383
async handler(request, h) {
8484
const { params } = request
8585
const { slug, state: status } = params
86-
const metadata = await getFormMetadata(slug)
86+
const metadata = await getFormMetadataWithGuard(slug, status)
8787
const model = detailsViewModel(metadata, status)
8888

8989
// Store any outstanding data from the current page in a special attribute
@@ -153,7 +153,7 @@ export default [
153153
const { email, securityQuestion, securityAnswer } = payload
154154
// Throws the offline marker BEFORE publishSaveAndExitEvent so we never
155155
// emit a magic-link email for a form the user can no longer reach.
156-
const metadata = await getFormMetadata(slug)
156+
const metadata = await getFormMetadataWithGuard(slug, status)
157157

158158
const cacheService = getCacheService(request.server)
159159

@@ -206,7 +206,7 @@ export default [
206206
async failAction(request, h, err) {
207207
const { params, payload } = request
208208
const { slug, state: status } = params
209-
const metadata = await getFormMetadata(slug)
209+
const metadata = await getFormMetadataWithGuard(slug, status)
210210

211211
const model = detailsViewModel(
212212
metadata,
@@ -231,7 +231,7 @@ export default [
231231
async handler(request, h) {
232232
const { params } = request
233233
const { slug, state: status } = params
234-
const metadata = await getFormMetadata(slug)
234+
const metadata = await getFormMetadataWithGuard(slug, status)
235235

236236
// Get the email from session
237237
const email = /** @type {string} */ (
@@ -348,13 +348,13 @@ export default [
348348
path: '/resume-form-verify/{formId}/{magicLinkId}/{slug}/{state?}',
349349
async handler(request, h) {
350350
const { params } = request
351-
const { formId, magicLinkId } = params
351+
const { formId, magicLinkId, state } = params
352352

353353
// Assert the form is online BEFORE looking up save-and-exit details so
354354
// we don't leak magic-link validity timing for offline forms.
355355
let form
356356
try {
357-
form = await getFormMetadataById(formId)
357+
form = await getFormMetadataById(formId, state)
358358
} catch (err) {
359359
if (isOfflineBoom(err)) {
360360
throw err
@@ -398,7 +398,7 @@ export default [
398398

399399
if (slug) {
400400
try {
401-
await getFormMetadata(slug)
401+
await getFormMetadataWithGuard(slug, FormStatus.Live)
402402
} catch (err) {
403403
if (isOfflineBoom(err)) {
404404
throw err
@@ -433,12 +433,12 @@ export default [
433433
path: '/resume-form-verify/{formId}/{magicLinkId}/{slug}/{state?}',
434434
async handler(request, h) {
435435
const { params, payload } = request
436-
const { formId, magicLinkId } = params
436+
const { formId, magicLinkId, state } = params
437437
const { securityAnswer } = payload
438438

439439
let form
440440
try {
441-
form = await getFormMetadataById(formId)
441+
form = await getFormMetadataById(formId, state)
442442
} catch (err) {
443443
if (isOfflineBoom(err)) {
444444
throw err
@@ -516,7 +516,10 @@ export default [
516516
return h.redirect(ERROR_BASE_URL).takeover()
517517
}
518518

519-
const form = await getFormMetadataById(resumeDetails.form.id)
519+
const form = await getFormMetadataById(
520+
resumeDetails.form.id,
521+
params.state
522+
)
520523

521524
const model = passwordViewModel(
522525
form,
@@ -532,15 +535,15 @@ export default [
532535
}
533536
}),
534537
/**
535-
* @satisfies {ServerRoute<{ Params: { slug: string, state?: string} }>}
538+
* @satisfies {ServerRoute<{ Params: { slug: string, state?: FormStatus} }>}
536539
*/
537540
({
538541
method: 'GET',
539542
path: '/resume-form-success/{slug}/{state?}',
540543
async handler(request, h) {
541544
const { params } = request
542545
const { slug, state } = params
543-
const form = await getFormMetadata(slug)
546+
const form = await getFormMetadataWithGuard(slug, state)
544547

545548
const model = resumeSuccessViewModel(
546549
form,
@@ -565,6 +568,5 @@ export default [
565568
/**
566569
* @import { ServerRoute } from '@hapi/hapi'
567570
* @import { CacheRequest, FormPayload } from '@defra/forms-engine-plugin/engine/types.js'
568-
* @import { FormStatus } from '@defra/forms-model'
569571
* @import { BoomErrorCustomSaveAndExit, SaveAndExitParams, SaveAndExitPayload, SaveAndExitResumePasswordPayload, SaveAndExitResumePasswordParams } from '~/src/server/models/save-and-exit.js'
570572
*/

src/server/routes/save-and-exit.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import { createJoiError } from '~/src/server/helpers/error-helper.js'
88
import { createServer } from '~/src/server/index.js'
99
import { addError } from '~/src/server/routes/save-and-exit.js'
1010
import {
11-
getFormMetadata,
12-
getFormMetadataById
11+
getFormMetadataById,
12+
getFormMetadataWithGuard
1313
} from '~/src/server/services/formMetadataGuards.js'
1414
import {
1515
getSaveAndExitDetails,
@@ -414,7 +414,7 @@ describe('Save-and-exit check routes', () => {
414414
statusCode: 503,
415415
data: { offline: true }
416416
})
417-
jest.mocked(getFormMetadata).mockRejectedValueOnce(offlineErr)
417+
jest.mocked(getFormMetadataWithGuard).mockRejectedValueOnce(offlineErr)
418418
jest.mocked(isOfflineBoom).mockReturnValueOnce(true)
419419

420420
const options = {
@@ -428,7 +428,7 @@ describe('Save-and-exit check routes', () => {
428428

429429
test('logs info on other metadata fetch error', async () => {
430430
const otherErr = new Error('fetch failed')
431-
jest.mocked(getFormMetadata).mockRejectedValueOnce(otherErr)
431+
jest.mocked(getFormMetadataWithGuard).mockRejectedValueOnce(otherErr)
432432
jest.mocked(isOfflineBoom).mockReturnValueOnce(false)
433433

434434
const options = {
@@ -449,7 +449,7 @@ describe('Save-and-exit check routes', () => {
449449
describe('GET /resume-form-success', () => {
450450
test('route renders page without state', async () => {
451451
jest
452-
.mocked(getFormMetadata)
452+
.mocked(getFormMetadataWithGuard)
453453
// @ts-expect-error - allow partial objects for tests
454454
.mockResolvedValueOnce({
455455
slug: 'my-form-to-resume',
@@ -478,7 +478,7 @@ describe('Save-and-exit check routes', () => {
478478

479479
test('route renders page with slug', async () => {
480480
jest
481-
.mocked(getFormMetadata)
481+
.mocked(getFormMetadataWithGuard)
482482
// @ts-expect-error - allow partial objects for tests
483483
.mockResolvedValueOnce({
484484
slug: 'my-form-to-resume',
Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
11
import { assertFormAvailable } from '@defra/forms-engine-plugin'
2+
import { FormStatus } from '@defra/forms-model'
23

34
import * as rawFormsService from '~/src/server/services/formsService.js'
45

56
/**
6-
* Fetch form metadata by slug. Throws the offline marker when the form has
7-
* been taken offline so route handlers don't have to check.
7+
* Fetch form metadata by slug without the 'unavailable' guard.
88
* @param {string} slug
99
*/
10-
export async function getFormMetadata(slug) {
10+
export async function getFormMetadataWithoutGuard(slug) {
1111
const metadata = await rawFormsService.getFormMetadata(slug)
12-
assertFormAvailable(metadata)
12+
return metadata
13+
}
14+
15+
/**
16+
* Fetch form metadata by slug with 'unavailable' guard (throws the offline marker when the form has
17+
* been taken offline so route handlers don't have to check).
18+
* @param {string} slug
19+
* @param { FormStatus | undefined } formStatus
20+
*/
21+
export async function getFormMetadataWithGuard(slug, formStatus) {
22+
const metadata = await rawFormsService.getFormMetadata(slug)
23+
assertFormAvailable(metadata, formStatus ?? FormStatus.Live, false)
1324
return metadata
1425
}
1526

1627
/**
1728
* Fetch form metadata by id. Throws the offline marker when the form has
1829
* been taken offline.
1930
* @param {string} formId
31+
* @param {FormStatus} [formStatus]
2032
*/
21-
export async function getFormMetadataById(formId) {
33+
export async function getFormMetadataById(formId, formStatus) {
2234
const metadata = await rawFormsService.getFormMetadataById(formId)
23-
assertFormAvailable(metadata)
35+
assertFormAvailable(metadata, formStatus ?? FormStatus.Live, false)
2436
return metadata
2537
}

0 commit comments

Comments
 (0)