From 7e659102c08b98785ac44cae768451fdef03da76 Mon Sep 17 00:00:00 2001 From: Sarah Sloan Date: Tue, 23 Apr 2024 10:16:59 +0100 Subject: [PATCH 1/4] wip --- fsd_config/form_jsons/elig-test.json | 166 ++++++++++++++++++ .../EligibilityPageController.ts | 23 +++ .../plugins/engine/pageControllers/helpers.ts | 2 + 3 files changed, 191 insertions(+) create mode 100644 fsd_config/form_jsons/elig-test.json create mode 100644 runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts diff --git a/fsd_config/form_jsons/elig-test.json b/fsd_config/form_jsons/elig-test.json new file mode 100644 index 0000000000..0e62387053 --- /dev/null +++ b/fsd_config/form_jsons/elig-test.json @@ -0,0 +1,166 @@ +{ + "metadata": {}, + "startPage": "/eligiblity-start", + "name": "Eligibility Test", + "pages": [ + { + "path": "/eligiblity-start", + "title": "Eligibility", + "components": [ + { + "name": "hsyuiX", + "options": {}, + "type": "Html", + "content": "

Tell us if you are eligible

", + "schema": {} + } + ], + "next": [ + { + "path": "/eligibility-1" + } + ], + "controller": "./pages/start.js" + }, + { + "path": "/eligibility-1", + "title": "Eligibility Part 1", + "components": [ + { + "name": "areyou", + "options": {}, + "type": "RadiosField", + "title": "Do you think you are eligible?", + "list": "eligiblity-list", + "schema": {} + } + ], + "next": [ + { + "path": "/summary-not-eligible", + "condition": "nonono" + }, + { + "path": "/summary", + "condition": "DtRJdr" + } + ], + "section": "eAEGhH" + }, + { + "path": "/summary-not-eligible", + "title": "You are NOT eligible", + "components": [ + { + "name": "sumsum", + "options": {}, + "type": "Para", + "content": "* Display answers *", + "schema": {} + } + ], + "next": [], + "section": "eAEGhH", + "controller": "./pages/summary.js" + }, + { + "path": "/summary", + "title": "You are eligible", + "components": [ + { + "name": "BsGzRm", + "options": {}, + "type": "Para", + "content": "* Display answers *", + "schema": {} + } + ], + "next": [], + "section": "eAEGhH", + "controller": "./pages/summary.js" + } + ], + "lists": [ + { + "title": "Do you think you are eligible?", + "name": "eligiblity-list", + "type": "string", + "items": [ + { + "text": "Yes, I think I am", + "value": "Yes, I think I am" + }, + { + "text": "Nope", + "value": "Nope" + } + ] + } + ], + "sections": [ + { + "name": "eAEGhH", + "title": "Eligibility" + } + ], + "conditions": [ + { + "displayName": "eligible-no", + "name": "nonono", + "value": { + "name": "eligible-no", + "conditions": [ + { + "field": { + "name": "areyou", + "type": "RadiosField", + "display": "Do you think you are eligible?" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "Nope", + "display": "Nope" + } + } + ] + } + }, + { + "displayName": "eligible-yes", + "name": "DtRJdr", + "value": { + "name": "eligible-yes", + "conditions": [ + { + "field": { + "name": "areyou", + "type": "RadiosField", + "display": "Do you think you are eligible?" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "Yes, I think I am", + "display": "Yes, I think I am" + } + } + ] + } + } + ], + "fees": [], + "outputs": [ + { + "name": "update-form", + "title": "Update form in application store", + "type": "savePerPage", + "outputConfiguration": { + "savePerPageUrl": "https://webhook.site/3f3bfa5a-43b3-4b94-81ca-6fa478623f70" + } + } + ], + "version": 2, + "skipSummary": false, + "markAsComplete": false +} diff --git a/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts b/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts new file mode 100644 index 0000000000..9427705e0a --- /dev/null +++ b/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts @@ -0,0 +1,23 @@ +import { PageController } from "./PageController"; +import { HapiRequest, HapiResponseToolkit } from "server/types"; + +export class EligibilityPageController extends PageController { + getViewModel(formData, errors) { + return { + ...super.getViewModel(formData, errors), + isStartPage: false, + skipTimeoutWarning: true, + }; + } + + makePostRouteHandler() { + return async (request: HapiRequest, h: HapiResponseToolkit) => { + const { payService, cacheService, uploadService } = request.services([]); + const model = this.model; + const state = await cacheService.getState(request); + state.metadata.isEligible = true; + await cacheService.mergeState(request, { ...state }); + // return super.makePostRouteHandler(); + }; + } +} diff --git a/runner/src/server/plugins/engine/pageControllers/helpers.ts b/runner/src/server/plugins/engine/pageControllers/helpers.ts index 74b48293fb..65f45ccb52 100644 --- a/runner/src/server/plugins/engine/pageControllers/helpers.ts +++ b/runner/src/server/plugins/engine/pageControllers/helpers.ts @@ -6,6 +6,7 @@ import { PageController } from "./PageController"; import { StartDatePageController } from "./StartDatePageController"; import { StartPageController } from "./StartPageController"; import { SummaryPageController } from "./SummaryPageController"; +import { EligibilityPageController } from "./EligibilityPageController"; import { PageControllerBase } from "./PageControllerBase"; import { RepeatingFieldPageController } from "./RepeatingFieldPageController"; import { Page } from "@xgovformbuilder/model"; @@ -19,6 +20,7 @@ const PageControllers = { SummaryPageController, PageControllerBase, RepeatingFieldPageController, + EligibilityPageController, }; export const controllerNameFromPath = (filePath: string) => { From b96d2c33b7246552b91570be2ae1bf2e1f56e30f Mon Sep 17 00:00:00 2001 From: Sarah Sloan Date: Wed, 1 May 2024 15:50:18 +0100 Subject: [PATCH 2/4] wip parsing response --- .../EligibilityPageController.ts | 26 ++++++++++++------- .../pageControllers/PageControllerBase.ts | 5 +++- runner/src/server/services/statusService.ts | 1 + runner/src/server/services/webhookService.ts | 12 ++++++--- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts b/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts index 9427705e0a..2e13672876 100644 --- a/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts +++ b/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts @@ -10,14 +10,20 @@ export class EligibilityPageController extends PageController { }; } - makePostRouteHandler() { - return async (request: HapiRequest, h: HapiResponseToolkit) => { - const { payService, cacheService, uploadService } = request.services([]); - const model = this.model; - const state = await cacheService.getState(request); - state.metadata.isEligible = true; - await cacheService.mergeState(request, { ...state }); - // return super.makePostRouteHandler(); - }; - } + // makePostRouteHandler() { + // return async (request: HapiRequest, h: HapiResponseToolkit) => { + // const { payService, cacheService, uploadService } = request.services([]); + // const model = this.model; + // const state = await cacheService.getState(request); + // state.metadata.isEligible = true; + // await cacheService.mergeState(request, { ...state }); + // // return super.makePostRouteHandler(); + // const savedState = await cacheService.getState(request); + // let relevantState = this.getConditionEvaluationContext( + // this.model, + // savedState + // ); + // return this.proceed(request, h, relevantState); + // }; + // } } diff --git a/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts b/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts index d2aee73c0f..42495fe3d8 100644 --- a/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts +++ b/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts @@ -758,7 +758,10 @@ export class PageControllerBase { webhookData: saveViewModel.validatedWebhookData, }); - await statusService.savePerPageRequest(request); + const response = await statusService.savePerPageRequest(request); + if ("elig" in response.metadata) { + console.log("got eligibility in metadata"); + } } return this.proceed(request, h, relevantState); }; diff --git a/runner/src/server/services/statusService.ts b/runner/src/server/services/statusService.ts index a9b12df849..ce84255472 100644 --- a/runner/src/server/services/statusService.ts +++ b/runner/src/server/services/statusService.ts @@ -139,6 +139,7 @@ export class StatusService { `savePerPageWebhook response: ${response}` ); } + return response; } catch (e) { this.logger.console.error( `Failed to save per page. savePerPageUrl: ${savePerPageWebhook?.outputData.url}` diff --git a/runner/src/server/services/webhookService.ts b/runner/src/server/services/webhookService.ts index f49943a110..2242207c99 100644 --- a/runner/src/server/services/webhookService.ts +++ b/runner/src/server/services/webhookService.ts @@ -43,16 +43,20 @@ export class WebhookService { } try { - const { reference } = JSON.parse(payload); + let { result } = JSON.parse(payload); + if (typeof result === "undefined") { + result = JSON.parse(payload.toString()); + } + this.logger.info( ["WebhookService", "postRequest"], `Webhook request to ${url} submitted OK` ); this.logger.debug( - ["WebhookService", "postRequest", `REF: ${reference}`], - JSON.stringify(payload) + ["WebhookService", "postRequest", `REF: ${result}`], + JSON.stringify(result) ); - return reference; + return result; } catch (error) { this.logger.error(["WebhookService", "postRequest"], error); return "UNKNOWN"; From 5992944ea34ce35e37e708002f192fa46d50dcab Mon Sep 17 00:00:00 2001 From: Sarah Sloan Date: Thu, 2 May 2024 13:10:44 +0100 Subject: [PATCH 3/4] fs-3530 eligibility page controller --- .../EligibilityPageController.ts | 74 +++++++++++++------ .../pageControllers/PageControllerBase.ts | 5 +- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts b/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts index 2e13672876..a02b9a4336 100644 --- a/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts +++ b/runner/src/server/plugins/engine/pageControllers/EligibilityPageController.ts @@ -1,29 +1,59 @@ import { PageController } from "./PageController"; import { HapiRequest, HapiResponseToolkit } from "server/types"; +import config from "server/config"; +import { SaveViewModel } from "../models"; export class EligibilityPageController extends PageController { - getViewModel(formData, errors) { - return { - ...super.getViewModel(formData, errors), - isStartPage: false, - skipTimeoutWarning: true, + makePostRouteHandler() { + return async (request: HapiRequest, h: HapiResponseToolkit) => { + const response = await this.handlePostRequest(request, h); + if (response?.source?.context?.errors) { + return response; + } + const { cacheService, statusService } = request.services([]); + const savedState = await cacheService.getState(request); + //This is required to ensure we don't navigate to an incorrect page based on stale state values + let relevantState = this.getConditionEvaluationContext( + this.model, + savedState + ); + + // Start page check so forms do not save when hitting the "Contine" button on the first page + const startPage = this.model.def.startPage; + const isStartPage = this.path === startPage; + + if (config.savePerPage && !isStartPage) { + // Set flag for continous saves on each question? + const saveViewModel = new SaveViewModel( + this.title, + this.model, + relevantState, + request + ); + + await cacheService.mergeState(request, { + outputs: saveViewModel.outputs, + userCompletedSummary: true, + }); + await cacheService.mergeState(request, { + webhookData: saveViewModel.validatedWebhookData, + }); + + const response = await statusService.savePerPageRequest(request); + const isEligible = response.metadata.is_eligible; + if (isEligible) { + return this.proceed(request, h, relevantState); + } + + let redirectUrl = response.metadata.not_eligible_redirect_url; + + if (request.query.form_session_identifier) { + redirectUrl += `?form_session_identifier=${request.query.form_session_identifier}`; + } + + return h.redirect(redirectUrl); + } + return this.proceed(request, h, relevantState); }; } - - // makePostRouteHandler() { - // return async (request: HapiRequest, h: HapiResponseToolkit) => { - // const { payService, cacheService, uploadService } = request.services([]); - // const model = this.model; - // const state = await cacheService.getState(request); - // state.metadata.isEligible = true; - // await cacheService.mergeState(request, { ...state }); - // // return super.makePostRouteHandler(); - // const savedState = await cacheService.getState(request); - // let relevantState = this.getConditionEvaluationContext( - // this.model, - // savedState - // ); - // return this.proceed(request, h, relevantState); - // }; - // } } diff --git a/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts b/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts index 42495fe3d8..d2aee73c0f 100644 --- a/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts +++ b/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts @@ -758,10 +758,7 @@ export class PageControllerBase { webhookData: saveViewModel.validatedWebhookData, }); - const response = await statusService.savePerPageRequest(request); - if ("elig" in response.metadata) { - console.log("got eligibility in metadata"); - } + await statusService.savePerPageRequest(request); } return this.proceed(request, h, relevantState); }; From 9cc8d87060136b304301755ddb58d47c28b26d32 Mon Sep 17 00:00:00 2001 From: Sarah Sloan Date: Fri, 3 May 2024 07:59:42 +0100 Subject: [PATCH 4/4] hsra placeholder form --- .../form_jsons/hsra/hsra-r1-eligibility.json | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 fsd_config/form_jsons/hsra/hsra-r1-eligibility.json diff --git a/fsd_config/form_jsons/hsra/hsra-r1-eligibility.json b/fsd_config/form_jsons/hsra/hsra-r1-eligibility.json new file mode 100644 index 0000000000..35c8a742d6 --- /dev/null +++ b/fsd_config/form_jsons/hsra/hsra-r1-eligibility.json @@ -0,0 +1,147 @@ +{ + "metadata": {}, + "startPage": "/eligiblity-start", + "name": "Eligibility Test", + "pages": [ + { + "path": "/eligiblity-start", + "title": "Eligibility", + "components": [ + { + "name": "hsyuiX", + "options": {}, + "type": "Html", + "content": "

Tell us if you are eligible

", + "schema": {} + } + ], + "next": [ + { + "path": "/eligibility-1" + } + ], + "controller": "./pages/start.js" + }, + { + "path": "/eligibility-1", + "title": "Eligibility Part 1", + "components": [ + { + "name": "areyou", + "options": {}, + "type": "RadiosField", + "title": "Do you think you are eligible?", + "list": "eligiblity-list", + "schema": {} + } + ], + "next": [ + { + "path": "/summary" + } + ], + "section": "eAEGhH", + "controller": "EligibilityPageController" + }, + + { + "path": "/summary", + "title": "Check your answers", + "components": [ + { + "name": "BsGzRm", + "options": {}, + "type": "Para", + "content": "* Display answers *", + "schema": {} + } + ], + "next": [], + "section": "eAEGhH", + "controller": "./pages/summary.js" + } + ], + "lists": [ + { + "title": "Do you think you are eligible?", + "name": "eligiblity-list", + "type": "string", + "items": [ + { + "text": "Yes, I think I am", + "value": "Yes, I think I am" + }, + { + "text": "Nope", + "value": "Nope" + } + ] + } + ], + "sections": [ + { + "name": "eAEGhH", + "title": "Eligibility" + } + ], + "conditions": [ + { + "displayName": "eligible-no", + "name": "nonono", + "value": { + "name": "eligible-no", + "conditions": [ + { + "field": { + "name": "areyou", + "type": "RadiosField", + "display": "Do you think you are eligible?" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "Nope", + "display": "Nope" + } + } + ] + } + }, + { + "displayName": "eligible-yes", + "name": "DtRJdr", + "value": { + "name": "eligible-yes", + "conditions": [ + { + "field": { + "name": "areyou", + "type": "RadiosField", + "display": "Do you think you are eligible?" + }, + "operator": "is", + "value": { + "type": "Value", + "value": "Yes, I think I am", + "display": "Yes, I think I am" + } + } + ] + } + } + ], + "fees": [], + "outputs": [ + { + "name": "update-form", + "title": "Update form in application store", + "type": "savePerPage", + "outputConfiguration": { + "savePerPageUrl": "True" + } + } + ], + "version": 2, + "skipSummary": false, + "markAsComplete": false +}