Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion e2e/cypress/e2e/runner/initialiseSession.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,20 @@ When("the session is initialised with the options", (table) => {
redirectUrl,
},
},
questions: [],
questions: [
{
question: "What is your name?",
fields: [
{
key: "firstName",
title: "What is your name?",
type: "text",
answer: "Jen",
},
],
index: 0,
},
],
}).then((res) => {
cy.wrap(res.body.token).as("token");
});
Expand Down
28 changes: 23 additions & 5 deletions e2e/cypress/fixtures/initialiseSession.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,31 @@
"components": [],
"next": [
{
"path": "/summary"
"path": "/name"
}
],
"controller": "./pages/start.js"
},
{
"title": "What is your name?",
"path": "/name",
"components": [
{
"type": "TextField",
"name": "firstName",
"title": "First name",
"options": {
"required": true
},
"schema": {}
}
],
"next": [
{
"path": "/summary"
}
]
},
{
"path": "/summary",
"controller": "./pages/summary.js",
Expand All @@ -20,14 +40,12 @@
"next": []
}
],
"lists": [
],
"lists": [],
"sections": [],
"phaseBanner": {},
"fees": [],
"payApiKey": "",
"outputs": [
],
"outputs": [],
"declaration": "<p class=\"govuk-body\">All the answers you have provided are true to the best of your knowledge.</p>",
"version": 2,
"conditions": []
Expand Down
2 changes: 2 additions & 0 deletions model/src/data-model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export type NotifyOutputConfiguration = {
export type WebhookOutputConfiguration = {
url: string;
sendAdditionalPayMetadata?: boolean;
allowRetry?: boolean;
};

export type OutputConfiguration =
Expand Down Expand Up @@ -162,6 +163,7 @@ export type FeeOptions = {
customPayErrorMessage?: string;
showPaymentSkippedWarningPage: boolean;
additionalReportingColumns?: AdditionalReportingColumn[];
payApiKey?: string | MultipleApiKeys | undefined;
};

/**
Expand Down
26 changes: 25 additions & 1 deletion runner/src/server/plugins/engine/models/FormModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
} from "@xgovformbuilder/model";

import { FormSubmissionState } from "../types";
import { PageControllerBase, getPageController } from "../pageControllers";
import {
PageControllerBase,
getPageController,
SummaryPageController,
} from "../pageControllers";
import { PageController } from "../pageControllers/PageController";
import { ExecutableCondition } from "server/plugins/engine/models/types";
import { DEFAULT_FEE_OPTIONS } from "server/plugins/engine/models/FormModel.feeOptions";
Expand Down Expand Up @@ -273,4 +277,24 @@ export class FormModel {

return this.fieldsForContext.getFormDataFromState(contextState);
}

getRelevantPages(state: FormSubmissionState) {
let nextPage = this.startPage;
const relevantPages: any[] = [];
let endPage = null;

while (nextPage != null) {
if (nextPage.hasFormComponents) {
relevantPages.push(nextPage);
} else if (
!nextPage.hasNext &&
!(nextPage instanceof SummaryPageController)
) {
endPage = nextPage;
}
nextPage = nextPage.getNextPage(state, true);
}

return { relevantPages, endPage };
}
}
92 changes: 8 additions & 84 deletions runner/src/server/plugins/engine/models/SummaryViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,12 @@ import { FormModel } from "./FormModel";
import { feedbackReturnInfoKey, redirectUrl } from "../helpers";
import { decodeFeedbackContextInfo } from "../feedback";
import { webhookSchema } from "server/schemas/webhookSchema";
import { SummaryPageController } from "../pageControllers";
import { FormSubmissionState } from "../types";
import { FEEDBACK_CONTEXT_ITEMS, WebhookData } from "./types";
import {
EmailModel,
FeesModel,
NotifyModel,
WebhookModel,
} from "server/plugins/engine/models/submission";
import { FormDefinition, isMultipleApiKey } from "@xgovformbuilder/model";
import { FeesModel } from "server/plugins/engine/models/submission";
import { HapiRequest } from "src/server/types";
import { InitialiseSessionOptions } from "server/plugins/initialiseSession/types";
import { Outputs } from "server/plugins/engine/models/submission/Outputs";

/**
* TODO - extract submission behaviour dependencies from the viewmodel
Expand Down Expand Up @@ -55,7 +49,6 @@ export class SummaryViewModel {
| undefined;

_outputs: any; // TODO
_payApiKey: FormDefinition["payApiKey"];
_webhookData: WebhookData | undefined;
callback?: InitialiseSessionOptions;
showPaymentSkippedWarningPage: boolean = false;
Expand All @@ -66,14 +59,13 @@ export class SummaryViewModel {
request: HapiRequest
) {
this.pageTitle = pageTitle;
const { relevantPages, endPage } = this.getRelevantPages(model, state);
const { relevantPages, endPage } = model.getRelevantPages(state);
const details = this.summaryDetails(request, model, state, relevantPages);
const { def } = model;
// @ts-ignore
this.declaration = def.declaration;
// @ts-ignore
this.skipSummary = def.skipSummary;
this._payApiKey = def.feeOptions?.payApiKey ?? def.payApiKey;
this.endPage = endPage;
this.feedbackLink =
def.feedback?.url ??
Expand All @@ -92,14 +84,10 @@ export class SummaryViewModel {
this.processErrors(result, details);
} else {
this.fees = FeesModel(model, state);
const outputs = new Outputs(model, state);

this._webhookData = WebhookModel(
relevantPages,
details,
model,
this.fees,
model.getContextState(state)
);
// TODO: move to controller
this._webhookData = outputs.webhookData;
this._webhookData = this.addFeedbackSourceDataToWebhook(
this._webhookData,
model,
Expand All @@ -111,40 +99,8 @@ export class SummaryViewModel {
* Skip outputs if this is a callback
*/
if (def.outputs && !state.callback) {
this._outputs = def.outputs.map((output) => {
switch (output.type) {
case "notify":
return {
type: "notify",
outputData: NotifyModel(
model,
output.outputConfiguration,
state
),
};
case "email":
return {
type: "email",
outputData: EmailModel(
model,
output.outputConfiguration,
this._webhookData
),
};
case "webhook":
return {
type: "webhook",
outputData: {
url: output.outputConfiguration.url,
sendAdditionalPayMetadata:
output.outputConfiguration.sendAdditionalPayMetadata,
allowRetry: output.outputConfiguration.allowRetry,
},
};
default:
return {};
}
});
// TODO: move to controller
this._outputs = outputs.outputs;
}
}

Expand Down Expand Up @@ -269,26 +225,6 @@ export class SummaryViewModel {
return details;
}

private getRelevantPages(model: FormModel, state: FormSubmissionState) {
let nextPage = model.startPage;
const relevantPages: any[] = [];
let endPage = null;

while (nextPage != null) {
if (nextPage.hasFormComponents) {
relevantPages.push(nextPage);
} else if (
!nextPage.hasNext &&
!(nextPage instanceof SummaryPageController)
) {
endPage = nextPage;
}
nextPage = nextPage.getNextPage(state, true);
}

return { relevantPages, endPage };
}

get validatedWebhookData() {
const result = webhookSchema.validate(this._webhookData, {
abortEarly: false,
Expand Down Expand Up @@ -321,18 +257,6 @@ export class SummaryViewModel {
set outputs(value) {
this._outputs = value;
}

get payApiKey() {
if (isMultipleApiKey(this._payApiKey)) {
return (
this._payApiKey[config.apiEnv] ??
this._payApiKey.test ??
this._payApiKey.production
);
}
return this._payApiKey;
}

/**
* If a declaration is defined, add this to {@link this._webhookData} as a question has answered `true` to
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { FormModel } from "server/plugins/engine/models";
import { TEmailModel } from "./types";
import config from "server/config";
import { EmailOutputConfiguration } from "@xgovformbuilder/model";
import { WebhookData } from "server/plugins/engine/models/types";
const { notifyTemplateId, notifyAPIKey } = config;

/**
* returns an object used for sending email requests. Used by {@link SummaryViewModel}
*/
export function EmailModel(model: FormModel, outputConfiguration, webhookData) {
export function EmailModel(
model: FormModel,
outputConfiguration: EmailOutputConfiguration,
webhookData: WebhookData
): TEmailModel {
const data: string[] = [];

webhookData?.questions?.forEach((question) => {
Expand Down
14 changes: 2 additions & 12 deletions runner/src/server/plugins/engine/models/submission/NotifyModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,7 @@ import { FormModel } from "server/plugins/engine/models";
import { FormSubmissionState } from "server/plugins/engine/types";
import { reach } from "hoek";
import { NotifyOutputConfiguration, List } from "@xgovformbuilder/model";

export type NotifyModel = Omit<
NotifyOutputConfiguration,
"emailField" | "replyToConfiguration" | "personalisation"
> & {
emailAddress: string;
emailReplyToId?: string;
personalisation: {
[key: string]: string | boolean;
};
};
import { TNotifyModel } from "./types";

const parseListAsNotifyTemplate = (
list: List,
Expand All @@ -38,7 +28,7 @@ export function NotifyModel(
model: FormModel,
outputConfiguration: NotifyOutputConfiguration,
state: FormSubmissionState
): NotifyModel {
): TNotifyModel {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was getting clashes with NotifyModel the function and NotifyModel the data type, so I've renamed it to TNotifyModel

const {
addReferencesToPersonalisation,
apiKey,
Expand Down
62 changes: 62 additions & 0 deletions runner/src/server/plugins/engine/models/submission/Outputs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { FormModel } from "server/plugins/engine/models";
import { FormSubmissionState } from "server/plugins/engine/types";
import {
EmailModel,
WebhookModel,
NotifyModel,
} from "server/plugins/engine/models/submission";
import { WebhookData } from "server/plugins/engine/models/types";
import {
EmailOutputConfiguration,
NotifyOutputConfiguration,
OutputType,
WebhookOutputConfiguration,
} from "@xgovformbuilder/model";
import { OutputData } from "server/plugins/engine/models/submission/types";

export class Outputs {
webhookData: WebhookData;
outputs: (OutputData | unknown)[];

constructor(model: FormModel, state: FormSubmissionState) {
this.webhookData = WebhookModel(model, state);

const outputDefs = model.def.outputs;
this.outputs = outputDefs.map((output) => {
switch (output.type) {
case "notify":
/**
* Typescript does not support nested type discrimination {@link https://github.com/microsoft/TypeScript/issues/18758}
*/
const notifyOutputConfiguration = output.outputConfiguration as NotifyOutputConfiguration;
return {
type: OutputType.Notify,
outputData: NotifyModel(model, notifyOutputConfiguration, state),
};
case "email":
const emailOutputConfiguration = output.outputConfiguration as EmailOutputConfiguration;
return {
type: OutputType.Email,
outputData: EmailModel(
model,
emailOutputConfiguration,
this.webhookData
),
};
case "webhook":
const webhookOutputConfiguration = output.outputConfiguration as WebhookOutputConfiguration;
return {
type: OutputType.Webhook,
outputData: {
url: webhookOutputConfiguration.url,
sendAdditionalPayMetadata:
webhookOutputConfiguration.sendAdditionalPayMetadata,
allowRetry: webhookOutputConfiguration.allowRetry,
},
};
default:
return {} as unknown;
}
});
}
}
Loading