-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Added image quality playback page for document upload
- Loading branch information
Showing
14 changed files
with
418 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Document upload | ||
|
||
the form builder supports the use of an external document upload service. This allows users to upload files, but gives developers the flexibility to decide how they want to process the files. | ||
|
||
## Setup | ||
|
||
In order to start using file upload files in your form, you will need to specify an endpoint to send your files to. This can be done by setting the following environment variables: | ||
|
||
| Variable name | Definition | example | | ||
| ----------------------- | ------------------------------------------------------ | ------------------------------- | | ||
| DOCUMENT_UPLOAD_API_URL | the root endpoint of service used to upload your files | https://document-upload-api.com | | ||
|
||
The service you're using for your document upload api will need an endpoint of /files that accepts POST requests with a file in the body. Currently, there is no support for authenticating against this endpoint, so this endpoint will need to be open. | ||
|
||
### Responses | ||
|
||
The upload service which handles communication with the api can handle the following responses: | ||
|
||
| Code | Payload | Handled by | | ||
| ---- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| 201 | | Updating the value of the upload field to the location url returned | | ||
| 201 | `qualityWarning` | Updating the upload field as above, as well as routing to the upload playback page if using the UploadPageController. See below for more details. | | ||
| 400 | | Redirects back to the upload field page displaying a file type error | | ||
| 413 | | Redirects back to the upload field page displaying a file size error | | ||
| 422 | | Redirects back to the upload field page displaying a file virus error | | ||
|
||
#### UploadPageController | ||
|
||
We have introduced a specific UploadPageController, which can be used if you want to integrate image quality checking into your document upload api. | ||
By adding the property `controller: UploadPageController` to the page in your form json, if a successful response is returned from the api but with the payload "qualityWarning", the user will be presented a playback page. | ||
This page will strongly suggest the user upload a new image, and give the user the option to continue anyway or upload a new image. | ||
If the UploadPageController is not specified on the page, the quality warning will be ignored, and the user will be routed to the next page in the form as normal. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
runner/src/server/plugins/engine/pageControllers/PlaybackUploadPageController.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { PageController } from "server/plugins/engine/pageControllers/PageController"; | ||
import { FormModel } from "server/plugins/engine/models"; | ||
import { Page } from "@xgovformbuilder/model"; | ||
import { FormComponent } from "server/plugins/engine/components"; | ||
import { HapiRequest, HapiResponseToolkit } from "server/types"; | ||
import joi from "joi"; | ||
import { FormSubmissionErrors } from "../types"; | ||
export class PlaybackUploadPageController extends PageController { | ||
inputComponent: FormComponent; | ||
retryUploadViewModel = { | ||
name: "retryUpload", | ||
type: "RadiosField", | ||
options: {}, | ||
schema: {}, | ||
fieldset: { | ||
legend: { | ||
text: "Would you like to upload a new image?", | ||
isPageHeading: false, | ||
classes: "govuk-fieldset__legend--s", | ||
}, | ||
}, | ||
items: [ | ||
{ | ||
value: true, | ||
text: "Yes - I would like to upload a new image", | ||
}, | ||
{ | ||
value: false, | ||
text: "No - I am happy with the image", | ||
}, | ||
], | ||
}; | ||
|
||
constructor(model: FormModel, pageDef: Page, inputComponent: FormComponent) { | ||
super(model, pageDef); | ||
this.inputComponent = inputComponent; | ||
this.formSchema = joi.object({ | ||
crumb: joi.string(), | ||
retryUpload: joi | ||
.string() | ||
.required() | ||
.allow("true", "false") | ||
.label("if you would like to upload a new image"), | ||
}); | ||
} | ||
|
||
/** | ||
* Gets the radio button view model for the "Would you like to upload a new image?" question | ||
* @param error - if the user hasn't chosen an option and tries to continue, add the required field error to the field | ||
* @returns the view model for the radio button component | ||
* */ | ||
getRetryUploadViewModel(errors?: FormSubmissionErrors) { | ||
let viewModel = { ...this.retryUploadViewModel }; | ||
errors?.errorList?.forEach((err) => { | ||
if (err.name === viewModel.name) { | ||
viewModel.errorMessage = { | ||
text: err.text, | ||
}; | ||
} | ||
}); | ||
return viewModel; | ||
} | ||
|
||
makeGetRouteHandler() { | ||
return async (request: HapiRequest, h: HapiResponseToolkit) => { | ||
const { cacheService } = request.services([]); | ||
|
||
const state = await cacheService.getState(request); | ||
const { progress = [] } = state; | ||
let sectionTitle = this.section?.title; | ||
return h.view("upload-playback", { | ||
sectionTitle: sectionTitle, | ||
showTitle: true, | ||
pageTitle: "Check your image", | ||
backLink: progress[progress.length - 1] ?? this.backLinkFallback, | ||
radios: this.getRetryUploadViewModel(), | ||
}); | ||
}; | ||
} | ||
|
||
makePostRouteHandler() { | ||
return async (request: HapiRequest, h: HapiResponseToolkit) => { | ||
const { cacheService } = request.services([]); | ||
|
||
const state = await cacheService.getState(request); | ||
const { progress = [] } = state; | ||
const { payload } = request; | ||
const result = this.formSchema.validate(payload, this.validationOptions); | ||
if (result.error) { | ||
const errors = this.getErrors(result); | ||
let sectionTitle = this.section?.title; | ||
return h.view("upload-playback", { | ||
sectionTitle: sectionTitle, | ||
showTitle: true, | ||
pageTitle: "Check your image", | ||
uploadErrors: errors, | ||
backLink: progress[progress.length - 2] ?? this.backLinkFallback, | ||
radios: this.getRetryUploadViewModel(errors), | ||
}); | ||
} | ||
|
||
if (payload.retryUpload === "true") { | ||
return h.redirect(`/${this.model.basePath}${this.path}`); | ||
} | ||
|
||
return h.redirect(this.getNext(request.payload)); | ||
}; | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
runner/src/server/plugins/engine/pageControllers/UploadPageController.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { PageController } from "server/plugins/engine/pageControllers/PageController"; | ||
import { FormModel } from "server/plugins/engine/models"; | ||
import { HapiRequest, HapiResponseToolkit } from "server/types"; | ||
import { PlaybackUploadPageController } from "server/plugins/engine/pageControllers/PlaybackUploadPageController"; | ||
import { FormComponent } from "server/plugins/engine/components"; | ||
|
||
function isUploadField(component: FormComponent) { | ||
return component.type === "FileUploadField"; | ||
} | ||
|
||
export class UploadPageController extends PageController { | ||
playback: PlaybackUploadPageController; | ||
inputComponent: FormComponent; | ||
constructor(model: FormModel, pageDef: any) { | ||
super(model, pageDef); | ||
const inputComponent = this.components?.items?.find(isUploadField); | ||
if (!inputComponent) { | ||
throw Error( | ||
"UploadPageController initialisation failed, no file upload component was found" | ||
); | ||
} | ||
this.playback = new PlaybackUploadPageController( | ||
model, | ||
pageDef, | ||
inputComponent as FormComponent | ||
); | ||
this.inputComponent = inputComponent as FormComponent; | ||
} | ||
|
||
makeGetRouteHandler() { | ||
return async (request: HapiRequest, h: HapiResponseToolkit) => { | ||
const { query } = request; | ||
const { view } = query; | ||
|
||
if (view === "playback") { | ||
return this.playback.makeGetRouteHandler()(request, h); | ||
} | ||
|
||
return super.makeGetRouteHandler()(request, h); | ||
}; | ||
} | ||
|
||
makePostRouteHandler() { | ||
return async (request: HapiRequest, h: HapiResponseToolkit) => { | ||
const { query } = request; | ||
|
||
if (query?.view === "playback") { | ||
return this.playback.makePostRouteHandler()(request, h); | ||
} | ||
|
||
const defaultRes = super.makePostRouteHandler()(request, h); | ||
|
||
if (request.pre?.warning) { | ||
return h.redirect("?view=playback"); | ||
} | ||
|
||
return defaultRes; | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.