From e58e4b35a436365f4b79da9c21ed80bbfa1e5ccf Mon Sep 17 00:00:00 2001 From: Kathryn Dale Date: Wed, 26 Jun 2024 12:11:39 +0100 Subject: [PATCH 1/5] Merge remote-tracking branch 'upstream/main' into test-branch --- .eslintrc.json | 14 +- ...ta--lint-unit-build-and-publish-images.yml | 81 + .../branch--lint-unit-and-smoke-test.yml | 12 +- .github/workflows/build.yml | 10 +- .github/workflows/dependency-review.yml | 10 +- ...in--lint-unit-build-and-publish-images.yml | 6 +- .github/workflows/smoke-test.yml | 6 +- .gitignore | 5 +- README.md | 4 +- babel.config.json | 8 +- designer/Dockerfile | 4 +- designer/babel.config.js | 11 +- designer/client/ComponentTypeEdit.tsx | 5 +- designer/client/__mocks__/tabbable.js | 14 + designer/client/components/Flyout/Flyout.tsx | 28 +- .../Flyout/__tests__/Flyout.test.tsx | 1 + .../client/conditions/InlineConditions.tsx | 45 +- .../client/conditions/SelectConditions.tsx | 81 +- .../__tests__/conditionsByType.jest.ts | 55 + .../conditions/select-condition-helpers.ts | 57 + designer/client/data/types.ts | 2 + designer/client/field-edit.tsx | 143 +- designer/client/file-upload-field-edit.tsx | 45 +- .../i18n/translations/en.translation.json | 28 +- designer/client/list/ListEdit.tsx | 7 +- designer/client/list/ListItemEdit.tsx | 7 +- .../outputs/__tests__/output-edit.jest.tsx | 2 + designer/client/outputs/notify-edit-items.tsx | 7 +- designer/client/outputs/notify-edit.tsx | 24 +- designer/client/outputs/output-edit.tsx | 2 + designer/client/outputs/outputs-edit.tsx | 6 +- designer/client/outputs/types.ts | 2 + .../component/componentReducer.options.ts | 39 + designer/client/reducers/component/types.ts | 5 + designer/client/section/section-edit.js | 33 +- designer/package.json | 53 +- designer/test/.transform.js | 6 +- designer/webpack.config.js | 7 +- docker-compose.smoke.yml | 2 + docker-compose.yml | 50 +- docs/adr/0003-submitter-diagram.svg | 1 + docs/adr/0003-submitter.md | 67 + docs/adr/0004-submitter.md | 41 + docs/adr/0005-runner-pulls-from-source.md | 43 + docs/adr/0006-atomic-saves.md | 88 + docs/adr/0007-mid-journey-save-return.md | 215 ++ docs/designer/query-param-field.png | Bin 0 -> 195515 bytes docs/designer/query-param-prepopulation.md | 26 + docs/runner/document-upload.md | 32 + docs/runner/fee-options.md | 177 ++ docs/runner/multi-start-page.md | 55 + docs/runner/redirects.md | 54 + docs/runner/session-initialisation-oas.yaml | 143 + docs/runner/session-initialisation.md | 96 + docs/runner/submission-queue.md | 200 ++ docs/runner/templating.md | 29 + e2e/cypress/e2e/designer/notifyOutput.feature | 16 + e2e/cypress/e2e/designer/notifyOutput.js | 27 + .../e2e/runner/backLinkFallback.feature | 20 + e2e/cypress/e2e/runner/backLinkFallback.js | 7 + e2e/cypress/e2e/runner/completeAForm.feature | 8 +- e2e/cypress/e2e/runner/dateValidation.feature | 35 + e2e/cypress/e2e/runner/dateValidation.js | 78 + e2e/cypress/e2e/runner/htmlTemplating.feature | 17 + .../e2e/runner/imageQualityPlayback.feature | 24 + .../e2e/runner/initialiseSession.feature | 26 +- e2e/cypress/e2e/runner/initialiseSession.js | 36 +- .../runner/queryParamPrePopulation.feature | 29 + e2e/cypress/e2e/runner/redirect.feature | 18 + e2e/cypress/fixtures/backLinkFallback.json | 53 + e2e/cypress/fixtures/date.json | 52 + .../fixtures/disabled-query-param-form.json | 60 + e2e/cypress/fixtures/fails-ocr.png | Bin 0 -> 35266 bytes .../fixtures/html-templating-example.json | 63 + .../fixtures/image-quality-playback.json | 35 + e2e/cypress/fixtures/initialiseSession.json | 28 +- e2e/cypress/fixtures/notifyOutput.json | 105 + e2e/cypress/fixtures/passes.png | Bin 0 -> 33620 bytes e2e/cypress/fixtures/query-param-form.json | 60 + e2e/cypress/fixtures/redirects.json | 87 + e2e/cypress/support/commands.js | 1 + .../designer/i_am_viewing_the_designer.js | 2 +- .../runner/i_am_redirected_to_string.js | 5 + .../runner/i_navigate_to_string.js | 7 + .../runner/i_navigate_to_the_string_form.js | 4 +- .../runner/i_see_the_string_page.js | 10 + .../runner/i_upload_a_file_that_string.js | 6 + .../the_field_string_contains_string.js | 9 + .../runner/the_form_string_exists.js | 5 +- e2e/package.json | 2 +- model/babel.config.json | 8 +- model/package.json | 28 +- model/src/components/component-types.ts | 8 +- model/src/components/types.ts | 42 +- model/src/data-model/types.ts | 36 +- model/src/schema/__tests__/schema.test.ts | 125 +- model/src/schema/schema.ts | 85 +- model/src/utils/helpers.ts | 2 +- package.json | 44 +- queue-model/babel.config.json | 18 + .../20230913152003_init/migration.sql | 14 + .../20230915145048_add_defaults/migration.sql | 4 + .../20230919102214_use_db_text/migration.sql | 2 + .../migration.sql | 2 + .../migration.sql | 5 + queue-model/migrations/migration_lock.toml | 3 + queue-model/package.json | 41 + queue-model/schema.prisma | 21 + queue-model/src/index.ts | 4 + queue-model/tsconfig.json | 13 + runner/Dockerfile | 27 +- runner/README.md | 47 +- .../config/custom-environment-variables.json | 17 +- runner/config/default.js | 41 +- runner/config/production.json | 3 +- runner/config/test.json | 8 +- runner/package.json | 90 +- runner/src/client/sass/application.scss | 29 + .../server/forms/html-templating-example.json | 63 + .../forms/multi-start-page-example.json | 129 + .../server/forms/runner-components-test.json | 54 +- runner/src/server/forms/test.json | 8 +- runner/src/server/index.ts | 33 +- .../src/server/plugins/applicationStatus.ts | 112 - .../checkUserCompletedSummary.ts | 20 + .../handleUserWithConfirmationViewModel.ts | 36 + .../server/plugins/applicationStatus/index.ts | 137 + .../paymentSkippedWarning.ts | 37 + .../plugins/applicationStatus/retryPay.ts | 27 + runner/src/server/plugins/blankie.ts | 11 +- .../engine/components/AutocompleteField.ts | 11 + .../engine/components/CheckboxesField.ts | 25 +- .../engine/components/ComponentCollection.ts | 21 + .../engine/components/ContextComponent.ts | 34 + .../components/ContextComponentCollection.ts | 42 + .../plugins/engine/components/DateField.ts | 2 +- .../engine/components/DatePartsField.ts | 16 + .../engine/components/DateTimePartsField.ts | 23 + .../engine/components/FileUploadField.ts | 32 +- .../server/plugins/engine/components/Html.ts | 8 +- .../engine/components/ListFormComponent.ts | 30 +- .../engine/components/MonthYearField.ts | 17 +- .../engine/components/MultilineTextField.ts | 49 +- .../plugins/engine/components/NumberField.ts | 44 +- .../components/SelectionControlField.ts | 1 - .../engine/components/TelephoneNumberField.ts | 20 +- .../plugins/engine/components/TextField.ts | 8 +- .../plugins/engine/components/TimeField.ts | 15 +- .../plugins/engine/components/WebsiteField.ts | 2 +- .../plugins/engine/components/YesNoField.ts | 14 +- .../plugins/engine/components/constants.ts | 2 +- .../plugins/engine/components/helpers.ts | 19 +- .../server/plugins/engine/components/index.ts | 1 + runner/src/server/plugins/engine/helpers.ts | 29 + .../engine/models/FormModel.feeOptions.ts | 31 + .../server/plugins/engine/models/FormModel.ts | 42 +- .../plugins/engine/models/SummaryViewModel.ts | 91 +- .../engine/models/submission/EmailModel.ts | 9 +- .../engine/models/submission/FeesModel.ts | 53 +- .../engine/models/submission/NotifyModel.ts | 62 +- .../engine/models/submission/Outputs.ts | 62 + .../engine/models/submission/WebhookModel.ts | 139 +- .../submission/__tests__/FeesModel.test.ts | 118 +- .../__tests__/NotifyModel.test.json | 104 + .../submission/__tests__/NotifyModel.test.ts | 56 + .../__tests__/WebhookModel.test.json | 553 ++++ .../submission/__tests__/WebhookModel.test.ts | 223 ++ .../plugins/engine/models/submission/types.ts | 43 + .../MultiStartPageController.ts | 18 + .../engine/pageControllers/PageController.ts | 2 +- .../pageControllers/PageControllerBase.ts | 93 +- .../PlaybackUploadPageController.ts | 109 + .../pageControllers/SummaryPageController.ts | 83 +- .../pageControllers/UploadPageController.ts | 60 + .../plugins/engine/pageControllers/helpers.ts | 4 + .../pageControllers/validationOptions.ts | 22 +- runner/src/server/plugins/engine/plugin.ts | 66 +- .../plugins/engine/views/components/html.html | 2 +- .../server/plugins/engine/views/index.html | 9 +- .../engine/views/partials/components.html | 2 +- .../plugins/initialiseSession/helpers.ts | 16 + .../initialiseSession/initialiseSession.ts | 13 +- .../server/plugins/initialiseSession/types.ts | 11 + runner/src/server/plugins/logging.ts | 2 + runner/src/server/plugins/queue.ts | 41 + runner/src/server/plugins/router.ts | 38 +- runner/src/server/plugins/views.ts | 2 + runner/src/server/prismaClient.ts | 72 + runner/src/server/schemas/types.ts | 5 +- runner/src/server/services/QueueService.ts | 26 + runner/src/server/services/cacheService.ts | 4 +- runner/src/server/services/emailService.ts | 20 +- runner/src/server/services/httpService.ts | 2 +- runner/src/server/services/index.ts | 2 +- .../src/server/services/mySqlQueueService.ts | 98 + runner/src/server/services/notifyService.ts | 38 +- .../src/server/services/payService.nanoid.ts | 8 + runner/src/server/services/payService.ts | 86 +- .../src/server/services/pgBossQueueService.ts | 176 ++ .../src/server/services/queueStatusService.ts | 117 + runner/src/server/services/statusService.ts | 137 +- runner/src/server/services/upload/index.ts | 2 + .../services/upload/mockUploadService.ts | 20 + .../services/{ => upload}/uploadService.ts | 60 +- runner/src/server/services/webhookService.ts | 25 +- .../server/templates/additionalContexts.json | 12 + runner/src/server/types.ts | 6 +- runner/src/server/utils/configSchema.ts | 61 +- runner/src/server/views/help/cookies.html | 67 +- runner/src/server/views/layout.html | 2 + runner/src/server/views/multi-start-page.html | 37 + runner/src/server/views/pay-error.html | 11 +- .../server/views/payment-skip-warning.html | 26 + runner/src/server/views/upload-playback.html | 53 + runner/test/cases/server/config.test.js | 28 +- .../cases/server/initialiseSession.test.ts | 47 +- .../cases/server/multi-start-page.test.json | 48 + .../test/cases/server/plugins/blankie.test.ts | 20 +- .../plugins/engine/ListFormComponent.test.ts | 2 +- .../plugins/engine/MonthYearField.test.ts | 2 +- .../plugins/engine/MultilineTextField.test.ts | 8 +- ....test.ts => SummaryPageController.test.ts} | 29 +- .../plugins/engine/SummaryViewModel.json | 10 +- .../plugins/engine/WebhookModel.test.ts | 20 +- .../components/ListFormComponents.test.ts | 58 +- .../engine/components/WebsiteField.test.ts | 8 +- .../server/plugins/engine/datefield.test.ts | 12 +- .../plugins/engine/datepartsfield.test.ts | 6 +- .../plugins/engine/datetimepartsfield.test.ts | 2 +- .../server/plugins/engine/helpers.test.ts | 92 + .../server/plugins/engine/numberField.test.ts | 4 +- .../MultiStartPageController.test.ts | 136 + .../UploadPageController.test.ts | 91 + .../cases/server/services/payService.test.ts | 4 +- .../statusService.getViewModel.test.ts | 39 +- .../server/services/statusService.test.ts | 82 +- runner/test/cases/server/status.test.json | 6 +- runner/test/cases/server/titles.json | 68 +- runner/test/cases/server/titles.test.js | 13 + runner/test/cases/server/upload.test.js | 4 +- .../cases/server/utils/verifyToken.test.ts | 45 + runner/tsconfig.json | 9 +- submitter/.babelrc | 15 + submitter/Dockerfile | 64 + submitter/README.md | 53 + .../config/custom-environment-variables.json | 13 + submitter/config/default.js | 38 + submitter/config/test.json | 4 + submitter/jest.config.js | 8 + submitter/nodemon.json | 5 + submitter/package.json | 64 + submitter/src/__mocks__/prismaClient.ts | 14 + submitter/src/config.ts | 2 + submitter/src/prismaClient.ts | 63 + submitter/src/submission/createServer.ts | 48 + submitter/src/submission/index.ts | 18 + submitter/src/submission/plugins/logging.ts | 22 + submitter/src/submission/plugins/poll.ts | 28 + submitter/src/submission/plugins/retention.ts | 25 + .../src/submission/plugins/retentionCron.ts | 22 + submitter/src/submission/retention/errors.ts | 5 + .../submission/retention/redactSubmissions.ts | 44 + .../services/__tests__/queueService.test.ts | 77 + .../services/__tests__/webhookService.test.ts | 30 + .../src/submission/services/httpService.ts | 38 + submitter/src/submission/services/index.ts | 2 + .../src/submission/services/queueService.ts | 130 + .../src/submission/services/webhookService.ts | 54 + submitter/src/submission/setupDatabase.ts | 29 + submitter/src/submission/types.ts | 23 + submitter/tsconfig.json | 17 + yarn.lock | 2352 +++++++---------- 272 files changed, 10194 insertions(+), 2386 deletions(-) create mode 100644 .github/workflows/beta--lint-unit-build-and-publish-images.yml create mode 100644 designer/client/__mocks__/tabbable.js create mode 100644 designer/client/conditions/__tests__/conditionsByType.jest.ts create mode 100644 designer/client/conditions/select-condition-helpers.ts create mode 100644 docs/adr/0003-submitter-diagram.svg create mode 100644 docs/adr/0003-submitter.md create mode 100644 docs/adr/0004-submitter.md create mode 100644 docs/adr/0005-runner-pulls-from-source.md create mode 100644 docs/adr/0006-atomic-saves.md create mode 100644 docs/adr/0007-mid-journey-save-return.md create mode 100644 docs/designer/query-param-field.png create mode 100644 docs/designer/query-param-prepopulation.md create mode 100644 docs/runner/document-upload.md create mode 100644 docs/runner/fee-options.md create mode 100644 docs/runner/multi-start-page.md create mode 100644 docs/runner/redirects.md create mode 100644 docs/runner/session-initialisation-oas.yaml create mode 100644 docs/runner/session-initialisation.md create mode 100644 docs/runner/submission-queue.md create mode 100644 docs/runner/templating.md create mode 100644 e2e/cypress/e2e/designer/notifyOutput.feature create mode 100644 e2e/cypress/e2e/designer/notifyOutput.js create mode 100644 e2e/cypress/e2e/runner/backLinkFallback.feature create mode 100644 e2e/cypress/e2e/runner/backLinkFallback.js create mode 100644 e2e/cypress/e2e/runner/dateValidation.feature create mode 100644 e2e/cypress/e2e/runner/dateValidation.js create mode 100644 e2e/cypress/e2e/runner/htmlTemplating.feature create mode 100644 e2e/cypress/e2e/runner/imageQualityPlayback.feature create mode 100644 e2e/cypress/e2e/runner/queryParamPrePopulation.feature create mode 100644 e2e/cypress/e2e/runner/redirect.feature create mode 100644 e2e/cypress/fixtures/backLinkFallback.json create mode 100644 e2e/cypress/fixtures/date.json create mode 100644 e2e/cypress/fixtures/disabled-query-param-form.json create mode 100644 e2e/cypress/fixtures/fails-ocr.png create mode 100644 e2e/cypress/fixtures/html-templating-example.json create mode 100644 e2e/cypress/fixtures/image-quality-playback.json create mode 100644 e2e/cypress/fixtures/notifyOutput.json create mode 100644 e2e/cypress/fixtures/passes.png create mode 100644 e2e/cypress/fixtures/query-param-form.json create mode 100644 e2e/cypress/fixtures/redirects.json create mode 100644 e2e/cypress/support/step_definitions/runner/i_am_redirected_to_string.js create mode 100644 e2e/cypress/support/step_definitions/runner/i_navigate_to_string.js create mode 100644 e2e/cypress/support/step_definitions/runner/i_see_the_string_page.js create mode 100644 e2e/cypress/support/step_definitions/runner/i_upload_a_file_that_string.js create mode 100644 e2e/cypress/support/step_definitions/runner/the_field_string_contains_string.js create mode 100644 queue-model/babel.config.json create mode 100644 queue-model/migrations/20230913152003_init/migration.sql create mode 100644 queue-model/migrations/20230915145048_add_defaults/migration.sql create mode 100644 queue-model/migrations/20230919102214_use_db_text/migration.sql create mode 100644 queue-model/migrations/20231107195736_add_allow_retry/migration.sql create mode 100644 queue-model/migrations/20231108100812_webhook_url_required/migration.sql create mode 100644 queue-model/migrations/migration_lock.toml create mode 100644 queue-model/package.json create mode 100644 queue-model/schema.prisma create mode 100644 queue-model/src/index.ts create mode 100644 queue-model/tsconfig.json create mode 100644 runner/src/server/forms/html-templating-example.json create mode 100644 runner/src/server/forms/multi-start-page-example.json delete mode 100644 runner/src/server/plugins/applicationStatus.ts create mode 100644 runner/src/server/plugins/applicationStatus/checkUserCompletedSummary.ts create mode 100644 runner/src/server/plugins/applicationStatus/handleUserWithConfirmationViewModel.ts create mode 100644 runner/src/server/plugins/applicationStatus/index.ts create mode 100644 runner/src/server/plugins/applicationStatus/paymentSkippedWarning.ts create mode 100644 runner/src/server/plugins/applicationStatus/retryPay.ts create mode 100644 runner/src/server/plugins/engine/components/ContextComponent.ts create mode 100644 runner/src/server/plugins/engine/components/ContextComponentCollection.ts create mode 100644 runner/src/server/plugins/engine/models/FormModel.feeOptions.ts create mode 100644 runner/src/server/plugins/engine/models/submission/Outputs.ts create mode 100644 runner/src/server/plugins/engine/models/submission/__tests__/NotifyModel.test.json create mode 100644 runner/src/server/plugins/engine/models/submission/__tests__/NotifyModel.test.ts create mode 100644 runner/src/server/plugins/engine/models/submission/__tests__/WebhookModel.test.json create mode 100644 runner/src/server/plugins/engine/models/submission/__tests__/WebhookModel.test.ts create mode 100644 runner/src/server/plugins/engine/pageControllers/MultiStartPageController.ts create mode 100644 runner/src/server/plugins/engine/pageControllers/PlaybackUploadPageController.ts create mode 100644 runner/src/server/plugins/engine/pageControllers/UploadPageController.ts create mode 100644 runner/src/server/plugins/queue.ts create mode 100644 runner/src/server/prismaClient.ts create mode 100644 runner/src/server/services/QueueService.ts create mode 100644 runner/src/server/services/mySqlQueueService.ts create mode 100644 runner/src/server/services/payService.nanoid.ts create mode 100644 runner/src/server/services/pgBossQueueService.ts create mode 100644 runner/src/server/services/queueStatusService.ts create mode 100644 runner/src/server/services/upload/index.ts create mode 100644 runner/src/server/services/upload/mockUploadService.ts rename runner/src/server/services/{ => upload}/uploadService.ts (82%) create mode 100644 runner/src/server/templates/additionalContexts.json create mode 100644 runner/src/server/views/multi-start-page.html create mode 100644 runner/src/server/views/payment-skip-warning.html create mode 100644 runner/src/server/views/upload-playback.html create mode 100644 runner/test/cases/server/multi-start-page.test.json rename runner/test/cases/server/plugins/engine/{SummaryViewModel.test.ts => SummaryPageController.test.ts} (52%) create mode 100644 runner/test/cases/server/plugins/engine/pageControllers/MultiStartPageController.test.ts create mode 100644 runner/test/cases/server/plugins/engine/pageControllers/UploadPageController.test.ts create mode 100644 runner/test/cases/server/utils/verifyToken.test.ts create mode 100644 submitter/.babelrc create mode 100644 submitter/Dockerfile create mode 100644 submitter/README.md create mode 100644 submitter/config/custom-environment-variables.json create mode 100644 submitter/config/default.js create mode 100644 submitter/config/test.json create mode 100644 submitter/jest.config.js create mode 100644 submitter/nodemon.json create mode 100644 submitter/package.json create mode 100644 submitter/src/__mocks__/prismaClient.ts create mode 100644 submitter/src/config.ts create mode 100644 submitter/src/prismaClient.ts create mode 100644 submitter/src/submission/createServer.ts create mode 100644 submitter/src/submission/index.ts create mode 100644 submitter/src/submission/plugins/logging.ts create mode 100644 submitter/src/submission/plugins/poll.ts create mode 100644 submitter/src/submission/plugins/retention.ts create mode 100644 submitter/src/submission/plugins/retentionCron.ts create mode 100644 submitter/src/submission/retention/errors.ts create mode 100644 submitter/src/submission/retention/redactSubmissions.ts create mode 100644 submitter/src/submission/services/__tests__/queueService.test.ts create mode 100644 submitter/src/submission/services/__tests__/webhookService.test.ts create mode 100644 submitter/src/submission/services/httpService.ts create mode 100644 submitter/src/submission/services/index.ts create mode 100644 submitter/src/submission/services/queueService.ts create mode 100644 submitter/src/submission/services/webhookService.ts create mode 100644 submitter/src/submission/setupDatabase.ts create mode 100644 submitter/src/submission/types.ts create mode 100644 submitter/tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json index 9cc11f6baa..8cf31a364f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,10 +1,7 @@ { - "extends": [ - "plugin:json/recommended", - "plugin:prettier/recommended" - ], + "extends": ["plugin:json/recommended", "plugin:prettier/recommended"], "plugins": ["@babel", "prettier"], - "parser": "babel-eslint", + "parser": "@babel/eslint-parser", "env": { "browser": true, "es6": true, @@ -38,7 +35,12 @@ { "files": ["*.ts", "*.tsx"], "parser": "@typescript-eslint/parser", - "plugins": ["@babel", "prettier", "@typescript-eslint", "eslint-plugin-tsdoc"], + "plugins": [ + "@babel", + "prettier", + "@typescript-eslint", + "eslint-plugin-tsdoc" + ], "parserOptions": { "ecmaFeatures": { "jsx": true } } diff --git a/.github/workflows/beta--lint-unit-build-and-publish-images.yml b/.github/workflows/beta--lint-unit-build-and-publish-images.yml new file mode 100644 index 0000000000..a033899b8b --- /dev/null +++ b/.github/workflows/beta--lint-unit-build-and-publish-images.yml @@ -0,0 +1,81 @@ +name: Beta QA +on: + push: + branches: + - beta + +jobs: + calculate-version: + runs-on: ubuntu-latest + outputs: + semVer: ${{ steps.gitversion.outputs.semVer }} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + branches: main + + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v0.9.7 + with: + versionSpec: "5.x" + + - name: Determine Version + id: gitversion + uses: gittools/actions/gitversion/execute@v0.9.7 + with: + useConfigFile: true + + assign-semver: + runs-on: ubuntu-latest + needs: [calculate-version] + env: + SEMVER: ${{ needs.calculate-version.outputs.semVer }} + MAJOR: ${{ needs.calculate-version.outputs.Major }} + outputs: + SEMVER: ${{ steps.calc-semver.outputs.semver }} + steps: + - run: echo $SEMVER + - name: Add 3 to calculated semver + run: | + echo SEMVER="$((3 + MAJOR))${SEMVER:1}" >> $GITHUB_ENV + - name: Set semver to output + id: calc-semver + run: echo "::set-output name=semver::$(echo $SEMVER)" + + lint-and-test: + name: Workspace + strategy: + matrix: + workspace: [model, designer, runner, submitter] + uses: ./.github/workflows/lint-and-test.yml + with: + workspace: ${{ matrix.workspace }} + + build-and-publish-images: + name: Build and publish + needs: [calculate-version, assign-semver, lint-and-test] + strategy: + matrix: + app: [designer, runner, submitter] + uses: ./.github/workflows/build.yml + secrets: inherit + with: + semver: ${{ needs.assign-semver.outputs.SEMVER }} + publish: true + app: ${{matrix.app}} + + tag-branch: + runs-on: ubuntu-latest + needs: [calculate-version, assign-semver, build-and-publish-images] + env: + SEMVER: ${{ needs.assign-semver.outputs.SEMVER }} + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + token: ${{ secrets.GHCR_PAT }} + - name: Tag branch with run number + run: | + git tag ${{ env.SEMVER }} + git push --tags origin HEAD diff --git a/.github/workflows/branch--lint-unit-and-smoke-test.yml b/.github/workflows/branch--lint-unit-and-smoke-test.yml index 03582521fe..cf5cff02cf 100644 --- a/.github/workflows/branch--lint-unit-and-smoke-test.yml +++ b/.github/workflows/branch--lint-unit-and-smoke-test.yml @@ -3,6 +3,7 @@ on: pull_request: branches: - main + - beta paths-ignore: - "docs/**" - "**/README.md" @@ -18,7 +19,7 @@ jobs: name: Workspace strategy: matrix: - workspace: [model, designer, runner] + workspace: [model, designer, runner, submitter] uses: ./.github/workflows/lint-and-test.yml with: workspace: ${{ matrix.workspace }} @@ -30,6 +31,13 @@ jobs: app: designer secrets: inherit + build-submitter: + name: Submitter + uses: ./.github/workflows/build.yml + with: + app: submitter + secrets: inherit + build-runner: name: Runner uses: ./.github/workflows/build.yml @@ -38,7 +46,7 @@ jobs: secrets: inherit smoke-test: - needs: [build-runner,build-designer] + needs: [build-runner, build-designer] uses: ./.github/workflows/smoke-test.yml with: runner-cache-ref: ${{needs.build-runner.outputs.tag}} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b8cc263fb0..bc17d1a126 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: workflow_call: inputs: app: - description: the app to build "designer" or "runner" + description: the app to build "designer", "runner" or "submitter" required: true type: string publish: @@ -23,7 +23,6 @@ on: description: hash used for docker caching value: ${{ jobs.build-app.outputs.hash }} - jobs: build-app: if: ${{!contains(github.event.head_commit.message, 'chore(deps-dev)')}} @@ -33,12 +32,11 @@ jobs: tag: ${{ steps.hashFile.outputs.tag }} hash: ${{ steps.hashFile.outputs.hash }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v3.6.0 - name: Use Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v3.6.0 with: node-version: "16.x" - cache: yarn - name: Get yarn cache directory path id: yarn-cache-dir-path @@ -51,6 +49,7 @@ jobs: key: ${{ runner.os }}-yarn-${{inputs.app}}-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn-${{inputs.app}} + fail-on-cache-miss: false - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 @@ -65,7 +64,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - # The hash is a function of the Dockerfile and the yarn.lock Packages take up the bulk of the time during a docker build. The hash is used to cache the docker builds. # As long as the yarn.lock and dockerfiles are the same, you will be able to share this cache with another commit/branch. - id: hashFile diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index fe461b4243..3bd12c66a1 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -4,7 +4,7 @@ # # Source repository: https://github.com/actions/dependency-review-action # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement -name: 'Dependency Review' +name: "Dependency Review" on: [pull_request] permissions: @@ -14,7 +14,11 @@ jobs: dependency-review: runs-on: ubuntu-latest steps: - - name: 'Checkout Repository' + - name: "Checkout Repository" uses: actions/checkout@v3 - - name: 'Dependency Review' + - name: "Dependency Review" uses: actions/dependency-review-action@v2 + with: + allow-ghsas: + - GHSA-c429-5p7v-vgjp + - GHSA-7fh5-64p2-3v2j diff --git a/.github/workflows/main--lint-unit-build-and-publish-images.yml b/.github/workflows/main--lint-unit-build-and-publish-images.yml index 375b33ab20..b50fe9b0e4 100644 --- a/.github/workflows/main--lint-unit-build-and-publish-images.yml +++ b/.github/workflows/main--lint-unit-build-and-publish-images.yml @@ -47,7 +47,7 @@ jobs: name: Workspace strategy: matrix: - workspace: [ model, designer, runner ] + workspace: [model, designer, runner, submitter] uses: ./.github/workflows/lint-and-test.yml with: workspace: ${{ matrix.workspace }} @@ -57,7 +57,7 @@ jobs: needs: [calculate-version, assign-semver, lint-and-test] strategy: matrix: - app: [designer, runner] + app: [designer, runner, submitter] uses: ./.github/workflows/build.yml secrets: inherit with: @@ -71,7 +71,7 @@ jobs: secrets: inherit strategy: matrix: - app: [ designer, runner ] + app: [designer, runner] with: app: ${{ matrix.app }} tag: ${{ needs.assign-semver.outputs.SEMVER }} diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index ff465cdca8..4341901a1e 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -30,7 +30,6 @@ jobs: id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn config get cacheFolder)" - - uses: actions/cache@v3 id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) with: @@ -53,7 +52,6 @@ jobs: config-inline: | [registry."ghcr.io"] - - name: Login to GitHub Container Registry uses: docker/login-action@v2 with: @@ -88,5 +86,9 @@ jobs: docker compose -f docker-compose.smoke.yml up -d docker ps + - name: log + run: | + docker compose logs runner + - name: run smoke tests run: yarn e2e cypress run diff --git a/.gitignore b/.gitignore index 22413ef5b0..25abc0b60a 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,8 @@ tsconfig.tsbuildinfo docs/**/typedoc /e2e/cypress/screenshots/ -/runner/config/default.js +.env_mysql +/queue-model/dist +/queue-model/module +/queue-model/src/prisma/generated/runner/config/default.js runner/config/default.js diff --git a/README.md b/README.md index ebf4d83400..13b01f0b9a 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Also see the individual repo README files for additional info: **Always run scripts from the root directory.** -1. Make sure you are using node 16 `node --version`. +1. Make sure you are using node 18 `node --version`. 2. Make sure you have yarn 1.22+ installed. You do not need to install yarn 2.4+, yarn will detect the yarn 2 binary within [.yarn](./.yarn) and that will be used. 3. If using the designer: - Note that the designer requires the runner to be running with the default `NODE_ENV=development` settings (see [runner/config/development.json](https://github.com/XGovFormBuilder/digital-form-builder/tree/main/runner/config/development.json)) to enable posting and previewing of forms during design. @@ -116,6 +116,6 @@ The latest releases will be running here: [Runner](https://digital-form-builder- A suite of smoke tests are run against all PRs. There is a Cron Job that executes smoke tests against the Heroku deployments and is scheduled to run at midnight every day. -A legacy suite of smoke tests can be found in this [repository](https://github.com/XGovFormBuilder/digital-form-builder-legacy-smoke-tests). They have been removed so that the project can run on node 16. +A legacy suite of smoke tests can be found in this [repository](https://github.com/XGovFormBuilder/digital-form-builder-legacy-smoke-tests). They have been removed so that the project can run on node 18. Smoke tests will be migrated to use [cypress.io](https://cypress.io) in the coming months. diff --git a/babel.config.json b/babel.config.json index 81698c3e65..0cbf17ce9e 100644 --- a/babel.config.json +++ b/babel.config.json @@ -3,11 +3,11 @@ "exclude": ["node_modules/**"], "plugins": [ "@babel/plugin-proposal-export-default-from", - "@babel/plugin-proposal-class-properties", - "@babel/plugin-proposal-private-property-in-object", - "@babel/plugin-proposal-private-methods", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-private-property-in-object", + "@babel/plugin-transform-private-methods", "@babel/plugin-transform-runtime", "@babel/plugin-syntax-jsx", - "@babel/plugin-proposal-logical-assignment-operators" + "@babel/plugin-transform-logical-assignment-operators" ] } diff --git a/designer/Dockerfile b/designer/Dockerfile index dac1f04e2a..ef872e2a1b 100644 --- a/designer/Dockerfile +++ b/designer/Dockerfile @@ -2,7 +2,7 @@ # Stage 1 # Base image contains the updated OS and # It also configures the non-root user that will be given permission to copied files/folders in every subsequent stages -FROM node:16-alpine AS base +FROM node:18-alpine AS base RUN mkdir -p /usr/src/app && \ addgroup -g 1001 appuser && \ adduser -S -u 1001 -G appuser appuser && \ @@ -51,6 +51,8 @@ ARG LAST_COMMIT="NOT_DEFINED" ARG LAST_TAG="NOT_DEFINED" ENV LAST_COMMIT=$LAST_COMMIT ENV LAST_TAG=$LAST_TAG +ENV NODE_OPTIONS="--openssl-legacy-provider" +COPY --chown=appuser:appuser designer/package.json ./designer/ RUN --mount=type=cache,target=.yarn/cache,id=designer,uid=1001,mode=0755 yarn workspaces focus @xgovformbuilder/designer COPY --chown=appuser:appuser ./designer ./designer/ diff --git a/designer/babel.config.js b/designer/babel.config.js index 50d6e7915c..83080b8780 100644 --- a/designer/babel.config.js +++ b/designer/babel.config.js @@ -20,15 +20,14 @@ module.exports = { ], ], plugins: [ - "@babel/plugin-proposal-class-properties", - "@babel/plugin-proposal-private-methods", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-private-methods", "@babel/plugin-syntax-dynamic-import", "@babel/plugin-transform-runtime", "@babel/plugin-proposal-export-default-from", - "@babel/plugin-proposal-nullish-coalescing-operator", - "@babel/plugin-proposal-optional-chaining", - "@babel/plugin-proposal-logical-assignment-operators", - + "@babel/plugin-transform-nullish-coalescing-operator", + "@babel/plugin-transform-logical-assignment-operators", + "@babel/plugin-transform-optional-chaining", [ "module-resolver", { diff --git a/designer/client/ComponentTypeEdit.tsx b/designer/client/ComponentTypeEdit.tsx index a06c2168c1..9c464a2b85 100644 --- a/designer/client/ComponentTypeEdit.tsx +++ b/designer/client/ComponentTypeEdit.tsx @@ -51,7 +51,10 @@ function ComponentTypeEdit(props) { return (
{needsFieldInputs && ( - + )} {TagName && }
diff --git a/designer/client/__mocks__/tabbable.js b/designer/client/__mocks__/tabbable.js new file mode 100644 index 0000000000..3ddff586f7 --- /dev/null +++ b/designer/client/__mocks__/tabbable.js @@ -0,0 +1,14 @@ +const lib = jest.requireActual("tabbable"); +const tabbable = { + ...lib, + tabbable: (node, options) => + lib.tabbable(node, { ...options, displayCheck: "none" }), + focusable: (node, options) => + lib.focusable(node, { ...options, displayCheck: "none" }), + isFocusable: (node, options) => + lib.isFocusable(node, { ...options, displayCheck: "none" }), + isTabbable: (node, options) => + lib.isTabbable(node, { ...options, displayCheck: "none" }), +}; + +module.exports = tabbable; diff --git a/designer/client/components/Flyout/Flyout.tsx b/designer/client/components/Flyout/Flyout.tsx index 23e3aa9295..f3617623ff 100644 --- a/designer/client/components/Flyout/Flyout.tsx +++ b/designer/client/components/Flyout/Flyout.tsx @@ -1,16 +1,32 @@ -import React, { useContext, useEffect, useLayoutEffect, useState } from "react"; +import React, { + CSSProperties, + ReactChildren, + useContext, + useLayoutEffect, + useState, +} from "react"; import FocusTrap from "focus-trap-react"; import { FlyoutContext } from "../../context"; -import { DataContext } from "../../context"; import { i18n } from "../../i18n"; import "./Flyout.scss"; -import { bool } from "aws-sdk/clients/signer"; -export function useFlyoutEffect(props: {}) { +interface Props { + style: string; + width?: string; + onHide: () => void; + closeOnEnter: (e) => void; + show: boolean; + offset: number; + title?: string; + children?: ReactChildren; + NEVER_UNMOUNTS?: boolean; +} + +export function useFlyoutEffect(props: Props) { const flyoutContext = useContext(FlyoutContext); const [offset, setOffset] = useState(0); - const [style, setStyle] = useState(); + const [style, setStyle] = useState(); const show = props.show ?? true; /** @@ -58,7 +74,7 @@ export function useFlyoutEffect(props: {}) { return { style, width: props?.width, closeOnEnter, onHide, offset, show }; } -export function Flyout(props) { +export function Flyout(props: Props) { const { style, width = "", diff --git a/designer/client/components/Flyout/__tests__/Flyout.test.tsx b/designer/client/components/Flyout/__tests__/Flyout.test.tsx index 476fee2557..d0bf7fbbe5 100644 --- a/designer/client/components/Flyout/__tests__/Flyout.test.tsx +++ b/designer/client/components/Flyout/__tests__/Flyout.test.tsx @@ -14,6 +14,7 @@ const { test, describe, beforeEach, afterEach } = lab; function HookWrapper(props) { const hook = props.hook ? props.hook() : undefined; // @ts-ignore + // eslint-disable-next-line react/no-unknown-property return
; } diff --git a/designer/client/conditions/InlineConditions.tsx b/designer/client/conditions/InlineConditions.tsx index 6aeb7d050b..7aa75cbcc6 100644 --- a/designer/client/conditions/InlineConditions.tsx +++ b/designer/client/conditions/InlineConditions.tsx @@ -13,6 +13,7 @@ import { allInputs, findList, inputsAccessibleAt, + removeCondition, updateCondition, } from "../data"; import randomId from "../randomId"; @@ -147,8 +148,6 @@ export class InlineConditions extends React.Component { return; } - const copy = { ...data }; - if (condition) { const updatedData = updateCondition(data, condition.name, conditions); await save(updatedData); @@ -169,6 +168,18 @@ export class InlineConditions extends React.Component { } }; + onClickDelete = async (event: MouseEvent) => { + event?.preventDefault(); + const { data, save } = this.context; + const { cancelCallback, condition } = this.props; + + const updatedData = removeCondition(data, condition.name); + await save(updatedData); + if (cancelCallback) { + cancelCallback(event); + } + }; + saveCondition = (condition) => { this.setState({ conditions: this.state.conditions.add(condition), @@ -314,16 +325,28 @@ export class InlineConditions extends React.Component { fields={this.state.fields} saveCallback={this.saveCondition} /> -
+
{hasConditions && ( - - {i18n("save")} - + <> + + {i18n("save")} + + {this.props.condition && ( + + {i18n("delete")} + + )} + )} { @@ -81,22 +91,25 @@ class SelectConditions extends React.Component { const { data } = this.context; const fields: any = Object.values(this.fieldsForPath(path)); const { conditions = [] } = data; - var conditionsForPath: any[] = []; - - const stringConditions = conditions.filter( - (condition) => typeof condition.value === "string" - ); - const objectConditions = conditions.filter( - (condition) => typeof condition.value !== "string" - ); + let conditionsForPath: any[] = []; + const conditionsByTypeMap = conditionsByType(conditions); fields.forEach((field) => { this.handleStringConditions( - stringConditions, + conditionsByTypeMap.string, + field.name, + conditionsForPath + ); + this.handleConditions( + conditionsByTypeMap.object, + field.name, + conditionsForPath + ); + this.handleNestedConditions( + conditionsByTypeMap.nested, field.name, conditionsForPath ); - this.handleConditions(objectConditions, field.name, conditionsForPath); }); return conditionsForPath; @@ -108,11 +121,11 @@ class SelectConditions extends React.Component { conditionsForPath: any[] ) { objectConditions.forEach((condition) => { - condition.value.conditions.forEach((innerCondition) => { + condition.value.conditions?.forEach((innerCondition) => { this.checkAndAddCondition( condition, fieldName, - innerCondition.field.name, + getFieldNameSubstring(innerCondition.field.name), conditionsForPath ); }); @@ -150,7 +163,36 @@ class SelectConditions extends React.Component { conditionsForPath ) ); - var a = ""; + } + // loops through nested conditions, checking the referenced condition against the current field + handleNestedConditions( + nestedConditions: ConditionData[], + fieldName: string, + conditionsForPath: any[] + ) { + nestedConditions.forEach((condition) => { + condition.value.conditions.forEach((innerCondition) => { + // if the condition is already in the conditions array, skip the for each loop iteration + if (isDuplicateCondition(conditionsForPath, condition.name)) return; + // if the inner condition isn't a nested condition, handle it in the standard way + if (!hasConditionName(innerCondition)) { + this.checkAndAddCondition( + condition, + fieldName, + getFieldNameSubstring(innerCondition.field.name), + conditionsForPath + ); + return; + } + //if the inner condition is a nested condition, + //check if that nested condition is already in the conditions array, + //and if so, add this condition to the array + if ( + isDuplicateCondition(conditionsForPath, innerCondition.conditionName) + ) + conditionsForPath.push(condition); + }); + }); } checkAndAddCondition( @@ -159,10 +201,7 @@ class SelectConditions extends React.Component { conditionFieldName: string, conditions: any[] ) { - const isDuplicateCondition = conditions.includes( - (condition) => condition.name === conditionToAdd.name - ); - if (isDuplicateCondition) return; + if (isDuplicateCondition(conditions, conditionToAdd.name)) return; if (fieldName === conditionFieldName) conditions.push(conditionToAdd); } diff --git a/designer/client/conditions/__tests__/conditionsByType.jest.ts b/designer/client/conditions/__tests__/conditionsByType.jest.ts new file mode 100644 index 0000000000..6a1f77f2ec --- /dev/null +++ b/designer/client/conditions/__tests__/conditionsByType.jest.ts @@ -0,0 +1,55 @@ +import { conditionsByType } from "./../select-condition-helpers"; + +const stringCondition = { + name: "likesScrambledEggs", + displayName: "Likes scrambled eggs", + value: "likeScrambled == true", +}; + +const objectCondition = { + name: "likesFriedEggsCond", + displayName: "Likes fried eggs", + value: { + name: "likesFriedEggs", + conditions: [ + { + value: { + name: "likesFried", + displayName: "Do you like fried eggs?", + field: { + name: "likesFried", + type: "string", + display: "Do you like fried eggs?", + }, + operator: "is", + type: "Value", + value: "true", + display: "true", + }, + }, + ], + }, +}; + +const nestedCondition = { + name: "likesFriedAndScrambledEggs", + displayName: "Favourite egg is fried and scrambled", + value: { + conditions: [ + { + conditionName: "likesScrambledEggs", + conditionDisplayName: "likes scrambled eggs", + }, + { coordinator: "and", ...objectCondition }, + ], + }, +}; + +test("conditionsByType", () => { + const conditions = [stringCondition, objectCondition, nestedCondition]; + expect(conditionsByType(conditions)).toEqual({ + string: [stringCondition], + nested: [nestedCondition], + object: [objectCondition], + }); +}); diff --git a/designer/client/conditions/select-condition-helpers.ts b/designer/client/conditions/select-condition-helpers.ts new file mode 100644 index 0000000000..b42f368dd1 --- /dev/null +++ b/designer/client/conditions/select-condition-helpers.ts @@ -0,0 +1,57 @@ +import { ConditionData } from "./SelectConditions"; + +export const isObjectCondition = (condition: ConditionData) => { + return typeof condition.value !== "string"; +}; + +export const isStringCondition = (condition: ConditionData) => { + return typeof condition.value === "string"; +}; + +export const hasConditionName = (condition: any) => { + return !!condition?.conditionName; +}; + +export const hasNestedCondition = (condition: ConditionData) => { + if (typeof condition.value === "string") { + return false; + } + return condition.value.conditions?.find?.(hasConditionName) ?? false; +}; + +export const isDuplicateCondition = ( + conditions: any[], + conditionName: string +) => { + return !!conditions.find((condition) => condition.name === conditionName); +}; + +export const getFieldNameSubstring = (sectionFieldName: string) => { + return sectionFieldName.substring(sectionFieldName.indexOf(".")); +}; + +export function conditionsByType(conditions: ConditionData[]) { + return conditions.reduce( + (conditionsByType, currentValue) => { + if (isStringCondition(currentValue)) { + conditionsByType.string.push(currentValue); + } else if (!!hasNestedCondition(currentValue)) { + conditionsByType.nested.push(currentValue); + } else if (isObjectCondition(currentValue)) { + conditionsByType.object.push(currentValue); + } + return conditionsByType; + }, + { + string: [], + nested: [], + object: [], + } as ConditionByTypeMap + ); +} + +type ConditionByTypeMap = { + string: ConditionData[]; + nested: ConditionData[]; + object: ConditionData[]; +}; diff --git a/designer/client/data/types.ts b/designer/client/data/types.ts index d801378f4a..776d374eb8 100644 --- a/designer/client/data/types.ts +++ b/designer/client/data/types.ts @@ -16,6 +16,8 @@ export const isNotContentType = ( "Details", "Html", "InsetText", + "List", + "FlashCard", ]; return !contentTypes.find((type) => `${type}` === `${obj.type}`); }; diff --git a/designer/client/field-edit.tsx b/designer/client/field-edit.tsx index 9fc18182b2..bded117a09 100644 --- a/designer/client/field-edit.tsx +++ b/designer/client/field-edit.tsx @@ -9,19 +9,30 @@ import { ErrorMessage } from "./components/ErrorMessage"; type Props = { isContentField?: boolean; + isListField?: boolean; }; -export function FieldEdit({ isContentField = false }: Props) { +export function FieldEdit({ + isContentField = false, + isListField = false, +}: Props) { const { state, dispatch } = useContext(ComponentContext); const { selectedComponent, errors } = state; const { name, title, hint, attrs, type, options = {} } = selectedComponent; - const { hideTitle = false, optionalText = false, required = true } = options; + const { + hideTitle = false, + optionalText = false, + required = true, + exposeToContext = false, + allowPrePopulation = false, + allowPrePopulationOverwrite = false, + disableChangingFromSummary = false, + } = options; const isFileUploadField = selectedComponent.type === "FileUploadField"; const fieldTitle = ComponentTypes.find((componentType) => componentType.name === type) ?.title ?? ""; - return (
@@ -188,8 +199,134 @@ export function FieldEdit({ isContentField = false }: Props) {
+
+
+ + dispatch({ + type: Actions.EDIT_OPTIONS_EXPOSE_TO_CONTEXT, + payload: e.target.checked, + }) + } + /> + + + {i18n("common.exposeToContextOption.helpText")} + +
+
+ {isListField && ( + <> +
+
+ + dispatch({ + type: Actions.EDIT_OPTIONS_ALLOW_PRE_POPULATION, + payload: e.target.checked, + }) + } + /> + + + {i18n("common.allowPrePopulationOption.helpText")} + +
+
+
+
+ + dispatch({ + type: + Actions.EDIT_OPTIONS_ALLOW_OVERWRITE_FROM_QUERY_PARAM, + payload: e.target.checked, + }) + } + /> + + + {i18n("common.allowPrePopulationOverwriteOption.helpText")} + +
+
+ + )} +
+
+ + dispatch({ + type: Actions.EDIT_OPTIONS_DISABLE_CHANGING_FROM_SUMMARY, + payload: e.target.checked, + }) + } + /> + + + {i18n("common.disableChangingFromSummaryOption.helpText")} + +
+
); } + export default FieldEdit; diff --git a/designer/client/file-upload-field-edit.tsx b/designer/client/file-upload-field-edit.tsx index 7be3f57af3..bd64e80957 100644 --- a/designer/client/file-upload-field-edit.tsx +++ b/designer/client/file-upload-field-edit.tsx @@ -5,10 +5,15 @@ import { Actions } from "./reducers/component/types"; import { CssClasses } from "./components/CssClasses"; import { i18n } from "./i18n"; +const defaultOptions = { + multiple: false, + imageQualityPlayback: false, +}; + export function FileUploadFieldEdit() { const { state, dispatch } = useContext(ComponentContext); const { selectedComponent } = state; - const { options = {} } = selectedComponent; + const options = { ...defaultOptions, ...selectedComponent.options }; return (
@@ -22,21 +27,20 @@ export function FileUploadFieldEdit() {
{ - e.preventDefault(); dispatch({ type: Actions.EDIT_OPTIONS_FILE_UPLOAD_MULTIPLE, - payload: !options.multiple, + payload: e.target.checked, }); }} /> @@ -46,6 +50,35 @@ export function FileUploadFieldEdit() {
+
+
+ { + dispatch({ + type: Actions.EDIT_OPTIONS_IMAGE_QUALITY_PLAYBACK, + payload: e.target.checked, + }); + }} + /> + + + {i18n( + "fileUploadFieldEditPage.imageQualityPlaybackOption.helpText" + )} + +
+
+ ); diff --git a/designer/client/i18n/translations/en.translation.json b/designer/client/i18n/translations/en.translation.json index b5eac278e1..d6a58fe2ce 100644 --- a/designer/client/i18n/translations/en.translation.json +++ b/designer/client/i18n/translations/en.translation.json @@ -69,6 +69,22 @@ "detailsLink": { "title": "Additional settings" }, + "exposeToContextOption": { + "helpText": "If using additional context, choose this option to expose the field to be used by additional contexts", + "title": "Expose to context" + }, + "allowPrePopulationOption": { + "helpText": "Tick this box if you want this field to be available to be pre-populated by query parameter", + "title": "Allow pre-population" + }, + "allowPrePopulationOverwriteOption": { + "helpText": "Tick this box if you want query parameters to override state values for this field when passed in. This will only have an effect if 'Allow pre-population' is also ticked", + "title": "Allow overwriting from query parameter" + }, + "disableChangingFromSummaryOption": { + "helpText": "Tick this box if you want the change button to be removed for this field on the summary screen", + "title": "Disable changing from summary" + }, "helpTextField": { "helpText": "Enter the description to show for this field", "title": "Help text (optional)" @@ -204,6 +220,10 @@ "multipleFilesOption": { "helpText": "Tick this box to enable users to upload multiple files", "title": "Allow multiple file upload" + }, + "imageQualityPlaybackOption": { + "helpText": "If your document upload API assesses the quality of uploaded images, and you want to inform the user but don't want to stop them from continuing, check this box.", + "title": "Enable playback page for image quality checking" } }, "formDetails": { @@ -326,7 +346,9 @@ "outputEdit": { "notifyEdit": { "includeReferenceTitle": "Include webhook and payment references", - "includeReferenceHint": "If webhook or payment references are available, they will be included in Notify's personalisation object. The included fields are: hasWebhookReference (boolean), webhookReference: (string), hasPaymentReference: (boolean), paymentReference: string." + "includeReferenceHint": "If webhook or payment references are available, they will be included in Notify's personalisation object. The included fields are: hasWebhookReference (boolean), webhookReference: (string), hasPaymentReference: (boolean), paymentReference: string.", + "escapeURLsTitle": "Escape Notify encoded URLs", + "escapeURLsHint": "If you do not expect notify-encoded links to be passed through from your form, select this box to break this formatting. It is strongly recommended to enable this to prevent phishing attacks" } }, "page": { @@ -390,6 +412,10 @@ "titleField": { "helpText": "Appears above the page title. However, if these titles are the same, the form will only show the page title.", "title": "Section title" + }, + "hideTitleField": { + "helpText": "Tick this box if you do not want the section title to show on any pages in this section", + "title": "Hide section title" } }, "title": "Title", diff --git a/designer/client/list/ListEdit.tsx b/designer/client/list/ListEdit.tsx index 27de722ff2..5a9272a1b2 100644 --- a/designer/client/list/ListEdit.tsx +++ b/designer/client/list/ListEdit.tsx @@ -151,7 +151,12 @@ export function ListEdit() { {i18n("list.item.add")}
<> -
-
diff --git a/designer/client/outputs/__tests__/output-edit.jest.tsx b/designer/client/outputs/__tests__/output-edit.jest.tsx index 4fdecbfe7c..f0def08c7a 100644 --- a/designer/client/outputs/__tests__/output-edit.jest.tsx +++ b/designer/client/outputs/__tests__/output-edit.jest.tsx @@ -29,6 +29,7 @@ describe("OutputEdit", () => { ], outputs: [], conditions: [], + lists: [], }; }); @@ -103,6 +104,7 @@ describe("OutputEdit", () => { templateId: "NewTemplateId", apiKey: "NewAPIKey", emailField: "9WH4EX", + escapeURLs: false, addReferencesToPersonalisation: true, }, }, diff --git a/designer/client/outputs/notify-edit-items.tsx b/designer/client/outputs/notify-edit-items.tsx index a8f0308573..311c52802b 100644 --- a/designer/client/outputs/notify-edit-items.tsx +++ b/designer/client/outputs/notify-edit-items.tsx @@ -99,7 +99,12 @@ class NotifyItems extends React.Component { Notify template key -
+ Add diff --git a/designer/client/outputs/notify-edit.tsx b/designer/client/outputs/notify-edit.tsx index 8fae58414c..2ad372f3bd 100644 --- a/designer/client/outputs/notify-edit.tsx +++ b/designer/client/outputs/notify-edit.tsx @@ -33,7 +33,7 @@ class NotifyEdit extends Component { render() { const { data, output, onEdit, errors } = this.props; - const { conditions } = data; + const { conditions, lists } = data; const outputConfiguration = (typeof output.outputConfiguration === "object" ? output.outputConfiguration : { @@ -50,6 +50,10 @@ class NotifyEdit extends Component { name: condition.name, display: condition.displayName, })), + ...lists.map((list) => ({ + name: list.name, + display: `${list.title} (List)`, + })), ...this.usableKeys, ]; @@ -135,6 +139,24 @@ class NotifyEdit extends Component { name="add-references-to-personalisation" /> +
+ + {i18n("outputEdit.notifyEdit.escapeURLsTitle")} + + ), + hint: { + children: i18n("outputEdit.notifyEdit.escapeURLsHint"), + }, + value: true, + }, + ]} + name="escape-urls" + /> +
); } diff --git a/designer/client/outputs/output-edit.tsx b/designer/client/outputs/output-edit.tsx index 0e633d430f..80314f7c2b 100644 --- a/designer/client/outputs/output-edit.tsx +++ b/designer/client/outputs/output-edit.tsx @@ -83,11 +83,13 @@ class OutputEdit extends Component { emailField: formData.get("email-field") as string, addReferencesToPersonalisation: formData.get("add-references-to-personalisation") === "true", + escapeURLs: formData.get("escape-urls") === "true", }; break; case OutputType.Webhook: outputConfiguration = { url: formData.get("webhook-url") as string, + allowRetry: true, }; break; } diff --git a/designer/client/outputs/outputs-edit.tsx b/designer/client/outputs/outputs-edit.tsx index 361a96348d..f9799063a1 100644 --- a/designer/client/outputs/outputs-edit.tsx +++ b/designer/client/outputs/outputs-edit.tsx @@ -68,7 +68,11 @@ class OutputsEdit extends React.Component { ))}

  • - + Add output
  • diff --git a/designer/client/outputs/types.ts b/designer/client/outputs/types.ts index 6e2f9f60c0..241000da52 100644 --- a/designer/client/outputs/types.ts +++ b/designer/client/outputs/types.ts @@ -14,10 +14,12 @@ export type NotifyOutputConfiguration = { emailField: string; personalisation: string[]; addReferencesToPersonalisation?: boolean; + escapeURLs?: boolean; }; export type WebhookOutputConfiguration = { url: string; + allowRetry: boolean; }; export type OutputConfiguration = diff --git a/designer/client/reducers/component/componentReducer.options.ts b/designer/client/reducers/component/componentReducer.options.ts index c09d350056..ff346fadd9 100644 --- a/designer/client/reducers/component/componentReducer.options.ts +++ b/designer/client/reducers/component/componentReducer.options.ts @@ -53,6 +53,13 @@ export function optionsReducer(state, action: OptionsActions) { options: { ...options, multiple: payload }, }, }; + case Options.EDIT_OPTIONS_IMAGE_QUALITY_PLAYBACK: + return { + selectedComponent: { + ...selectedComponent, + options: { ...options, imageQualityPlayback: payload }, + }, + }; case Options.EDIT_OPTIONS_CLASSES: return { selectedComponent: { @@ -128,5 +135,37 @@ export function optionsReducer(state, action: OptionsActions) { options: { ...options, maxWords: payload }, }, }; + case Options.EDIT_OPTIONS_EXPOSE_TO_CONTEXT: + return { + ...state, + selectedComponent: { + ...selectedComponent, + options: { ...options, exposeToContext: payload }, + }, + }; + case Options.EDIT_OPTIONS_ALLOW_PRE_POPULATION: + return { + ...state, + selectedComponent: { + ...selectedComponent, + options: { ...options, allowPrePopulation: payload }, + }, + }; + case Options.EDIT_OPTIONS_ALLOW_PRE_POPULATION_OVERWRITE: + return { + ...state, + selectedComponent: { + ...selectedComponent, + options: { ...options, allowPrePopulationOverwrite: payload }, + }, + }; + case Options.EDIT_OPTIONS_DISABLE_CHANGING_FROM_SUMMARY: + return { + ...state, + selectedComponent: { + ...selectedComponent, + options: { ...options, disableChangingFromSummary: payload }, + }, + }; } } diff --git a/designer/client/reducers/component/types.ts b/designer/client/reducers/component/types.ts index ee4e8549e1..c0cf5c03d7 100644 --- a/designer/client/reducers/component/types.ts +++ b/designer/client/reducers/component/types.ts @@ -40,6 +40,7 @@ export enum Options { EDIT_OPTIONS_REQUIRED = "EDIT_OPTIONS_REQUIRED", EDIT_OPTIONS_HIDE_OPTIONAL = "EDIT_OPTIONS_HIDE_OPTIONAL", EDIT_OPTIONS_FILE_UPLOAD_MULTIPLE = "EDIT_OPTIONS_FILE_UPLOAD_MULTIPLE", + EDIT_OPTIONS_IMAGE_QUALITY_PLAYBACK = "EDIT_OPTIONS_IMAGE_QUALITY_PLAYBACK", EDIT_OPTIONS_CLASSES = "EDIT_OPTIONS_CLASSES", EDIT_OPTIONS_MAX_DAYS_IN_FUTURE = "EDIT_OPTIONS_MAX_DAYS_IN_FUTURE", EDIT_OPTIONS_MAX_DAYS_IN_PAST = "EDIT_OPTIONS_MAX_DAYS_IN_PAST", @@ -51,6 +52,10 @@ export enum Options { EDIT_OPTIONS_MAX_WORDS = "EDIT_OPTIONS_MAX_WORDS", EDIT_OPTIONS_PREFIX = "EDIT_OPTIONS_PREFIX", EDIT_OPTIONS_SUFFIX = "EDIT_OPTIONS_SUFFIX", + EDIT_OPTIONS_EXPOSE_TO_CONTEXT = "EDIT_OPTIONS_EXPOSE_TO_CONTEXT", + EDIT_OPTIONS_ALLOW_PRE_POPULATION = "EDIT_OPTIONS_ALLOW_PRE_POPULATION", + EDIT_OPTIONS_ALLOW_PRE_POPULATION_OVERWRITE = "EDIT_OPTIONS_ALLOW_PRE_POPULATION_OVERWRITE", + EDIT_OPTIONS_DISABLE_CHANGING_FROM_SUMMARY = "EDIT_OPTIONS_DISABLE_CHANGING_FROM_SUMMARY", } export const Actions = { diff --git a/designer/client/section/section-edit.js b/designer/client/section/section-edit.js index d23a006f5d..590e08a3a7 100644 --- a/designer/client/section/section-edit.js +++ b/designer/client/section/section-edit.js @@ -1,7 +1,8 @@ import React from "react"; import randomId from "../randomId"; -import { withI18n } from "../i18n"; +import { i18n, withI18n } from "../i18n"; import { Input } from "@govuk-jsx/input"; +import { Checkboxes } from "@xgovformbuilder/govuk-react-jsx"; import { validateName, validateTitle, @@ -11,6 +12,7 @@ import ErrorSummary from "../error-summary"; import { DataContext } from "../context"; import { addSection } from "../data"; import logger from "../plugins/logger"; +import { Actions } from "../reducers/component/types"; class SectionEdit extends React.Component { static contextType = DataContext; @@ -24,6 +26,7 @@ class SectionEdit extends React.Component { this.state = { name: section?.name ?? randomId(), title: section?.title ?? "", + hideTitle: section?.hideTitle ?? false, errors: {}, }; } @@ -35,11 +38,11 @@ class SectionEdit extends React.Component { if (hasValidationErrors(validationErrors)) return; const { data, save } = this.context; - const { name, title } = this.state; + const { name, title, hideTitle } = this.state; let updated = { ...data }; if (this.isNewSection) { - updated = addSection(data, { name, title: title.trim() }); + updated = addSection(data, { name, title: title.trim(), hideTitle }); } else { const previousName = this.props.section?.name; const nameChanged = previousName !== name; @@ -59,6 +62,7 @@ class SectionEdit extends React.Component { }); } copySection.title = title; + copySection.hideTitle = hideTitle; } try { @@ -110,7 +114,7 @@ class SectionEdit extends React.Component { render() { const { i18n } = this.props; - const { title, name, errors } = this.state; + const { title, name, hideTitle, errors } = this.state; return ( <> @@ -151,6 +155,27 @@ class SectionEdit extends React.Component { errors?.name ? { children: errors?.name.children } : undefined } /> +
    +
    + this.setState({ hideTitle: e.target.checked })} + /> + + + {i18n("sectionEdit.hideTitleField.helpText")} + +
    +
    {" "} diff --git a/designer/package.json b/designer/package.json index b1e341900c..10fb183c94 100644 --- a/designer/package.json +++ b/designer/package.json @@ -15,11 +15,11 @@ "lint": "yarn run eslint .", "fix-lint": "yarn run eslint . --fix", "symlink-env": "./bin/symlink-config", - "test": "yarn lint && yarn test-lab && yarn jest", - "test-cov": "yarn lint && yarn test-lab-cov && yarn jest && yarn merge-coverage", - "test:dev": "lab -T test/.transform.js test/.setup.js ./**/*.test.* -S -r console -o stdout -r html -o unit-test.html -I version -l --coverage-exclude client --coverage-exclude server --coverage-exclude config.js", - "test-lab": "lab -T test/.transform.js test/.setup.js ./**/*.test.* -S -v -r console -o stdout -r html -o unit-test.html -I version -l", - "test-lab-cov": "lab -T test/.transform.js test/.setup.js ./**/*.test.* -S -v -t 88 -r console -o stdout -r lcov -o test-coverage/lab/lcov.info -r html -o test-coverage/lab/unit-test.html -r junit -o test-results/lab/unit-test.xml -I version -l", + "test": "yarn lint && yarn test:dev && yarn jest", + "test-cov": "yarn lint && yarn test:dev && yarn jest", + "test:dev": "lab -T test/.transform.js test/.setup.js ./**!(node_modules)/*.test.* -S -r console -o stdout -r html -o unit-test.html -I version -l --coverage-exclude client --coverage-exclude server --coverage-exclude config.js", + "test-lab": "lab -T test/.transform.js test/.setup.js ./**!(node_modules)/.test.* -S -v -r console -o stdout -r html -o unit-test.html -I version -l", + "test-lab-cov": "lab -T test/.transform.js test/.setup.js ./**!(node_modules)/*.test.* -S -v -t 88 -r console -o stdout -r lcov -o test-coverage/lab/lcov.info -r html -o test-coverage/lab/unit-test.html -r junit -o test-results/lab/unit-test.xml -I version -l", "jest": "yarn jest:client && yarn jest:server", "jest:client": "jest --coverage --config=jest.client.config.js -w", "jest:server": "jest --coverage --config=jest.server.config.js --runInBand", @@ -53,12 +53,13 @@ "hoek": "^6.1.3", "i18next": "^21.6.12", "i18next-http-backend": "^1.3.2", - "joi": "17.2.1", - "jszip": "^3.7.1", + "joi": "^17.9.1", + "jszip": "^3.10.1", "lodash": "^4.17.21", "nanoid": "^3.3.4", "nodemon": "^2.0.20", "nunjucks": "3.2.1", + "path-to-regexp": "1.8.0", "react": "16.13.1", "react-dom": "16.13.1", "react-helmet": "^6.1.0", @@ -71,23 +72,20 @@ "yar": "^9.1.0" }, "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.1", - "@babel/eslint-parser": "^7.17.0", - "@babel/eslint-plugin": "^7.16.5", - "@babel/node": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/cli": "^7.23.3", + "@babel/core": "^7.23.3", + "@babel/eslint-parser": "^7.23.3", + "@babel/eslint-plugin": "^7.22.10", + "@babel/node": "^7.22.19", + "@babel/plugin-proposal-export-default-from": "7.23.3", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-runtime": "^7.17.0", - "@babel/preset-env": "7.16.11", - "@babel/preset-react": "7.16.7", - "@babel/preset-typescript": "^7.16.7", - "@babel/register": "7.17.0", - "@babel/runtime": "7.17.2", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-runtime": "^7.23.3", + "@babel/preset-env": "^7.23.3", + "@babel/preset-react": "^7.23.3", + "@babel/preset-typescript": "^7.23.3", + "@babel/register": "^7.22.15", + "@babel/runtime": "^7.23.3", "@hapi/code": "^8.0.7", "@hapi/eslint-plugin": "^6.0.0", "@hapi/lab": "^24.5.1", @@ -97,7 +95,6 @@ "@types/dagre": "^0.7.47", "@types/hapi": "^18.0.7", "@types/node": "^17.0.21", - "@types/pino": "^7.0.5", "@types/react": "^17.0.39", "@types/react-dom": "^17.0.11", "@typescript-eslint/eslint-plugin": "^5.13.0", @@ -106,7 +103,7 @@ "acorn": "8.7.0", "autoprefixer": "^10.4.2", "babel-eslint": "^10.1.0", - "babel-loader": "^8.2.3", + "babel-loader": "^8.3.0", "babel-plugin-module-name-mapper": "^1.2.0", "babel-plugin-module-resolver": "^4.1.0", "babel-plugin-transform-import-ignore": "^1.1.0", @@ -135,7 +132,9 @@ "jsdom": "^19.0.0", "lcov-result-merger": "^3.1.0", "mini-css-extract-plugin": "^0.11.2", - "msw": "^0.47.4", + "msw": "^1.3.2", + "nodemon": "^2.0.20", + "nunjucks": "^3.2.3", "postcss": "^8.2.4", "postcss-loader": "^4.1.0", "prismjs": "1.27.0", @@ -145,7 +144,7 @@ "sinon": "^13.0.1", "standard": "16.0.4", "ts-node-dev": "^1.1.8", - "typescript": "^4.1.3", + "typescript": "4.9.5", "webpack": "^4.44.2", "webpack-bundle-analyzer": "^4.3.0", "webpack-cli": "^3.3.12", diff --git a/designer/test/.transform.js b/designer/test/.transform.js index 8bcad41c89..cfd2cc64c9 100644 --- a/designer/test/.transform.js +++ b/designer/test/.transform.js @@ -55,9 +55,9 @@ internals.transform = function (content, filename) { auxiliaryCommentAfter: "$lab:coverage:on$", plugins: [ "@babel/plugin-proposal-export-default-from", - "@babel/plugin-proposal-class-properties", - "@babel/plugin-proposal-private-property-in-object", - "@babel/plugin-proposal-private-methods", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-private-property-in-object", + "@babel/plugin-transform-private-methods", "@babel/plugin-transform-runtime", "@babel/plugin-syntax-dynamic-import", [ diff --git a/designer/webpack.config.js b/designer/webpack.config.js index 7d56bb0813..8ded84cd1d 100644 --- a/designer/webpack.config.js +++ b/designer/webpack.config.js @@ -37,7 +37,12 @@ const client = { rules: [ { test: /\.(js|jsx|tsx|ts)$/, - exclude: /node_modules/, + exclude: [ + { + test: /node_modules/, + exclude: /pino/, + }, + ], loader: "babel-loader", }, { diff --git a/docker-compose.smoke.yml b/docker-compose.smoke.yml index e72ebf0af8..759bdc52ea 100644 --- a/docker-compose.smoke.yml +++ b/docker-compose.smoke.yml @@ -36,6 +36,8 @@ services: - sandbox=true - PREVIEW_MODE=true - NODE_ENV=test + - ALLOW_USER_TEMPLATES=true + - NODE_CONFIG={"documentUploadApiUrl":null} command: yarn runner start depends_on: - redis diff --git a/docker-compose.yml b/docker-compose.yml index 08a2c8f161..974f65cca5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,11 +40,59 @@ services: - PREVIEW_MODE=true - LAST_COMMIT - LAST_TAG + # - ENABLE_QUEUE_SERVICE=true + # - QUEUE_DATABASE_URL=mysql://root:root@mysql:3306/queue # or postgres://user:root@postgres:5432/queue + # - DEBUG="prisma*" + # - QUEUE_TYPE="MYSQL" command: yarn runner start depends_on: - - redis + redis: + condition: service_started + # mysql: + # condition: service_healthy redis: image: "redis:alpine" command: redis-server --requirepass 123abc ports: - "6379:6379" +# if using MYSQL, uncomment submitter +# submitter: +# image: digital-form-builder-submitter +# build: +# context: . +# dockerfile: ./submitter/Dockerfile +# ports: +# - "9000:9000" +# environment: +# - PORT=9000 +# - QUEUE_DATABASE_URL=mysql://root:root@mysql:3306/queue +# - QUEUE_POLLING_INTERVAL=5000 +# - DEBUG="prisma*" +# command: yarn submitter start +# depends_on: +# mysql: +# condition: service_healthy +# mysql: +# container_name: mysql +# image: "mysql:latest" +# command: --default-authentication-plugin=mysql_native_password +# ports: +# - "3306:3306" +# environment: +# MYSQL_ROOT_PASSWORD: root +# MYSQL_DATABASE: queue +# healthcheck: +# test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] +# timeout: 20s +# retries: 10 + +# use psql if you want a PostgreSQL based queue (recommended) +# postgres: +# container_name: postgres +# image: "postgres:16" +# ports: +# - "5432:5432" +# environment: +# POSTGRES_DB: queue +# POSTGRES_PASSWORD: root +# POSTGRES_USER: user diff --git a/docs/adr/0003-submitter-diagram.svg b/docs/adr/0003-submitter-diagram.svg new file mode 100644 index 0000000000..cc93e82dc8 --- /dev/null +++ b/docs/adr/0003-submitter-diagram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/adr/0003-submitter.md b/docs/adr/0003-submitter.md new file mode 100644 index 0000000000..1cb3b72967 --- /dev/null +++ b/docs/adr/0003-submitter.md @@ -0,0 +1,67 @@ +# Submitter and DB queue + +- Status: [ accepted ] | superseded by [ADR-0004](./0004-submitter.md) +- Deciders: FCDO / OS maintainers: [@jenbutongit](https://github.com/jenbutongit) [@superafroman](https://github.com/superafroman) +- Date: [2023-07-14] + +## Context and Problem Statement + +After a user submits their form, if there is an issue with submission, whether on the runner side, or webhook, this submission is essentially "lost". + +We do provide logging of the full payload if there is an error, however would require support staff to manually re-enter details. + +## Decision Drivers + +- We have "lost" submissions due to webhook errors +- It is likely all transactional services will require to implement a queue or some failsafe to ensure submissions aren't lost + - We are building a new service built in node, so have decided to implement this directly into the form builder + +## Considered Options + +Terminology: + +- Submission: User's data to be sent to a webhook +- Submitter: A new process which will become responsible for POST-ing or PUT-ing data to the webhook +- Queue: A database which will store a user's submission. This can also be used for auditing purposes + +### Option 1 + +1. After a user submits a form, push the payload into the database, including any additional information required +2. A separate microservice "Submitter" will poll the database for unsent or failed entries +3. Submitter posts to the webhook, and the webhook will respond to the submitter +4. On response, update the entry and flag it as "successful" with reference code if applicable +5. The runner will continuously poll the database for 2 seconds to check if there is an update or reference number +6. As long as the database insertion described in (1) is successful, the user will see the success page + +[Prisma ORM](https://www.prisma.io/) will be used. This will allow us to use the same interfaces, regardless of which database you wish to use. +Prisma supports PostgreSQL, MySQL, MariaDB, SQLite, AWS Aurora (inc serverless), Microsoft SQL Server, Azure SQL, MongoDB, CockroachDB. +[Full details on supported versions on their website](https://www.prisma.io/docs/reference/database-reference/supported-databases). + +Prisma will be able to generate migrations for your new or existing database. + +### Option 2 + +1. After a user submits a form, push the payload into the database, including any additional information required +2. A separate microservice "Submitter" will poll the database for unsent or failed entries +3. Submitter posts to the webhook, and the webhook will respond to the submitter +4. On response, update the entry and flag it as "successful" with reference code if applicable +5. The runner will continuously poll an endpoint on the submitter, like `/status` rather than the database directly + +- This allows us to manage database connections or lockups, and allow us to apply rate limiting however will take more time to implement + +### Option 3 + +Use a native queue service, like SQS. + +## Decision Outcome + +Option 1 for now, however an upgrade to Option 2 will be possible. + +Most transactional services will already have a database, or be able to provision one simply. +Databases are easily set up via Docker, enabling faster local development. We will also circumvent any vendor lock-in this way (AWS vs Azure vs GCP), +however, given a strong need from the OS community, adapters or subclasses can be written at a later date. + +You will not be required to use this new process, however will be advised that you do! +You will also be able to implement your own submitter if you do not want to use this solution. + +See supplementary sequence diagram [0003-submitter-diagram.svg](./0003-submitter-diagram.svg) diff --git a/docs/adr/0004-submitter.md b/docs/adr/0004-submitter.md new file mode 100644 index 0000000000..49d52178f6 --- /dev/null +++ b/docs/adr/0004-submitter.md @@ -0,0 +1,41 @@ +# Submitter and DB queue - Upgrade to PostgreSQL and pg-boss + +- Status: [ accepted ] +- Deciders: FCDO / OS maintainers: [@jenbutongit](https://github.com/jenbutongit) [@superafroman](https://github.com/superafroman) +- Date: 2024-01-12, updated 2024-01-17 + +## Context and Problem Statement + +This is an addition to [0003-submitter.md](./0003-submitter.md). ADRs 0003-submitter and 0004-submitter aim to make your services more reliable and resilient. + +As stated in [0003-submitter.md](./0003-submitter.md), an upgrade to option 2 would be possible. +~~Instead of polling a database for the reference number, it will make a GET request instead. This allows for better microservices architecture.~~ +To simplify architecture, for now, we will use the pg-boss utility method `getJobById`. Other queues do not typically implement this. + +## Decision Drivers + +### Better architectural decoupling (microservices) + +When queues are enabled the database, runner, submitter, and webhook endpoints are tightly coupled. Each of the services (runner, submitter and webhook) +are communicating via a single entry. If the schema is required to change, it creates a breaking change across all 3 services, and the deployments need to be coordinated. + +By only allowing the runner to submit to a queue, and poll reference numbers via an API, we remove the coupling from the runner. It no longer needs to keep track of the databases' schema. + +### Performance + +#### PostgreSQL and pg-boss + +pg-boss relies on PostgreSQL to queue jobs and easily allow processing of jobs. It also leverages node's event features (e.g. events and event emitter) to improve performance. +PostgreSQL has features with messaging built in mind, for example SKIP LOCKED to ensure rows are not being read or written by different processes. The MySQL based submitter does not currently do this. + +### Support/Maintenance + +Pg-boss is a lot more feature rich than our mysql based submitter. It has support for exponential backoff, pub/sub, automatic creation of tables and more. +It's far too much for us to write our own equivalent! There are some equivalent libraries available for MySQL, but are not as feature rich, or as well maintained. + +The pg-boss implementation will also allow easier support for other queues, like SQS, Kafka, RabbitMQ. All with their own libraries or SDKs that allow events to be emitted and consumed easily. + +### Negative Consequences + +- The MySQL queue is likely to be deprecated due to support/maintenance overheads. +- For the time being, both queue types will be supported, which means that there is more code to maintain and some additional complexity diff --git a/docs/adr/0005-runner-pulls-from-source.md b/docs/adr/0005-runner-pulls-from-source.md new file mode 100644 index 0000000000..06e386b0f5 --- /dev/null +++ b/docs/adr/0005-runner-pulls-from-source.md @@ -0,0 +1,43 @@ +# Change the runner to pull forms from a source + +- Status: [proposed] +- Deciders: OS maintainers [@jenbutongit](https://github.com/jenbutongit) [@superafroman](https://github.com/superafroman) [@ziggy-cyb](https://github.com/ziggy-cyb) +- Date: [2023-11-28 when the decision was last updated] + +## Context and Problem Statement + +Currently, when the user saves the form, it sends the entire form to the server, which optionally saves the form to S3 if configured, then +sends a post request to the runner (in preview mode), to `/publish`, and the form is initialised and saved in memory. + +For production environments, we recommend that you replace the docker images files `dist/server/forms` with the forms that should be available on startup, and have PREVIEW_MODE turned off. + +## Decision Drivers + +- Desire to make this into a SaaS product! +- Forms can be accessed when published, without having to redeploy + +## Considered Options + +- [option 1] Forms are no longer "pushed" to the runner. The runner would be configured with a source + (e.g. S3, mountpoint/filesystem/database/designer) and would pull forms and initialise them if requested. + +## Decision Outcome + +Chosen option: + +## Pros and Cons of the Options + +### [option 1] + +When a user requests a form at /forms/:id, the runner will pull from the configured source, and initialise the form. +This gives developers flexibility on how they wish to store, manage and "publish" forms. Newly published forms will therefore always be "available". + +When horizontally scaling the pod, it does not need to initialise all the forms that have been published or on the image, only the ones that were requested of that pod. +There may still need to be a way to "register" which pods have which forms, and prioritise requests to pods that have the form already initialised. +Session stickiness may also be required (to prevent a user from being redirected to a pod that does not have the form initialised). + +Handling different versions of forms should also be considered. We can send, in the metadata, the version of the form. The webhook can then determine what to do with this version. + +For the designer "source", we would just be moving the /publish and /published endpoints from the runner to the designer. + +### [option 2] diff --git a/docs/adr/0006-atomic-saves.md b/docs/adr/0006-atomic-saves.md new file mode 100644 index 0000000000..a68610ed17 --- /dev/null +++ b/docs/adr/0006-atomic-saves.md @@ -0,0 +1,88 @@ +# Designer - Atomic saves on the server + +- Status: [proposed] +- Deciders: OS maintainers [@jenbutongit](https://github.com/jenbutongit) [@superafroman](https://github.com/superafroman) [@ziggy-cyb](https://github.com/ziggy-cyb) +- Date: [2023-11-28 when the decision was last updated] + +## Context and Problem Statement + +Currently, when a form is edited, changes are made to a version of the form saved in memory on the browser (react state). +When the user saves, it sends the entire form to the server to be validated and then persisted. + +## Decision Drivers + +- Handling state (entirety of the form) on the client can get complex and difficult to test +- Saving "chunks" of the form can help with analytics or future features like edit history +- The designer is entirely client side rendered, it will not work without javascript enabled + - React server side components is not performant. (Neither is React for that matter!) +- By splitting the designer, it allows the community to "bring their own frontend" (they do not need to use GOV.UK styles) + +## Considered Options + +- [option 1] Move persistence to the designer server, and make the form a RESTful resource + - When the user edits a component, or page etc, this should send a request to the designer server, save, and return the updated form. The server becomes responsible for making the mutation to the persisted form. + - Since every "thing" in the form (components, page, etc) has an id, and some "things" being nested children (like list items or components), form JSONs can easily follow a RESTful structure. +- [option 2] Rewrite the whole thing in Svelte(Kit) (or more sensibly, next.js) + +## Decision Outcome + +Chosen option: [option 1]. + +### [option 1] + +Most of the application is using reducers to manage state. For example, list reducers, are already split into distinct actions. +That gives us the option to + +- migrate gradually, action by action +- migrate gradually, by reducer type (list, component, page) + +At first, the designer (client) will have to construct the URLs for the request. + +The form resource may look like this: + +``` +GET | POST | PUT /forms/:id +GET | POST | PUT /forms/:id/pages/:pagePath +GET | POST | PUT /forms/:id/pages/:pagePath/next +GET | POST | PUT /forms/:id/pages/:pagePath/title +GET | POST | PUT /forms/:id/pages/:pagePath/components/:componentId +GET | POST | PUT /forms/:id/lists/:listId +GET | POST | PUT /forms/:id/lists/:listId/items/:itemId +``` + +The post requests, can send an action name, and the payload (this is how the reducers currently work), and the server will make the change. + +The get request can either be used to just return the JSON, or render the page which allows the user to edit this component. +For example, to edit the component "name" on "/passport-details", the URL would be `/forms/:id/pages/passport-details/components/name`. +When the user submits the form on this page, it will post the same URL, with the action and payload. We can then use the post, redirect, get pattern to render the page with errors (if any). + +#### Positives + +- Accessibility and usability + - React and "the React way" makes it difficult for developers to think about accessibility and usability +- Handling multiple versions of the schema is simpler. We can just mount the routers to /v1, /v2 +- Testing is simpler +- More developer "concurrency" (both frontend and backend development can happen simultaneously) +- No longer mutating the entire form and sending, which makes the editing process "safer" +- We can explore using GOV.UK nunjucks to render the pages in future, which allows us to keep components up to date easily. React GOV.UK components are only provided as open source projects + +#### Negatives + +Client side rendering is often a consideration to reduce server load, so we will be losing this. But at low volumes of traffic it is not a concern. +It's also a lot of work (even if it can be done incrementally) + +### Rewrite in a web meta framework like next.js + +#### Positives + +Following the same API design as option 1, we would use next.js (because it is already compatible with react). Next.js can provide server side rendering, and file system based routing. +Developer experience of meta frameworks is typically very good. + +#### Negatives + +This would have to be worked on in parallel to the current designer, and released all at once. It also introduces tight coupling between the server and frontend. + +## Links + +- [Link type] [Link to ADR] +- … diff --git a/docs/adr/0007-mid-journey-save-return.md b/docs/adr/0007-mid-journey-save-return.md new file mode 100644 index 0000000000..050bed29c8 --- /dev/null +++ b/docs/adr/0007-mid-journey-save-return.md @@ -0,0 +1,215 @@ +# Mid journey save and returns + +- Status: [proposed] +- Deciders: OS maintainers [@jenbutongit](https://github.com/jenbutongit) [@superafroman](https://github.com/superafroman) [@ziggy-cyb](https://github.com/ziggy-cyb) + +- Date: [2024-06-13 when the decision was last updated] + +## Context and Problem Statement + +It is currently possible to inject a full or partial session _into_ the runner, but it is not possible to send session data +externally in the middle of a form. For long forms, or forms which require the user to get a document or find out more +information, they are unable to exit the form without losing all their data. + +## Considered Options + +- Option 1 + - Add a flag, or flags (perhaps on certain pages only?), to the form configuration, e.g. `allowSaveAndExit`, which will render a `Save and exit` button at the bottom of each question page + - The data is then POSTed to a 3rd party application, which will then store the data in their chosen database + - Optionally, add a data format to webhook outputs, which matches the state as stored in redis + - Optionally, add a data format to the `/sessions/{formId}` endpoint, which matches the state, as stored in redis + - The 3rd party application must also handle rehydrating the user's session, and managing how they re-enter the application + - after successful exit, show the user a success screen (customised similarly to the current application complete page), or allow the user to be redirected externally. +- Option 2 + - Add a flag, or flags (perhaps on certain pages only?), to the form configuration, e.g. `allowSaveAndExit`, which will render a `Save and exit` button at the bottom of each question page + - The runner stores this in redis with a longer ttl, or another database (possibly postgres), and sends the user a link so that they can return to their session + - after successful exit, show the user a success screen (customised similarly to the current application complete page), or allow the user to be redirected externally. + +## Decision Outcome + +## Decision Outcome + +Chosen option: "[option 1]", only teams with developers have asked for this feature. This will help us reduce the maintenance burden. +It also allows for flexibility on how users return to their journey (e.g. you may have a "task list" page on your application, which is authenticated). + +## Pros and Cons of the Options + +### [option 1] + +- Good, because it encourages engineers to develop in a microservice architecture. In future, if the runner needs to be replaced, + you will not need to rewrite the session hydration part of the application. +- Good, because teams looking to implement this feature may already have a preferred data store, and possibly an API which can serve this data. + XGovFormBuilder will not lock teams into tech they are not familiar with, or add superfluous tech to their stack +- Good, because the only "required" additional technology XGovFormBuilder requires is currently Redis. + However, Redis is not designed for long term storage. +- Good, because it does not lock teams/users into a specific user journey. In this instance, we would only allow users to return via a URL emailed to them. +- Bad, because it raises the bar to entry, a development team will be required. + +We have also suggested that we add additional data formats to /sessions/{formId} and the webhook output. This is to improve +developer experience and simplify making session rehydration calls. The webhook output format which is required by /sessions/{formId} +is fairly verbose. It includes information like the page title, section, key and answer. This is so that there is reduced +data loss, in the event that forms are changed. Unrecognised keys can still be placed in a generic description field, along with the page title. + +Some teams may only care about the key/answer, and accept the risk or have mitigated it in other ways when components names have changed. +This means that there would be an extra step for them to translate to/from this data format. + +The data format changes can be worked on separately to the save and return feature, but this is a good time to add additional support. + +Below is a comparison of the webhook format, and the state format. + +In redis, the data will be stored like so + +```json5 +{ + progress: [], + checkBeforeYouStart: { + ukPassport: true, + }, + applicantDetails: { + numberOfApplicants: 2, + phoneNumber: "123", + emailAddress: "a@b", + languagesProvided: ["fr", "it"], + contactDate: "2024-12-25T00:00:00.000Z", + }, + applicantOneDetails: { + firstName: "Winston", + lastName: "Smith", + address: { + addressLine1: "1 Street", + town: "London", + postcode: "ec2a4ps", + }, + }, + applicantTwoDetails: { + firstName: "Big", + lastName: "Brother", + address: { + addressLine1: "King Charles Street", + town: "London", + postcode: "SW1A 2AH", + }, + }, +} +``` + +When making calls to /sessions/{formId}, the payload can be shortened slightly from the webhook output, since `question`, `title`, and `type` are not required. + +```json5 +{ + name: "Digital Form Builder - Runner undefined", + metadata: {}, + questions: [ + { + category: "checkBeforeYouStart", + fields: [ + { + key: "ukPassport", + answer: true, + }, + ], + index: 0, + }, + { + category: "applicantDetails", + fields: [ + { + key: "numberOfApplicants", + answer: 2, + }, + ], + index: 0, + }, + { + category: "applicantOneDetails", + fields: [ + { + key: "firstName", + answer: "Winston", + }, + { + key: "lastName", + answer: "Smith", + }, + ], + index: 0, + }, + { + category: "applicantOneDetails", + fields: [ + { + key: "address", + answer: "1 Street, London, ec2a4ps", + }, + ], + index: 0, + }, + { + category: "applicantTwoDetails", + question: "Applicant 2", + fields: [ + { + key: "firstName", + title: "First name", + type: "text", + answer: "big", + }, + { + key: "lastName", + title: "Surname", + type: "text", + answer: "brother", + }, + ], + index: 0, + }, + { + category: "applicantTwoDetails", + question: "Address", + fields: [ + { + key: "address", + title: "Address", + type: "text", + answer: "King Charles Street, London, SW1A 2AH", + }, + ], + index: 0, + }, + { + category: "applicantDetails", + fields: [ + { + answer: ["fr", "it"], + key: "languagesProvided", + }, + ], + index: 0, + question: "Which languages do you speak?", + }, + { + category: "applicantDetails", + fields: [ + { + key: "phoneNumber", + answer: "123", + }, + { + key: "emailAddress", + answer: "a@b", + }, + { + answer: "2024-12-25", + type: "date", + }, + ], + index: 0, + }, + ], +} +``` + +### [option 2] + +- Good, because it simplifies enabling this feature. External applications/microservices do not need to be written. +- Bad, because it may require teams to run additional databases. XGovFormBuilder maintainers will need to write multiple adapters for different types of databases. diff --git a/docs/designer/query-param-field.png b/docs/designer/query-param-field.png new file mode 100644 index 0000000000000000000000000000000000000000..a937abd2c4f74d93722a334b8da1f59dd6cadba3 GIT binary patch literal 195515 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

    f%l!PN}V)24`PYT^+bCZ-wx#}g^m$+t! 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�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�Pmy*|hZ?BL{TA6OQr2cPullU-iT ziFJ=^)n}B$&mV?4~Q?%rT?czrsi6c2|iv`G335pHlE& zD=CI;lzIDPVoO`8ZTj-mVyLo1_C}9_2va_DdOqXU40|nmed%6k6Y;Mr8e<&Sy6+Sl zl58N4@Ed5F-WOAptH!2&Yq{G4ej{akk9zLW$UBW1d#KgCJalOF@;F*bCfgz|Oa|=r zglrXLcu#Z$*w?$JfZ{xGlXY``K-GAnqL0+%MX0d8##q+KSk{xT#Nr0i4MbDmp`27U zj@{|imbrJ8!$|krEvZ`MxVNaek$ifu3Gyl&R5_rOrxMTAEb43?<5U3Jq+wVd0M62u zc*b5dgP90mRuvdsS15xi*y7OC&ca7em&Pk%sLESMj`!Crf#8O&k-+_W%Hx2nY1VLk zY$fm@)z^EXa{IKZQBF~rHL$kn(ckJYf8|^}pVXw%OVlfKwUEfvq_wiM)q}~C`N{yk z?@1-N$*H4Seeot*Q~eU-)G^nbm=?$Fwfsza$;YyJ*x0G?=od-KwpN%g!2RI2ITPMA zCs>dkT-$yG%8XOtdy7BZ0WL6hSrp()*yxMv>=!4AE;Z7D0+)xB*7YB}{i5Lz~91gw`pd!GL>t8r^>n!@S zN=tg%yewzYHIND}KQp%%Z!|C{%U!FcmlD_-u-8h7v&1~Is$X{2C*JiJlWizwhr6?) z4US{+O3gaCgA@L?prd~kV6UNq3=c|}>>%O{1#EfF8W0;$7^~O*0I+yzYL+vGLY`Mu zqdsUQzUqa>uFALj&>>snb~ycDU>T%=YmaQSeV;rtu8-&j+&^O z`tK~i!hN07{X9)9@}-+T-&01uP(cjL>RLF%N^VwuD_Jx3-(qtXH*uvehHq$3-lS?4 z!q2Vyuw`wqG6YN{H7cB=dhJ?3HMz1fUc$5MFbyLj;|;!n*^z3eSUnZLbD;G>d@`>Z zWMs+Bhfd$6G>u|ajbsWGzkeKj$K+AeEPjU@dX0^)mxoeK_crIr9jwX$+56g?4J*R} zp0HiuZV5j@dkqsP{#jcI_Pk7T17&jyiF|TDeY;9iQQzd64?9kDs;z?{BpIZ&H~GhlNfw&b;)1`{CbS(Uk{}{7_20Ja>Yt z7m%UBYqN+(L6d`~-3PL4+a8?}(RLARud5q9G1XI4S3|_=Hg2H_1*B#kU7{&(@;Jyn zO9G?TYm<5cw_)^^%$j`K<1XjK)`fm^`vD-_)hEg5eO(L&>C+AjU7JaMvAtfy)t6V* zU>H`vFyc7rlNi+Z2o)EY*Lth`7SiXG`!Y1>%r{7I=%3O5?HdmXv!coUBg7jS`~iH6 z{kq3E)=9_DyntB^Uw$1jP`gkLNy(GBSta6yAFQGsA}znJQ&F6MqirgX?pmH>)f%;F zT&s%%S&;k23nP|^Gm{YIiK$)S-s>+0`YDDz__TlIwXcGLKF?L#bfyBOebd*tbZc}4f*$XU`>s0TP z*5$p(<{0F!RzO^iqh70HqlibGr(* z=q|H_kxCBKx|V}9SWj=G@YQ7>v+>}8$f5-@#5!D5`yys(!K$T7iQ0`9jK-{;?Zsec zwVU}j-|5bIPwpHc25`)$v`({B;#N}K=5^n@1#3CdBE(jP8Q<%VkX_${}}Zv5sqk-DjLdGjHuVI(okcZ^7HLbkH?`$G0 z$qvYCY{{T|41zKL0NtM62zIA2^?IIrqfsxkUw38w*&hU$Zxbj}`Nz|9Tib6E*TT}~ic`&)a&=n|L5dgv+( zQUBIPV;Vup#%yA|DBJ9K$)_eLk}5Hxe=( zf&$09u~leNv?BUGPQHp&#|(-yo#ZlEml+5VTke0Ft z5N35g)bJy6sl*!2vo_!2qs5Y1IYbel-4Z-=YJdixjOB>B{m&VmvzRm#l$e|D$ z`zW3N(pM~y8_<{JKan&%^^ctug|+_UI0kusS^-;E?fCS7G8?s`D?eIS(4S01I^0n>6eHn?I75185W*YGIlU$%1o|@ zt!2p4cd2SRcvChf*XH-G zN2f=CGavl#Hd7aMnSR0$(l+TqiBP4J5fP>3gCYsmexkugttKI4WH$mj^+<++?Q{%J~-KG+Crqc8y0I# zK@fV-f%&bW@T7sZvMr(`98{k)SmIv7XF5|lb-C8^u?h!*M()tOmJP^W?hy+O9pP}& z8jXf!Alx-{sE4>1zwXF~F$QvcDrBeX2yjfj5LDawMgOJc*i1Dux5#G08v>6GLR`2knw zGX^uO$)5mx^`#_))Gac}I0OJ<>LXUZow@Dlp3-i%cw@^aK<(-oEtVq-y94FuY5#~W zx)dAjQ;xgp5<5Td!hsobT&q(ghpWSrO1qDwh-wnM%9n%wO?^XOt|9L^AQkq2Y8kytgaN z1E;&!S@E2V(+@~CE96*%?w{!JodfYzRjbo_VV|aWY2xW1o@qn9Mb4Bh&2bx^$g6)5 zd3kGd9Gm}xb!)Ta`ZL> z*--VXcdkb`|IN?kqWMNUK>w-AFo0dTvf(vYfM5;A!SN09Luq59VT0jKJ4~)H=S8uq z_)hN&B6U7*hLjI=T-p6*IEU&qkVCI|ryc@;YAa-2W_NsEm&~Sq?i#_Ro>|4e$nbDE z-6b6Fg{rXW;VF;(f8ISY@Q81s&7t8nVD~!0p8vIb(d@EPGF-AP>1w>MeNb0OsVULA z6q-~oZ}ahI4IfSW%s>X(=1!b8yl{gLCiAfiLfQ1ig`M+lQ6U548D2>9r3ir5$tV`~ z;u}k8569E4nK&$skPLOzZO@Yr6eFkjK{e$NeGJ-R9)Mxh>NT_yae!N?EKEpB-R8b=pd9K!y)wc8f+QX%zw^9SZ6s6H-@EeV_Vhso>!>z-PiG0h zwyzl(JNg4OiX-k*;}5^9>pRJJSeO*=0hn@r5iW?!Df9QEjXILEh9&^OM2@Qq;AW;-s)9Ec+bM`Zq!Ka_m}p5NTL7e z9Okr9n3!|-8m9H-G33sF7^}6oyB4y{eoi z7rM(>KBTTiXy7Dwd3hqvd;~GwqiSiri;e*XsmEw*3Se_FsborIHpjB<^H8 zQ_XiqGYQ}H7XhXHzCGDiywSI(_ynsRY;R2XgFL+66PxB4;8tuhRgI{}Axm+`q7L6F zJ+bCG7P8o&)6nbAxBg0Fz3?GFfFu~eBV9H*9j}vogyozMlI+R)9Z+r*J^&dL?MnyL2f~ZMCaf7Q@i=*TEg&8H8;SEXC%}Zw zh&+G^w_qnO?YvcVs&XJG>Q}uyU(Ja-oeCQ|lU3ekF8@2NDNqr6dD+oUdhSo7wv^IK z3WJ8c*lRnvCL-?%!DMV!n;gTEF34iGfoVB0=$@Z-)iXI%xvV$F<=c2(AjHzBjual< zgx9kqEAI5hXH5eyxHvswRBeyh4(xc4%!uKzE)8g<5*GpD4xuV>O!w(U0c2QPLzMZW z=>v=(%+ZLCG^exv#=L0xabr(9*}XEyeK5x4eOWPi48+NJBt}W4rg#Ww+vQ+KY2f1^ z0T|VkCwJ`KU^m9AKrE+>*ggTVPoh0~abjD2eKr#uMlD!)@9S`l~5a&k{y!XH2x#d@%^6^c1Zzrx3CMqddq zVXU9l8h1hcc2z0>_S3Mv$x!U&yS3;0)AGH=8zaKiBd~G%cD5L7%e`7M>^oCuQSAml zFJbJsZOj3i{$?DxjlO>jsB6b{2Z%OVzShg-OpJD?3gaye1_R;aj%7e-<;o`RhBom@ z^=2@+jT-SC(<`u9$?z6x!uabE-VrVCj-dk&QoK+AS01WtZKNXKegvlbgqWLg9_qy? z?Oimmb7ZaIujVAdI=r{yIB|B(a`T;{VJ~el(e6eZN%VII?K^3fZ8uA#cF}Fyj+EPk^{?V4R}(d0dT5 zTpy{h#fD(jRaL^OD{Nt(Y(*=o&JHerzB9X82ggHs$45QzKqV7eFq5SKJ{O|5T6tWo zdtSNr(#;US0Shw$ebkXvpw8ydBWc^qTI0}*2;69OL^O!GEgRV8%KBhW7UMNyvDBPM z50-thE5DA~S;UKz@){7ecd=gkMgZHGca{6-3b(VrGn7h4yP69hryJsWWOA<-Pt*r( zd{$<^PDqBe!Ku{Zk7MvPg5ckuTx%Tapgp2;>#I4p9O%|vl&?&;(RmGI1-G9f&-POU zEx+hRO`oVx+;bTgsG6}YX)*~igg@|g~)lu`a8YLd82G6O_Suj@h)VT{Oi z<5TmeLrVs|c2iO^>?BNWk2K`)I<-_8eM1`ZCRW1a1H;^w`;$44MjN9(?CeDWevBTX zVnS}mLEd*;-TsenwSn?e#{=jv3I;B=oXe$lpEeN-@}0%RJZAH5Gwvx*HA}q zGs*CSTpa!WAsD9IN+c%S2ak9UgA{>!-_3OoF+VDNEdfAk6E*)d9=yr$o{B|IrVN9t zk05S2oRdouoJJpKZ);9bFTNgTQv!0TM>qfM)Sq(xIn^|P1#VEjpw4Lm8BkUmE`ArQ zJC}1T9kanJhBP6VqW1v^kN@Vf!>pJW**8!j1-%d7YZ72``m&*y;@mn?pJ+bM;Dyfi z9pI?3nzE{yy1CBv{K~t+f^!4NuaecF_L=9O?MaZ;VV<8M8;pKzf0R zRUBa)w;FD(zx2HTeG~fTbbw5=KCLb7iH^XzJ zaxw;|3T|otM6`CE2&V@ydUiJ#iuI~bNao+%(NroS%DGrhy}Wf`04v6+=1TR9ZbdUG z%Y8PbYWx?ya+jpX25+6ZMzf4A$$mlL$aoA@2(?wj`z$Q)(lnO4ud~OwjFnpSw>@p_ z(~3*SJmniJX4eHuB0aCLw1ct-pey_4P3~isakAaVpZV3@Wv_Y7W$~-ZWr_>fYBa%v zf$94+W%fXc$p$2}e_=ZcOKd!Gu1}q)a*XJ5&(LJJ?#;=U(-(^5*3>6m*Sm}U<}B#h zGyLEKQmNmzq!Ihp3SL~zQ(ky6Q#wXF++B4Jddo32W1VagjTHJokFkY~PkRgBMAIo& zmVijuJgKt#3IN8FAYP2!$lHb*h&b7l$>TDUe35aW*4@Az<@K~E^dI=n4~JlK z2Gn}(P#7YN6}dikUfc}t&G=%&9nD6_-;+uaqb3DxoAmOpv z<|+RVxQ$J`8Gier8_?y&kmA49AfDA>la(XU8qf_)6GsT0{9Ak4JcZ8KtnPl`q2Y~Z z`fS4g^~+ZgZUmCOe}AvH> zzYPsMO}(ab2=FxNbh_qTMOc3@Y8G#BoqOg1K7`COUY`9OkL|x*-2Xb9nite!1uCX17hF8)8UJfL z{3VIpl`67zq_iu~*Ki#E-K;HMu$&_WVi zVjutZ^Z$OJjveq$$CSbKv!7C?3{Z|8^?=ddUA0EawC+7DWqT zC!pHL(kf+b|3iD?MT~C61);iX=F#izJm(C)o`DFCr0PI1iWSICSSo&(*QSe4O#FiJ z;G+6IUZl6~1yIc*j(}#05G)kDDQHunCjJNy(Mh0Mc2_$)J8==dV2-2^wn+mxB$@%f z+m<3ALHdjJAK+VX@}BWZj&z@3wY@}cbuyLEm3_X`&ar&H2{FRUpR3dxTAwv~aF_IL zE@;SG$`PGPjsUHOJ;Ka&?W*-4)rR8rG#nd-Y$T9~*WVki=u5r0U|0v%X|>^cYBheT zsC8*;fTN=Yl!;lU^jFnwB|Jzy1W0(gqmxak#maQ2kjn+FhKW`lTp0ht=hBaUbuJy9 zb4R+>o_Fe&ADySr$R5`k>`(awYrsQjgs3)Lw3qd)cN%KU=br72Y4=@iH-+1%dHj0B zop|KChzuz|oJli|yQ2#^JGbXyT0UnXF@-Fs?Tt!rk>)pQ=O`_|Bc>%&v}$xEF+nov z{Cp3>)@*Pqd+%E(^T(li9sDsKQj5SdLcdbK>m+&fbldP#a_%P0`reTlz_W3{o5(gL z>xMG0&G32;ifQzE?|ask+U$v6AL%a04pEK450S+`ko@o>iXpuVxqnSeEB7Ux#}-=+ zusnm}dh06yJvi)<|M_O zu>QoSIe)C4W29-og&#{|IOybGNPQbrxV;I0$^MEuep?M8`*#}%JZxpWKr^0;d3Mg= z)i%><7igVoN{^a%MSaI~*VM}P0#~{!SBHFu)h>_=Im3<1zC|;My%A7izLxYv5IlnkFdq0O1ubKu{@FT8BSn9G;kFbeFJmf_xeNitH5zf1?ij?ScnPIX>E z+I_zJXlF&~zWJ>`tDVYg@aYQT;K z+P`8w{lX=fLM0UEL?J1@TA6>I7gX>@aC)hdBL-$}X`vijOI2&GRD(zUPW@zx76ltZvx;a=P55zZTS6 z8g^~_xi~&qhcH9F)YZi&Zp?jxCCAe~a73UC%BIvFtcogppaFkvoe**1VSxI?LRUC$ z{+ax=+*s%g`4YQ7Ez{3YdbJ5ShJtDSE#Im;= z%D;kqBb*zou*a+#5}vQ*j(*-cz2!l5{k{U{c=@A0M~@W1RPJ9>|Ge<29Ut6o?U&3J z%Q=}hscwq(%RNMqw%iui0?z9^JFR}+b3lFY<=B^rhk$9lCZpvP+{nMgDX20^o3))b znVYwr#ww6Utpxn1C+Y^tkuC7^2O8BaDsv;5)?y{u+i5ZSvcfB0oyKo37Cc1Z@}AG> z-p^>R`qGf>9pBf@8iww6jr9|_ZJNXN_-0!@*Je)MHnW)4at-&bi^q@T{QdDf0-^fg z%_5T~g}{kM6KZ~stSnyc`JcZkP=}f?t6P{fz-^KUfU(4T^U#0_^;+v?G7r<1r?zPX zxYVcy6i>y{lnh|6W-uLCLH;A#TE|u}9VSCMi0-ExpFw%34op)4i2V_j-Vv7^^@Z}vsb_E0By~X_TlN(-T$HB+s4y`V~DPHK2hn!URirS<2{WD0e+ngP(aOgIcBm#)5(G&B9z!U6>(+(gb)mb_2f!{ji zL@D9<|J2F+u@^fq$*cDe@fOXox~<~HmALVBv+>(w_!n9Fcy_N4K1_AzXt8|ZjS>Rd zt6?zrWv+?xlcRhdRGx?NPN(c}lV%^L5fY&zUFk5Jg1bftLrN3{)VVu!hx+da^vjQJ zg~zbq>&Z{}^eXN8)o$fcY?$1#hTMzC52?y@;i7JOv#}hx%#v!?qV=b#T0R?`7?a}kxMmaN&&Kg=I+XEi4K45POW`f6(`;}U@ioTo^jXXiKisv7t1JZ}5 z5XkQ4>T5bvvw$VtR5@Fy9Bv^_R>{xPfrG#b)E?!17k9Y#-x(jSo&Y7ajD1Edu}D}w z-m#?C*nu@LrD77QvY&00-*$>>d$rVI3muBObG6!OP_tKdL)E7|WroqJNO>l>S12HB zzScrQ>9nT!*kZ)$=@xr0K!bj?Vix#-z;Afh5nZgkavB$34c>Ws9N^M;Hc?B*{^1TL zaH6D!B}<7JforuLTILfn%h)^N5u3{lA}(!`t;D_@{4DD58(TAZKY}&jQw4u2lTRD{ z`-hA{hdcQW_xCw6ipUxGAJ4i2oyTjPUn}l5Q}P5wB~1yK1ynr?+Mc&2xw6;k5b8Q< zSu^8T;S!C>&-7PV<~J^?d8A{N=c}dq|q^U(y~5S+_|h5IGU?(W`L0UZq7JdqPRgHsDj^BPLhB03Kyi= zcaM5||GK3Ni}1W`gf)%i8~GrgNpEhj-RTqG+U62arr8{sib0vDVsXOQV}+qIQ31N$D-`CPk@`{{Gr4z`-9qAdm6U{Qc| zPoQJ-hys68ho?R61MxTU#q|Nk+t{#V(*dgI%glxbs}j($_O*QITY+BDtwwzqY{jPc z{fk{dFjzMHzx*(uWc z&2JRnEv6>?rnhLGr;@x%?$GDehn0K8Yb#}CZ;I}?*l?%HO$A!nA60V*%Rkb}15 zML@|oeoJT4e(&r>s*Xw`Vx`b$A%;he4;rHr3iLiaII$XnFpT*g_4to)i@A({>kNBw z5huM@x?yQ|U-p}ySD^_!&o7_ViJtpwo`1$I+|vht))X1$bZ+BdkHy0k7JFrgI(tJN zk)&-LVxYl|UK#9ddvv+4suZeKOANI)eX?8c@Z5_9n)^xs_0+jx&9B+qGm!p!Y-;p2 z^QfC|qCex0gGMqAJ*s}kt1%=`5?GeH66q)_4Nnd*ZQLUzE_D`p~s&Z!l-qs+^s7lmI~1oP@M3R zTuRL}M5Dj-u=wT-CzOR(3suXS*K*w?2%qRaDX5&@2GvF(qzjrwEDn29=Vq?*+ks?+Dl2s|ee;w81c(f(>&9oG;nfLhsPV0HiZyd%9mCA|yMV(1Zlpr@@Y39>t{NnS zlk2>YJM+HQHALZblM9@%Jf@;e#Y49YbD4CzvfVIV>m`k!KGJsafHPApC$S)Ws#jE} zZvdB^&*mN;s!eCwz>^usO&)xSgoUSZhmz#98201c(+|EFlw86l{y-*FROfw+XrY;Y zPw>F7>N-r;3m=hzJ4 z1DV6EKFU|TGuU!cV41Er5rxj678r&SNjqQaYK1BkU@tH%udVwOB7})A|D% zA=cS93(a?Af;qqQ2dy)4ciqx`v4eBY$e20k214Dd#k-{xy|T&^)pqMefk1F;b$|+s zU0p8PPLVNQ-fa&UUJZrg11g?cvnD!# zS=xjHI2BhbSR7UT5(EGnqy04S=ke()f%L~R`L+d0q4(kn_zC>R-_YC(J88HEE9!^Q zKEWNl)59j2Kk6?FLe!X+sz3vGUksn*=h6?NMloG2wY}bfrh68Nx_lEpH$^5}_#0_;lg(71ge@b9Y4(t6{tRfkR?9^<3S@;a)GH z6*z)Z%3mj1qVQp_#pGh)OHF@m;nsSVzDZVHeWA+?#G;5D)l`T=KzhCFXBqtFp3Uc#;een~)R9sjfnO|gzF`OB()22WtDXgM z6T=*?In6BFOefs=TPm~2M%*y8RU=NJ!=Nn&ne!Vc2?$X z-uW?@YrQ}t{~I7Yhs%mn${^zO2^2IWHObA6_Gj}`rp8`dMY%@44TH$!>?N1e;kDj* zjzs;4BU(j5?G>8G*rHZSo*`P5=?%*#t^6KW9-o5WBbxI< zSM9e?+}mCr9b>jwlW6mhyjnL*?>j4oeb?@jQ#U-x>Hp3q0ZZ|t6oQ#J+HZgnpd zS|>9`*9qyvd;8we?awR1@k;@8bn^^0;G} zxpH47iA3F>D(~p{o#v~SND*iB7Vkhe-3ngH`P@3i==m9$zb(VUYq!LPa)t(;y@2># zYYHy;@MQ8;;s{=dbW8JO;aTtp^%6p{-=RE z-6a}X#tIErjR$^*`SfK+=q1W0l3hoA(V}P3qFS4!^TUnX9@}t?0-D*)C3JviuwxDX zeL2KuEBfPtH}($U>U>*t-QGTVLa|4_`s=N;7WEdb1?~{apCP<;iu zw0_UZHFzD8S9Gh!-!R>=pcb$;4oWGE$Zmf=@a=^c8|B+<;2-KH^h3}r;UCq>&F{s@E_BW{P} z&3v-hZ7Pd;gS`>-p($yG__Yo9wDJ$R%GTr87#4D42sb)yzjCxR7ri-( zInev{ag1P$Y=LL!!?r>#a@yCXn1vfLj|~O1tE?=I#uLdZG(0hmuMy6wlyV>XbGTK#YiF<6%oof-r|PktDMpK}a+~}& zujS67AFy#K+O6Tn>v96?(iSMBs^YF-p5Attfz_?|dh4jtZ!a=SxkoRIM09rjzH>!J zmY;LCYQ4YhM)tr`RSgn{OYtlCNy98RSjakO37Xu_t}|41=H)%=QA=Q4XJQPMis0V#5l@LO6PCC{ z$4j%Md!F6Ow&f5?wX=>3JH`5wH0|uf?Ec`JoIUzk5$$YP+QpC5OcQs`T4^}DZzSfs zG-qlv<8lGd;hpM-7#4SN#XiHrxiXv6NQ`-~9)8*EOa88*?S=SF0 zQCf;*evOFFe{3BPbR_Pj=p!y)W8FSes-^Ui)o}TKmQ|!kY)=>pl>M@~`@m#Q6t*C= z;<-bz@@nDO%RTIwACQ3TdszSE2PgVqOY4ow#^spiMsQRiyE!p_(1ETtv7g*Z_k?jC zjLfN9Ynel`&g;4dyKayz(aQL9K;~64sDlheLEqPdR-~JHRBvy^pl+MqaJT#J@K~BqB)nKOq_KCJ z_e@bWF7S%yV{_Mc@8YJ70&UQev2wfD0Jt~Sr^L+fF-^T{Mb~3v0@7z1%Dd0l$VbcH zhkF!ZsiF^l!CvZ#GfTe{8+4Fx9oolpFr+0J`NNW785fhwu&V*Rh{bJJ_Xx2$w@qhs zp<#rAP7cbc$$_?7_qHjhqO(vQ#S^)A%xHMd0xm`5fTHgeILt1pWmIQ*K=(&%tL?6e zjRV8<_G!fei{H{hiA)y76z53!%81Erx8MoywYh6AO{Y`GB21X}ZXOv{ZWT4~exl#8 zACRf&fmN9KJxxE!|!j!C=iZs zcUASlRYpPshEZ`4fpjU4*x4&I;f%V(1o2|ffyW2ic6i&wcV%m<{%tMwoIl>yJS*}s z0wAhQG1}xbrtJyXT9sMWxX+)cQth^ z+bv;$wpuIJkBOOP;KMbzUKNbr5nHJcrvKd$lUu(4dC%B^H5A*M+Iod(Ty9 zAD>`J8bl!wF#9Et#Q%!^{ordVXrQgpGHzP^RDEAlL4&R)%r|4oH~&~#%OFfjyEO^K zYQc1eANB0&+>~aG{j2tPA!vTkH%m5Q`$*KmFC(c`GX!IO0AMI;o-#I&^7b(7>9dm* znL8q_3!{wFO&=cF8)?qbL5;y%DNqqG`lK!Q`NU`jQmP^QedyKlxQ=e_lai0$8ZBbm zTpXHgTVa_t#|E+UtdlLg>u5_IODR7VKc>$2>act|KgZ^I2%&Z;@80oPpVR@%FMyzA zx%NC}#pl~Dc?|ReghJ6JK?SBY&Gv;alAvTtjySfua;mWD6Iv0{e8Lnf5NHz>t`LeY z?GoA7dDhS_A$T8&146rDs=nob7FyGxh9EZ$P8pWzx+fwfCg5qwW!j8KjZs?8j4Z?X z`Mav}EvJhjaTiz80>vjYACBDZ$Tw+rz7Y?0XP+^H8!l9L+&A`rcbS)I~ z%S;1!SeL*^3*WA4`*6*J{<<-TTM4iOSZk+APJG!ahTy{`~XjnsEHq!Z=uREVx^1` zjk4+620a9tEr%V@2^;yTvhK>oVjnd(h_bRXy%w2}S0gjiRPn zt4SY~SfmqF#?VYBlwCIyb-kG)!!P;wYkE*RYt*Ll+`n`+Qpf3Ns1NpLf?_`}kYmLg z!UH@Eu-X;h%_pejuJ*S6Djzd$u12&!ClI0TT)BIVvY`-Jxfdr8D{^qc|9M4j(BGhZ zEA8Pri)p*HK*daj#jwWSyaDwI>yLIm6xXrRQ_E}29Ol+K*WT~I77mfG%z3EGs`V@m(Vth{Ld&0!3lm@)b^(zruf&|VNS}5^@t8;YE zWSH44z$<)E;d{$dw!&(9V5)l6bP-6>kUu>&#iaWlUs?$OL=mG_$om+& z`??sjH8tg0XAcD(cMoe#T9N9BX|C!|a*=86j4fm(jLk$1k0>Y9Yc zD9|={3FuasfvdO4X{tXja7l%6O`aHu*)zVJi+2hevUxuywr8sz{S1>R zu17WADOk8yi2=^7fO8-|ufkP;~=rF#hJp-Z~EyJ6_YZ}C3oIp_V(dCvL$=8s`!Gkfo~SKRBm zuj{(axx~;3U0f7a4Ck34anZ+s1?Tg6 z^gzQXO9t_VUqoS(zx*I_xuTTZv%5;63{B4TFJ$=Eh$6|`+_$T_eF62hw3!C`GQ|c= zc;9%Dg5FKWAlx7m1D3$O&Ezb&7tmBDX|~txjA|^5!HGGla4eZjqK}(<&%Z z@c;GRHX_J@=RJM;l%Jf)VYtN>%Fz5kk;Ot;%IBE-<`W|i75%JNKfdwN??F>h|DI8z zq@q^dptN(hqv&Eg^5rgAyk`YdgUvzy>bs+!Uye*=!yZN(>CPAh+|9YQ+rrHa+D?<1 zr;DzA>AV@A6O#Yxv=BI6ls<{gB7~>0^yS#%^Ud;59;1$MvRA;iU`Qk@x1Klre>XN<4byrMo>4KgRQwtehB!J^Y0AgIXl~} z+p%uvC@S>|TVqm^v?4b%_p~;>nxVJ#nbhGd5q_=9Gs{gggc^2$xo?KPP?d_H(uo+H zvV_z5qQf8uW+&pB-qzLmDMy&JHG*>`8VQz@MirsFa?()NkN=uh4Is2QELf{T5~)v1 zQQpP!&&51nem_Qv$poimI}M^*53YoSy`&d)4}qGNsj%3pXZerk%%hxMB)GbGKA;qW z(D=x@aak3R-QHyk|Ln|`mnDG=l}Svv71^4T^9y-<`j}D-{a`X~n`aIChoyn0B6Hmp zllx^-VQ)^IVv`!oYyo#Y`~a0ZtAa~hRrOOe?Aqdfq;7kDc&hhW++QtN z+lBk%l0Qx(HItW4doSmL+n5@X&7L*Oo0&$v3Z7x3IUdDP-ky?kxm^Jbl9S=$Zp(({ zint(8oZr(#kQ<@NUBluAG%a3>0tsH%aoDbv+wqf)kxr|@tFft*M8@0!6{4q4T6=rzx3VU^*N~9VmpsXUdu?0?>Y9|H2VensDE2)3xT&FOnyah zCSWjBlriIaQIa{|>Z8Mc<31Pw$VD}M5nhNE4sO$_oTujn{!u--nV00WW6y<3^&xX|36CLm zSi&l+5cl^vu7WH9H$9{!jeEDw+hOC~6txmiYGf3+zCI!e<=r<@NTAGm?Y{SOD(};T zA4Aoy-KyCSR$@eg5oG%iPS?HMW(#rV{pQCI2HE7I*TG)1+DjSPh(76S3q$dMaaD@i zJlyQ0CMUcPNI!WVk%kj=V0M2)eE;m?a|PeM^p7L16Rf+ia#uGfmgGJq!MqYk^dOLH zVan%N7zIqBLYMVhb!k3y=oMM$I?b0W0*NIwDoAZB;$7W&lx~pszlnfax$`W_yuY zCnRs2mx$~*h^15@w!E@R=B%7?na^sd8*DzD^iSncV!TsMPd*k*tL>ml!8jnV31WLz8w6aw>>+(jP^Yveo4oSmd(TRTnaN!k z%d#(QVx#yFhFI}0MnBprjbfp`3J4;mZRH|B!bLJ9VSkJ@#BKij$9s$)ModY3R9eVg z8F)UPE$I&q6!5hOsYtB-&S$0C{`dpufy@t#t$Hs=e%w>NDK@w7|5V>sw0l4L>p_YS zZ!BrRBfqv^Hls70!@@_C#JV!`O=o7SXeh-2UT=m&}|*E$u5qvZ7&@hXsz$jhFq1J%+6A7lqnZjz|<4Vw|IyAFlcpaF>~g< ziiH53B2htk|G^pm^vP!cPteU(i2m&bP-~Iueox^_Xyyv@aN0AOz>2_G17(nKi5Y9Z zD|h)de~@0sS3f=U#ewdDHv!PA`9jEUxhA_`q+-EGd>%cM@O4{yFcpV0Z%DtCCr`=F z3X*~qB|EkR`aG6`20Zt5XQ8l|dLJ-ey|R>1`X-B#T*Z@a@cy(@>5pcMflISAPxnHF zQ;pY@`l(2VzXH_w7#lU3`roI_sAh|6H}%?RmCb}FMpRvk_@E;9&XQDh$KUKeZs#%< zWjPcM z41(p|+|$dH^T^$6{Rd7(#b?pP;2)^=lRupxUZjW!cHD0lUSM+@Z{(sf5p{99|7Qgg z@QaSxjDLHh;m07%)kg3i=(R4~ngM9Bxs1!Va;1Drv<5;#Gd5c|E1%lq@q$o(#X^k| zJm~L7zG7!vPi(pX63a~Tw6ntVjP+INM_4^_zd?ss$KpwtjSnTO|-dc1ir5-vk7* zPN5s5*L0J#mPCyHT~PVcFmZ5uevlleu4#v6aE68mC)&8}8a z5biwz(yAJO$s!L(8D-7+)gp@jiZq=yg4{P-m&192s6K|Ub&l(JW=6lvL6{p*8Meq< zX>HyoOOo|4Ih25wUq~IWAp}%vMWVhSrru$D1tCN@Tu2R4rAfvox2txI_2X1FV#95b z5PkmoE9P7uA1`e*T=dntxyn6@pYiIJbDO&@b6AHBWxeBN$iN!=sa>Ra!;!0A4_ES{ z^}rwt-dEI5(*wY(BBk2E75wh@@AfBcmNt1Rxn?>g0-uNLt>4D25QTn|NKyA4x#v zj^!JhtkqIF!n7(K$RsV-$*!KTe2k#iy{C=;@GjESn?2$R1CgfmMj+IuiEN1TD!}xx zbpBD7U-yJO#9z%AI+TNl2&JuJT9rug=8OcXP@w@f}S8@992=%~q7>~(T z=Q7H&oiq0XEs7pNxkx3iY5ZwFUAR(x|8@GyJ@wYtnzQ(2Zz4KV5X7Vsb*ar_DKzax z0R9I4K9fqBh7owMlJwLj?5J_RKhX6bKVar3+#!awuqXdk{p``z8In4Xn>3P%4bhq&CmhSzE zR(K@DzN!9xan!34ZCAv!L7I!uym5`7t+p|=Tqjk`Z)J&}3(2*8!q~gNkHX1@GP=Q& zQeWFN8aB=yQi^d!DrE2r10PW`XAE)?1HPhryn?YwTHM?nrnp2H5e<9hjp7aGZu?#c z{dTb0Mr@xOMkt0&>R>;Z&-HAe!AGXJs(T~_ZF3(9KiE3KITHTFt@>06H$1OCY6G#m z{$l6SY^1-G|E_agOgSN_!8WijNB2tJ$M79}4-upVnl;mpf%>bpG4^v0juHyKeb>Y+ z)#WR=#X|IW6SBNi_7x_7S z4g1WaLG9|*6O%7$P|^{Lu_69HP|l_#DLa!LV#=@j$f8&u3?Pr5+v2axLS0ph)D_() zB{JTQe$BNtpmJVJr1D31n8Rb*r{t5W)HKkD6!+?>Ffmud(BiQwK>N(OeVv7ncufr@ zDH=5<)(zIMI?X9Td}By zuL-WKajdJ{u5}rN5MK*gj;4(0>ZY(^CR`-En37;1Q$-Xc`g~e)nw5HmLU;U~BmfUK zh-cJ=Zdw64v%WkAt+e}vT>|kJ-$3_UUyR8q9`oB6_k<`JGKt(bCm~s}FG7^~f z&Z7H8vR(AuyE>*BBwBu8vH{#Dzn5Xh#b>^{W}5)|humX8+^h4%zVfWoKdR*yarWeI zkqC~Wvd(b}vR4`bHxrbhSvZCrq-b=-hoxX1*~Ft(Hw|h%kVynkD5(E_6C#dBkicqB zE!*4kw&bTf2UDF1R?Nb zp0@ioj1S4~`%c$ikNEm}iRV*MFB8)u;Z-qAiNsj*%39cX_A+T-UJ%R2Q)CYW&`ING z;evHnE|1S(lR>j2IQ#DYVWs=`VOJxT-DY!-0Q_EgeFU6<9zpDyPZub2sMFqunc|J% z#SyUfSOY`{ajNCEU!a}#`@7S2X6V*!D6UexaB;X`19d}mt}U%-ErN%N_287iq^AXX z)g*8wzz}k>0$5m#juEB1F_h_MhRRlkEvToV2V#L8^4&N(Nfx6&oiO=9c0ta*e=}V{ zi1A;njGs=pRP1|ul6Z`Rz2t?>9O%b6j{1);akc`kv&jkxVrA+4<{B>z%YOSKLUdZn z@Xm;_X2aQ4kg^iQ?{SoJirmgfq{$cDHii!SYoottY_1H^8Q1Z9PlF3Pk30?DJdhC4 zyW*WwW!+wO&>TAuR9PGi-=F@`mn`$<&xbjs6eVZA`zyG9K`zPktj9M2MKQcg2czUI zca&^l0hixzKi-rx&t|9Emx{@TnQnXyEHdN3fL%yK+fLq8!ZDSgy((knAB<-w54r`C z{8CW}Ay)X<{pfB23+ZG11JKD_X`3eZ$FcGOlsajHVR$BFA;-88qSfdA$83m+n6lph z<(zP8s0J(C>a(V|ri6Y%f{lRYbUz1nS}} zl7f2WVqIueOI45_T@cm?4f4!pkBt^z_=^#-k&XZtHe{$EP6ofU`;^Y;+b>Fuo#u^7 ztsa%EIS2u#tVi!49&c?la}7{vNVw2h1z- zNSo4T=H_oSueq>jtlOWXq3|(DS)EoY0SNM@fZ7N{;{Ew(l$}@b_K}EzUi%GI0Aic~!o?J7Bnp4y$lL*&05lKjiXvd_fuehCnsv{)(|~Hb)n? z;EKY9J$lni?mZ{z0z0f$llHDRYEbO$Ta+gxs1;J@$TJK%9s2L}j-9#vWO;20lD>mH zV)kn4^((OTy{)0VSo^qxJ7U!O{OZ*v!;2|jOvqBsQ`*;QsR22~hRQ1lIKr~(lo5k?-`3(L<^^dlLA zr;00BzjvXmrx38a7CAX*;;|EHzq`7ectZVJ8_=p8zsRwiZ3`H=8!ZN4vcGQFdo=B` zGmut88rcGy9szX#SsjR3hJySe43Rr{IlU|wiPkx)6ky*_pMW(R1PuX}LXvkbMm;)J z>Z$80aXL(4+v9^r5O2IhT+U0q^LR>r=nsP0{$$FuzQ`!Um2?G>(fsQatDUP7hLj;Q zTcMnhC0BfD6Vj<(^dCQ0q79Uu*}SIiD1S}N z^y^WJtP6!8>zc0H2@g-&6;>Sy)likoHP)OBfLNVWui6H%++guvtg9_tmLIn|ivDDo zEbUyOvM~=e7Kblk+Pe~GAu!e|81QTKBb2C+(3=SQ2kdV^X}N4I z`Hv$oNDXWZy&Vl*0m2dK&Ir;-p4NM=wIV)FBtppjwZgvTb=VT$8lzEHv3L5Wt)sN8 z;dAn7>n-rU>KBznQi`exJA;C2p)l2rRP^lPV;{8DX_fqweetd2O=3DqDwxSVA}qJh zP3$*VNP&6_c(~h!x(Ov`o)pefs{Jz->}8VnbY|#M^^QmW)RN zhwlf6mjKbIdpgLc^?mXu*0oJpP_OIR)&3Ta5U`t)&6dYn#CedCI*G(iD+iy*C8Ssz zv~E8J$iy%Y&D%Tu#UGt$4?8JE3>crdpvc3e(B|QSK(d04mvEAGR?RKP&{ly;w1k`H zPzHDnno6E#b?GCwOV<#IQ%-2_w4H>XhyPRznrKtkoI*`Ab4`xp=B#uCj`q9qK7&Y3 z_5(~`<{~bpH^orja8Hj@5WTkAqf4M~gc0Xkp>x{xZKv9^U zUxM$;`v-;iI{26OOG>CiYI`XsFt-O{8d47ZOZP>UJ-`ymiWg=DFq8mZRX?IaC)J6F z>eL&d>D?x-onx=Fh{zv zED1MsF^|`0{u6)2I5XQ0C=r_u7ktttl&v0)o6pF#&eu#Ei{iRYlN|TVoju?N?9=E$ z_>jucjek~K_h?@xE`+dzMgohJQ>MW*iinDT!`h}}gWJ{LHCZkNGW@)YsVuc4)lGA) zr{4@N<+98>Dwcd6{L1gXl$R(z>cN9BV)+;uLgO6s<5P@vq$sop^3efWY zt8dZrc-%j#cQ@A|@5lEbbtD&!Z#%KFK4!lXt_P^3ygFAw=z5F=FYTh1VY`3Hl>1cQ zurQT#f{Ae)Y zV%weGuvqLH-n-o!H#Y8_a*`?7+YWa2@=Xx5xvK1?RRVa8sQ#AYYRpBA=X2kX-knYY z`-hC2pGR=d9D*&>mJuzhAKOR^ub5T6(o>(zaJ4^jb)BZFn?RL#xrYWNOCP;ZdUh_^ z!$Y;TMh28I22|*;AuEKZSq>ezgD`A_2y8T#rR(clc5~WV9rv#Z063v<@dwY;oVM=h`c=Vv8)NXdc z%xhY1yd#+Iufd9P2KeVnqAefq`TB5@$>!yX&vkv{e?JfOw=fm`5A{w`j17?IfcxuA zmNrlYoopj!qCxyQF0VQFJ#xA|_lv-66_Gy2Gt7J!^P&F+U#6fiuTCF77KO@*gFM=7 z;Egm??iA8o-{L_`-2gQiXLv8NC|ZOGk312S(;b#_>2gF_aTmY~z{!*ZsMBJQpwQTXYUX+g~b34z; zk&T2g#`%3?Km9n;7D6f_q zeo^#c{rJa0>wIB4lg8-u(4tI_KbvN3y7tMPh334)7VUo4hSFz z$)EO7Nc=l2is0ILc}K6=LX~6hgkUJ%1 z=0@o!nUc7lguCXeo2ETQLIB)pdq+aWi6E*#;c^h#V-z_Yv_ilB%2WFRU4iurNrUr^ z+q@;B>7IgA@LYU^Dc(DFt@m0&x10FmY7K%llN%u~2S(5z+(Q5GAT9HAelU8x8kHhJW7Fyqo5x%&z zZ2nHkb>S^6n6(8jE)2|ZjXuWKqH%C{?=m){^}MIF&5G)Un64>OiPb%HB5HLD5GNt$ zF^YVo>5SwqjBIWo&2W4SOg0Wpc=_0ho>ErsQqDlBTo{dz-ojb4?*E>9-gSoRhS``t>i@d<%wkP3oEjeduzHmNzBT8qY~n7v%PCT? zRj29B%TUvP?kx4258Ci#JI~*l8_#vJcyJlHZVA5AGb}&a$F=7K(nim{ZONUNJ)zl<2Ql1*hh+s_ns!1qyU{@57#{1Y5c=QLTUtO#2)hVFN2pK z;a6ABx~GRl~rS}O0>s!fxl-VMAodnC6jL(}>i zog?R)=W!>4JhAM`{rgx2G(XTT#CWdSq)CvCeu+${Au~ySq-lHCP?2Z*ST&{GT9S9P zLZ?QsnNm}&_Ls%7{MvOpX1!AXTzC~KtRCO*3XLdZmStv^~(0FUWj zY&c>oT=Fvpjg+&fgZt`bo5`bofiX^AIQrsMDYE@RAI5l z!l@LG8LxN~puQ3FjiK*V*EES;(#@ROc|5tWekrAPpQqf7LH(Vehho^Owte z$IoS9mv=r#n*a4ODi}b7(+m#mG<7A8b13u?QcAE(WK`-T*L@Gx@I>{Z-)IJ-_&hjj zB|k0N2>WKPu$BdCj~xHtloga7Rn&SJ@ORZzD>0zDNvCOlZ#W0VfXe!JS)9_vVq{`6 z#tJJp+L586*d#9{>Xi-*Yx8}uc1uy7pt9-?L|*8fZjtkI0$1ge#!o@{yR1RKg0(!P zPPRhMotlY)Rzrzli-nF?>&RPvti}* zF^0((Vp!EN%n36U{$koCLeFO^bTe~wsnK*bOw#r8sP}75IOT~ulJUKy$EsdORX zj5|6RlBj#h#?HQDy*eVqlb<@*Sd^tC$UXkKCBsb?Wb;~HL?#J=+d{fdgMSv%BTnvt zno>Dxi#q=9#EXvYvPnzavOzTPrD@TfD`F&V+NXh>&_@wu0t0|_NOgzu;j+tAP(IQ; zey@1_7W=(JWrPoJF%TiovimDLh6R|iL54nysQa#I;SEi)b_S>Nx=dyG zA4FgGO$!Az_YrnBek)aV8xq8gBIF8V2=LUOA4Bx&b- zc^PD%5IYM<3_0Q~Qie~+3>Tt4M-qQT4j#|Hf8{UDRK#V_lC^|Fe0)As7k9V>cE^Rx8%wR^+%TO_tv7BSW7q(!HRNL=tR9r$K%! zVf~m{Q#t6Z58q0~^9al{!PfCznV!b77|U7AaeRs6h(unCb$?p4$AkOEFa+}6k%S-5 zX_!M$4&JLe#$;d)ae{qT-El?Xe8Zh*I>`#3!oJi`l@x+_ZBu70&iSjTo~a3(yh{Fj z((w+;lMm?HvLYrJ*{M!j?l`pOrK`1Z2=hbiqq?8_oZn3IwDZ%tULPaBS*7s5d{UoT zVRiNPbk5X9=jD&^MM8UI9LD)S=YHWdp$F<5Yk_K>xY&|}-Ep`pt$xKwIq70Ev!?r= z8R{iz=JRMC0q;6%2;$7Z$bB#CtSh_?1EK*D+nFQzP z(Smd5ojrgMm$mqVr(zE-Ld2vAFCV0lV9k0A%m%%_`|Lkn#ioyf8Q^;frjM_4mLI~J z96pN}3oY_o);Zu#$~Nu=px^{gQe=p;B_^z%R0HgEo4N5O`rgAxF*0O4Bn&$4Cz5b+ ztgP2`_a9OJ{hHtcl!N3#cJgMTrx?SrYHIP#7Lcg^y_@EDwMr4S$sF7W%@l4oDQC$^ zq`s8qZA#lHXz<EjeGIuurF+1&_g<{U^F90f6yRLw z5%&VrFkp+bay@1W^q)u?LPz-Sp~bQlN=oPtCX6w>GV zUq4FiBOK9K%(+Yft5^%$+HP7rg_phA4W7SRkaR_qthz0e1*t?|mha25rUzFx>nWzw z%Z|A-{^}Qb@xvt|`0V#iSybb7+gWEz#JUjf+V$DAjVS+m&+tiE)I1s;Z%5Lu5(aG2 z3k`Ao_7n2y^9Ll)2xs5nS>K~UmHGCZjl}BPzd!T89{&4c^v2CKz%f|?75*YYfhWx7 z?%i6OpT16CQLaJpI3fgQ&+xxL*Z+LLf4%uF1X8I9rhUR+L3j9HUXN`73jp&RWonpDr_o=L$2ujrbkLap_`=`=Cqub@aCH2SU;p*t3k3i!uO&D{{8#t>&wl>*8>@c(g8&)q0=U7Ml%Ut1_r z>^?YI`6pey6w3eOptU;|kC4M&)IT@R-TnXg1Wu;e$j+e<@xLELeFXM6CMo=9Z~mSD z{%)B6YL54f;AE@|#PQkE|NB9auHeaX^(VPM{cjEPZ+|{t04Mvq8%;Q%TLK3Rnb_wg z>*O2}-~Qf365%**wwgwik{-KR`s=;OMRgZ^D%Y)hB9vJ+r z_lTpi|LFvj;7B*IMcTVZ{`>J=|EKM}`G?Lg_805QW-sjSHVwc}hBY-&{Z|wJ=WoB) zyE`36+*byP2TzL`!0KPa0O6tJ`iIMWN)I|EXL^C`0kG)k=AAG6YS0!UlZioS1d8l+ z#*yEiHT>xWJ|xE56{#6_Fp~OUni)Q+Y~o$^630;&&LJwEoo#f^=C8Gr(#Xc_+D&212s;~bb^ zSqYiH@#fphx$Ir5R9H?kX;t1nMI$e6xXaOgs8P=Sg%&dfHx4b(Y7m!+VPRCsS3d3C z2S(jdCtLLw%l)F6_H7{_)*6SZ!#NXB1if!mR0|<=ZJ~tGGK9>(LGeop=n+T2IIC7= zr<+s6H+D67PF8|*lIutG4sth#3-pO%pbbYeQz<5>kR@{g!qOZ zfaPvdmGd=US=a25@t>?j8#Rw?9=1>KZ#lV)!BvWCw=jflZpD6CO_Ua1FqSby#DSSm zuwj<#$xAQxWcQQ7Q1F|g30%f$f^UoF+3PNA;D|%!!`Zyi2R}#DCna&B3?oE7Y>m|D zgb zr%+38Y@AZ#HiM=5k9eJzXq(NYKj-)Kebic2D8+bosyEG<@OiOEwtt-9-y&&t#KI(nLGvgo8J!X^(_1F zGp`;VuFt^VN4NU88FOVUu_*5AGnx3d>a6Ij{%_-R9$M@$r|sT5^Oddb)3hm3DKkSn zdmH7m9pDJEgrUmBL9Aa3s9e(;Ve7qC!h$Z5%i;V}b?Sd^FB5H6Z>1@f zu%FGhC5e)#iWYny`7r*=e6=fO+CX1me1uo2=)bL3fBlJv0fRr}_OTMRid!`7z?32v z^_y@BdXzO*0B)oqhR$QOIz4L!y350v2uh{yf5?98U^?lWptKA$G6NRl<=OJMgXW6` zW_=ZV38H^4-(~gJtA%>(Ii1=--#c$ljH%iB-s3Y~v#fjA+CBYkg4c0H{o?(QS-;!z4kguaB9OpVJrKr1$^$d3X`0yZH*wyw=Im6n2{ILN$Ju&UPSX zBZ5+1YJd!Y%I)rIq#y2~?BVed`|llB%+*wH`&OfVsj+4*1woaXUp9uUlfqXm5u!5r z;W{S|lK%WUNY4ba-KlOz7bZa9Xye&V^LIku5yzsnpQqGW1?ehxdMaMmJow>dqT8$$ z?<}>&=*@Y>BZr%vYlr?=XV&kGC8w;TA35mQf+SUtB=^~pGmPGPFA`t**a|uiDNh!` z)0Rp3Mv7Fp;?Q=4)7!ghsXRz*hU1+)Yg`6t-FqZXmJhO1VqHUH+v`NBuYu#in>)Xt zv$abXrtuLjI<|jYI)Z7yG>0nfd@FXgV(od^2JIGa6)b&?y{qzhZx>+GbQ|s1ehVg2 z@H^Gg>CT+XC%Qv%bdl26PPumH`dziD2)>B*rHO?REzquDN4~(h!4b&6YN2 z&8Z@c*N`f%x7soH>!q8rD(yDVddI}Aj+Y)>Q6&{D%nDX1*nseM!wr{R1*+Pde~d5> z+A7*u?WRZ*5<|K;{ zzSE8LZv&9G&ezvv9><%ezP1nA2l$GwH%-a=Kg{q3G2%4jIoz(4u^UY*h$dv%15vz8 zkm@aEZ+`>wpjY_vB1Y8dM0)tpBGpTqIoedui%f?I+Tr1EaZs04MXPDx_mq6pR_4!v z(w>)pHE9*LHS=t56)$Sh*b?g}g)OXwfb48LdkYS<1G5FOmoBsT4styq%COwY6s3Qd zsj2VVfT_B!+GupBlgk9N^(hH*0Z^hA)!66~w%l97YfW2K5GE)Sif+!|b#iOGACM_` zlvOj`;3>AvYx(VGS0bLlBP@ea;Twl$l8H@ApJA4ukLW(fYuhkFbZ zn+Y!E;7>&q&cF|CxDW19Pp+KxMcbpvHO0=B#{7&*KwEY15XuID$D95})5<723flN= zeTmmpSF#d#W81MOFEeZAKWcWJSVjPo~rA<%v$y)@OYOMZ)G;nL(6Gn3Hn-6*(x7y zW+zJK*BHh@&@M^V?e4Vulp)m?{`L`<+_QFOA?rmmtQJp<{`v2`^CS-aY4`PxTNw|V zq^Y(Y`OX*(Uz??e@(k&Ksq zCHV4Xw7+-;Z)UEPTem)p+p56X9xv1SGGG#prj%hdo14Epi*6%{ZdBp=FiBXMT+VU# ztn4CmKN=WC6{)pYIFvprfm`Ms2Kqn8kkpnZw|MVBrIyBlg2%ilXKo2R2BxBiujNfJ za5XtzzI5;M*G39;{p^Uhxjjqxqvn6LU6xJ^gqQl#t{SGPKU8ea%pTyq+F8=FuIfvcrPdR@=y7o4M_#$DtLX?%K1JnP z&->NCmQe^~v_MSU&t(M|Gyb#kT~}lW=K7V4P32>(yqm6PR4$sWhDEwpeep($y2J6w z2WbD$Xh!%T2GnpYsgrjaI@WNDWGZNBR3?zdK6)I~Q-Q~$<-D;2)d2GRWPx{|6WHMy zxXV4mDp*6#bDVE_?WSlMYsPSud^4=9eFz|#h2LM6Mz4JT1MEgJ0C}|U(5@vYr|5<- zY2G9Y#IO%IvB#<)6xCaY?|Sq6m9DB5I{BPQP8CJ=oORsKVrTcazmz3@i7fUO`Kz)`&K3Z|Tr*2Y!<7IOg`TdtYi0MmYP-U2o7uMEba#^~A)m z!eg1;gJnrJz57phMBfB-o@=iA*kYB@hnhQ>E6;2vS{78`G?I_De_p|KygRm ze(WrCJ&;T}yR}SO({uLzKu>?;vfgN~C;oo8r4NBwJ2ut#_X|=rKw8KYF;y5p>PJ88 zsI${(U@;Dh!emeow%vlN~(Y9P#!OS{&-+JQtUM{}$dWhFS zbRe!zf`>&}SyBB;0GiRv#lzyheuHZ?v0*1rE19pXy0q4)tufuat&yEdpFCaO7t_vC zy!?ZXxMwa7EavMTC#k_`}FY2Xw094UVi_6V=MCyJF>|;Z^;TByKRqIUtla!gN7*i zDp=O??fkf}NO1+^pqKdeKMu4$q~I{#`R#A8w$Ef@=E>7YSP>vcCM?lm#lxVFnS^IT z+@G*WnmCfdJIsGXycxA}@C1nzdn=l*^!v$O;ygScbRLpYL7zN7BErUg&~G6qD0Q!O z?p0ZK_n)?dPu#B8AW+tnx?Sv$6L4m&S)&_cUy5%AL`x*MGrWfQLKD%0Ea0R%UF2!= zm1@*Z?-MKZX^V8=&83+4muwt$4=8HN? zS00-YvHp&$GQG|huE(E~Zs^D#G}BhGYAiZ63e&9^@<2%noXXnmZ~0AY%X&^~r5k(> zcU|(24`b!Xx}Fh37BcKGVVe*o2E)GpIr&A3#oq1I+j#H2wznCosgu+L#GDVMQV-WF z=X)|Xxm2LONqjIso#nNfV*y#_Q^6#$?)|+n4SAtkK88Y8+gPwqaZ+pO&>*&1`wsz? zz(dq!3GxwxSD^xldX02g9>}%Zr_;w`I(=RDxK8b!9jV0I_3W*nIaIt5$L(zC5i3eJ~=V=<3-!`g+qyR@D1`dgo2jslU5y z8e*t;t?Zl0)N7qg{Lo>aNv4}EX!qZ@vV}9i<>Li(AZ{m4>*rsSn;H!zg;CwW;4H5z ziWWxAXn2cFsirlX*gn&2@nU>rrHSz$X1GW(Yp`NFaCLrv=Ir7Dm0?R1Ww7>8L!uvU z-oEp7^hCwxsZ}tW`t@_`k$2}F+d)O6>)p;Ibx-HPDkiRG@TjQOe9`bUk|0g2sqm`t z6=2eDI4w)h&=GdUVSa`lBQOjwD^~;#D-3v^{L3UEV%58n~NLIs&M&J?{ zvTNFt%%C8A1@G%3D%m;Dz|*FI(_5U{0ir3*@mOBN^s>{)fDfmi$m}0PdMOlOpg$k8 zevs-o7y4yR$f#RXaI0Hnslf>Ub3636ZY1#ylvOz=lBLciHX1gMg}QA%oS6s;9kI)Q zHCM@(3EK*K+jh8`Z1~(^!RK%;h^iAr<6Djwa!?9hyUF!dB>f|*cMe9$R)1C_%&tSe z&Qwe{*Gs+Je?9DeAjbe6%a`{^^EngIAoZSoG_CvD8`D&7_-HNSiccDck{S+JrG?`PTAgaU0>#aVy^D)=9Y-V8RaLm?Daqz^x1E(f^ZNg0wgd6G}|deZSA+5OdODPDUhb<9vtXEi_Pi?&Bz zXMVUxg@{Wa;_OVj+8bZDo9bkEdnRAo;#kE`eB=4X4TWz^d+PS*^C&?p08; z1)Gree?l|=_J;9pa(GeWTcZCLX&d{}2m~27eZ`WMkW!GzuM-GHY*9{hCBrDRhTlP7 zU4{$0b$>74J_e;LbBgcB?cqFG=wttF^REVI`=K1BSrL=!-FdLEGoN2e{x<=i*C}+) z^F98wXThmm6O!Z9`QYBuYOjWaF~Jw+%}?vd7ay3&ldWgC?uJzwfq>}J3gmScu55_W z5V`suZM972U8fkta5^PqhEc!}9*)&v1V= zmVE&4a77Na5hpQ#u&#YcyTWAFEv6!Z&g9}D3@>}iaceEO`t$3uj&LtEKOGwD+_=dH zrcBM-K~&yMet{7q8g%kotHiob0RS-80IS*gV5Z#=K5k9GRu+NznV`+JTv#f~%XWUw z-Y9GytE{YUARapMkZudjs!91ME=QjRj1Nw%=rAs(dRusuz&we*PS|I z2CD`RRqB<_Mb|wKrjIVG48vo+gliL2`bJJ)zMAm2%lr9&(_vWyeuXz(4aju8uj0H# zC0kHa62R_y>uIp=j23ndk;29w5GSC}@}Y7#XaN`?8O{6u+>U4&xYylPc^!K5SqT6{ zZ?VwOdGAbiDZ%nUH$>}`iV!fprFFf|&32;1^QW##c2_NMSqO>I?e;h00@^4q$5X(b zplvD*q8#k_u6BriGz~)tHHK@$S zcShdRPJ+5oV|uLa^TTo{Yr80FiixtoDmT~>-S3kvdNI%xcfBWk2Nhk--K>ZZy^#$J zCtGe!Z>!_;Zhzb)tgi*^Z0=xDO_v=efa>MqJ~VK?W2hR^*-XJTOlE7vf>KFd7JC(KRI;fIrzifdC;OKE1+O! zGGFr5PFckA&n?ilw~Ru{G|HqcZxAH#Z2-VVk6MglAkzfPIeQ)WkKZXV-Eyo?+J|v3 zC;>!l-=iqK)l_kNeWY-wi3FzAF5y9|_t7554oaeRiW_&uw+twOiSiZn6+Jnu$ zh3V(-EcF0k@dJ*Z9zbGH)*pKP2Sx689J8u-nCSves(@_UGf&fTy^n|t zxXkA*;uP;9a_u$h$$G=unhISD*!$pL6*S?15nQnVfEs~NCH&3$+f%`3k8qrk4T51j zHuZ1Kl|^MSc9q_|%o#vsuRr__znsxPAVkY0Y4FZ* zzx4id1=vBS-?bAb=bF?X_D>r|@XJt0tFWrVAZ4#baZiti3MIAfKwN`Enbq&@MvecJ zMi6_Da+jGf=&TRez!0%Kt|H;=4{c`Ug}{WAy={d^ZUAKslU*A6t2w>De?X3EwoUp= z@{j0N0!Y*Xz-6N@LgV=SFfUd^SMgell>KZ+;j3BNvrSe$TtIv?+e>u?N5CC202UK3 z*E!SSbX_9d?fa~o+~y5Twy9Vv$oWHwgez?H@Xn_6tp3Khr9Ek)Fy-@zL~w28ynT9z zu3!hg7_9ox-b{U+%`{s1m4H8P{7*Prm|Ax9PaY)pwR{!6PZXkmSb|S5{A@+ce^WbI z)&?BGi6C~`cP^bB8Ubn+w35I5FS`u+AxVbNpq6(t-PCLIf>x#DOs=X^ zQm7Fh$)y7hR}H>qxyc#6Sj7D&5XwgzG}fBL*E&oNlCf*xXb$+eM9?NOzfT&OAD)Si zJA6qKFx&yoTny2V%g8cspFxv1WyuXxeT0q)|9UbFPh9W5yWKSO{yzzW!;@ zNp^JjoO|0>wk~}823J%S$w)Xu>cAfWin}f=$u);5ZF{$skrGPHgV}J_SVT(fmS()Z}{;C6Z1- zumWL{Wo%TV3d|P)<1~kCs=soG5RX1biXUQqM};)smD-RGugU~|$wPF#XtQ(4eSnW) zh8IM*UhR41%rEQohh3#KLxT{C;e-4CcJJ(qd;6#V3V(Y+t7!sL-eHI6tgQ(QD>v}U z?U0^&{R{BYxurQbo2NQN9t@u0V$rqgRoqQspZoW-HfY$)AHr!pZ z^2vL_y@vm>bUGP0m-qs^?zcEL>o)_BH*fMzfc5kJtS7&fPlY`!1s?tN>Gk^kFB^9O=R=met&M-$lhdE~A9%4y59i4V zr&@uF9=J^NoUsf-0OvM;0#{^Q|5NV!>91hw>JPUZc$c(F%*u0Ka|^f!ddb_jT{W6} zcD?*$j;)i)!1-n-&?E0=Uf1>SuR6)hZ>fAazVf9is5k%g<;Rqy=ho%_w0v)EnZEzu zFYUB)i9ai!>6&vr+TE52y6?y4$Bm-7p}mJ!dH%gs-ZoM9GuEjepx_Aupm!zN&fR^x zlLa(i`ZDmfVBP~@6*XB%wafcs($Q~sgda`B+8_bOp9^T9B_(5~A$Bi-V%T9DXaU#S z@OjUDu?G@(Vj6PXQR*=)6T+}w$4$@~G27xQ=ivx1uw^O0Fmr30CW*_zKt(CqKp)?% zdRlo8k7W~qM>|SMMy2`ScJqX_poI2%>hnrGmW>9`XaM0%W}_)+G>hR(91cvQWzc9L hjk8{*b1nAZKO=v0_e=CD;)wtN literal 0 HcmV?d00001 diff --git a/docs/designer/query-param-prepopulation.md b/docs/designer/query-param-prepopulation.md new file mode 100644 index 0000000000..90bf47e5e5 --- /dev/null +++ b/docs/designer/query-param-prepopulation.md @@ -0,0 +1,26 @@ +# Query parameter pre-population + +In some cases users might have filled in their information on a different site before being directed through to your form. In these cases, it might be a better user experience for these bvalues to be pre-populated. + +To allow this, the form builder supports query parameter pre-population, allowing values in the form to be pre-populated via query parameter. + +## Setup + +Access to query param pre-population is set at the component level. + +To allow a field to be pre-populated, tick the "allow query parameter pre-population" checkbox on the field configuration: + +![The query parameter pre-population field appears underneath the "expose to context" field in the field configuration panel](./query-param-field.png) + +Once pre-population is allowed on a field, you can pre-populate that field by appending a query parameter with the component name to a form url e.g. `https://your-forms-url/your-form/target-page?firstName=Joe&lastName=Bloggs`. + +## allowPrePopulationOverwrite + +By default, if a field marked for pre-population already has state set in the user's session, the incoming value will be ignored. +Sometimes you might want a query parameter to always overwrite the current state, for example, if there is a hidden field that the user will change through links with different query parameters. +To allow this, you can pass a second option to the component, `allowPrePopulationOverwrite`. + +## caveats + +- For the time being, due to complications with validation, this functionality is only available to list type components e.g. select fields or autocomplete fields. +- If the field is in a section, then the query param will need to be passed with dot notation e.g. `yourDetails.firstName=Joe`. diff --git a/docs/runner/document-upload.md b/docs/runner/document-upload.md new file mode 100644 index 0000000000..78c887e0ac --- /dev/null +++ b/docs/runner/document-upload.md @@ -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. diff --git a/docs/runner/fee-options.md b/docs/runner/fee-options.md new file mode 100644 index 0000000000..38ea0ed03f --- /dev/null +++ b/docs/runner/fee-options.md @@ -0,0 +1,177 @@ +# Fee options and Payment skipped warning page + +## Fee options + +`feeOptions` is a top level property in a form json. Fee options are used to configure API keys for GOV.UK Pay, and the behaviour of retrying payments. + +```json5 +{ + // pages, sections, conditions etc .. + feeOptions: { + /** + * If a payment is required, but the user fails, allow the user to skip payment + * and submit the form. this is the default behaviour. + * + * Any versions AFTER (and not including) v3.25.68-rc.927 allows this behaviour + * to be configurable. If you do not want payment to be skippable, set + * `allowSubmissionWithoutPayment: false` + */ + allowSubmissionWithoutPayment: true, + + /** + * The maximum number of times a user can attempt to pay before the form is auto submitted. + * There is no limit when allowSubmissionWithoutPayment is false. (The user can retry as many times as they like). + */ + maxAttempts: 3, + + /** + * A supplementary error message (`customPayErrorMessage`) + */ + customPayErrorMessage: "Custom error message", + + /** + * Shows a link (button) below the "Submit and pay" button on the summary page. Clicking this will take the user to a page + * that provides additional messaging, you can warn the user that this may delay their application for example. + * allowSubmissionWithoutPayment must be true for this to be shown. + */ + showPaymentSkippedWarningPage: false, + + /** + * Adds metadata to the GOV.UK Pay request. You may add static values, or values based on the user's answer. + */ + additionalReportingColumns: [ + { + columnName: "country", + fieldPath: "beforeYouStart.country", // the path in the state object to retrieve the value from. If the value is in a section, use the format {sectionName}.{fieldName}. + }, + { + columnName: "post", + fieldPath: "post", + }, + { + columnName: "service", + staticValue: "fee 11", + }, + ], + }, +} +``` + +As a failsafe, if a user was not able to pay, we will allow them to try up to 3 times (`maxAttempts`), then auto submit (`"allowSubmissionWithoutPayment": true`). +This is the default behaviour. Makes sure you check your organisations policy or legislative requirements. You must ensure there is a process to remediate payment failures. + +When a user fails a payment, they will see the page [pay-error](./../../runner/src/server/views/pay-error.html). + +When `allowSubmissionWithoutPayment` is true, the user will also see a link which allows them to skip payment. + +### Recommendations + +If your service does not allow submission without payment, set +`allowSubmissionWithoutPayment: false`. `maxAttempts` will have no effect. The user will be able to retry as many times as they like. +You can provide them with `customPayErrorMessage` to provide them with another route to payment. + +## paymentSkippedWarningPage + +`paymentSkippedWarningPage` can be found on the `specialPages` top level property. + +If `feeOptions.showPaymentSkippedWarningPage` (and `feeOptions.allowSubmissionWithoutPayment`) is true, +another page ([payment-skip-warning](./../../runner/src/server/views/payment-skip-warning.html)) will be presented to the user. +Additional messaging can be provided to the user for alternative routes to payment, or may result in application delays. +The can choose to continue or try online payment. This page will be shown only once. + +```json5 +{ + // pages, sections, conditions etc .. + paymentSkippedWarningPage: { + customText: { + caption: "Payment", + title: "Pay at appointment", + body: '

      You have chosen to skip payment. You will not be able to submit your application until you have paid.

      If you are unable to pay online, you\'ll need to bring the equivalent of £50 in cash in the local currency to your appointment. You wil not be given any change. Check current consular exchange rates

      ', + }, + }, +} +``` + +## Reporting columns + +[GOV.UK Pay allows additional reporting columns to be configured](https://docs.payments.service.gov.uk/api_reference/create_a_payment_reference/#json-body-parameters-for-39-create-a-payment-39). +This is useful if you wish to filter payments in GOV.UK Pay. In FCDO's case, it is useful to filter by country selected by the user. + +You may add static values, or values based on the user's answer. You may only configure 10 reporting columns as per +GOV.UK Pay's limits, and ensure that each columnName is <30 characters. The values may be 100 characters. + +```json5 +{ + //.. + additionalReportingColumns: [ + { + columnName: "country", + fieldPath: "beforeYouStart.country", // the path in the state object to retrieve the value from. If the value is in a section, use the format {sectionName}.{fieldName}. + }, + { + columnName: "post", + fieldPath: "post", + }, + { + columnName: "service", + staticValue: "fee 11", + }, + ], +} +``` + +If the value at the fieldPath cannot be found, the column will not be added to the metadata. + +Given the user state looks like + +```.ts +const state = { + beforeYouStart: { + country: "United Kingdom", + } +} +``` + +This will be parsed and sent to GOV.UK Pay as: + +```.ts + const requestOptions = { + //.. GOV.UK Pay request + metadata: { + country: "United Kingdom", + // no post key since it's not present in the user's state, + service: "fee 11" + } + } +``` + +When viewing this payment in GOV.UK Pay, you can sort by these columns, and will appear as "metadata" in their interface. + +## Additional payment metadata + +With fee options, there is the possibility to send through more payment metadata to your webhook outputs. This metadata will tell your webhook about the status of the payment, the payment id, and the payment reference. + +If you require this metadata, add the `sendAdditionaPayMetadata` option to your webhook output configuration as below: + +```json5 +{ + name: "outputName", + title: "Webhook output", + type: "webhook", + outputConfiguration: { + url: "https://some-url.com", + sendAdditionalPayMetadata: true, + }, +} +``` + +## Other - Reference numbers + +Reference numbers are generated with the alphabet "1234567890ABCDEFGHIJKLMNPQRSTUVWXYZ-\_". Note that the letter O is omitted. + +You may configure the length of the reference number by setting the environment variable `PAY_REFERENCE_LENGTH`. The default is 10 characters. +Use [Nano ID Collision Calculator](https://zelark.github.io/nano-id-cc/) to determine the right length for your service. +Since each user will "keep" their own reference number for multiple attempts, calculate the speed at unique users per hour. + +e.g. If your service expects 100,000 users per annum, you should expect ~274 users per day, and 11 users per hour. +Using nano-id-cc, and a reference length of 10 characters it will take 102 years, or 9 million IDs generated for a 1% chance of collision. diff --git a/docs/runner/multi-start-page.md b/docs/runner/multi-start-page.md new file mode 100644 index 0000000000..e4f0ece7dd --- /dev/null +++ b/docs/runner/multi-start-page.md @@ -0,0 +1,55 @@ +# Multi-page start pages + +Sometimes in your service it might be necessary to implement a multi-page start page, for example if there's two much content on one page. + +The form builder has a special page controller which can be used to achieve this effect. The controller matches the styles of the [carer's allowance start page](https://www.gov.uk/carers-allowance), the example for multi-page start pages, as closely as possible. + +## How it works + +To convert a standard page into a multi-page start page, you will need to add the following properties to your page definition: + +```json5 +{ + controller: "MultiStartPageController", + startPageNavigation: { + previous: { + labelText: "Previous page", + href: "/form-name/previous-page", + }, + next: { + labelText: "Next page", + href: "/form-name/next-page", + }, + }, +} +``` + +This will then create the page as a multi-page start page, with the previous and next page as paginated links. + +### Properties + +These are the multi-page specific properties which are either required or can be used to use other multi-page features. + +#### startPageNavigation - required + +`startPageNavigation` is a required property which is used to populate the pagination at the bottom of the page. + +It has a `previous` and `next` property which are used to populate each link, however both of these properties are optional in case a previous or next link cannot be specified. + +#### showContinueButton - optional + +`showContinueButton` is an optional property that defines whether the continue button should be shown on the page. The continue button is hidden by default, however if the flag is set `showContinueButton: true`, a continue button will be shown above the pagination footer. + +#### continueButtonText - optional + +`continueButtonText` defines the text to be shown on the continue button. By default, the button will say "Continue", however it may be necessary for you to have different text for your call to action e.g "Apply now". + +### Recommendations + +For the multi-page start pages to work with the form they must be in the main flow of the form i.e between the first page and the summary page of the form. With this in mind, to get the desired effect of the start pages, your page that leads to the rest of the form should have `showContinueButton: true` and should be placed before the actual start of the form. + +An example of this can be seen by looking at the `multi-page-example` form. + +If you want your call to action page to appear part way through your start pages, link this page to the start of your form questions, and keep the following start pages in an unreachable branch in the form. This way your latter start pages can still be accessed through the pagination in your start pages, however won't interrupt the flow of the form at all. + +The guidance for multi-page start pages advises putting all of your start pages under a shared heading, and then having a sub-heading outlining the name of the page. The best way to achieve this effect is to name all your start pages with the shared heading, but different paths, and then to add an HTML component with an `

      ` element providing your section title. diff --git a/docs/runner/redirects.md b/docs/runner/redirects.md new file mode 100644 index 0000000000..ad2e359475 --- /dev/null +++ b/docs/runner/redirects.md @@ -0,0 +1,54 @@ +# Redirects + +Pages in the form JSON can be configured to go to the next page in the form, or redirect to a new URL. This happens when the user +"continues" to the next page, and any field validations do not fail. + +To redirect to another URL, it must be a fully qualified URL (i.e. not a partial path). This will be useful if your service can be completed by another service or site. You must manually change the JSON to enable this feature. It is currently not supported in the designer. + +```json5 +{ + title: "Start", + path: "/start", + section: "beforeYouStart", + components: [ + { + name: "country", + type: "AutocompleteField", + title: "Country", + list: "SfkWjb", + }, + ], + next: [ + { + path: "/second-page", // next page in form + }, + { + redirect: "http://localhost:3009/help/cookies", // a URL you wish to redirect to + condition: "shouldRedirectToCookiesPage", + }, + ], +} +``` + +To go to the next page in the form, in the `next` array, add: + +```json5 +{ + path: "/second-page", // page.path of the next page in the form + condition: "..", // optional, set up a condition if you only want the user to go to this page if the condition succeeds +} +``` + +To redirect the user to another URL + +```json5 +{ + redirect: "http://localhost:3009/help/cookies", + condition: "shouldRedirectToCookiesPage", // optional +} +``` + +It is good practice to always have a page that does not have a condition attached, making it the "default" page. +This way, if the conditions fail to evaluate, the user will not see an error. + +See [redirects.json](../../e2e/cypress/fixtures/redirects.json) for a full example. diff --git a/docs/runner/session-initialisation-oas.yaml b/docs/runner/session-initialisation-oas.yaml new file mode 100644 index 0000000000..8768698b4a --- /dev/null +++ b/docs/runner/session-initialisation-oas.yaml @@ -0,0 +1,143 @@ +openapi: 3.0.0 +info: + title: Runner - initialise session + version: 1.0.0 +servers: + - url: http://localhost:3009 + +components: + schemas: + CallbackOptions: + type: object + properties: + callbackUrl: + description: The URL to send the PUT request to, after the user has completed the form + type: string + redirectPath: + description: Which page to send the user to, when after they've activated the session. Defaults to /{formId}/summary + type: string + message: + description: What to display at the top of the summary page + type: string + customText: + description: What to display on the application complete page. It mirrors the ConfirmationPage["customText"] schema. + type: object + properties: + paymentSkipped: + description: Setting to false disables this string from rendering on the application complete page. + oneOf: + - type: boolean + - type: string + nextSteps: + description: Setting to false disables this string from rendering on the application complete page. + oneOf: + - type: boolean + - type: string + components: + description: Any additional content components to display on the application complete page. It mirrors the ConfirmationPage["components"] schema. + type: array + items: + type: object + properties: + name: + type: string + options: + type: object + type: + type: string + content: + type: string + schema: + type: object + required: + - callbackUrl + + Question: + type: object + properties: + question: + type: string + category: + type: string + fields: + type: array + items: + type: object + properties: + key: + type: string + answer: + oneOf: + - type: string + - type: boolean + - type: number + required: + - key + - answer + + Metadata: + type: object + +paths: + /sessions/{formId}: + post: + summary: Submit a session with options and questions + parameters: + - name: formId + in: path + description: This must match the form JSONs' filename + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + options: + $ref: "#/components/schemas/CallbackOptions" + questions: + type: array + items: + $ref: "#/components/schemas/Question" + metadata: + $ref: "#/components/schemas/Metadata" + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + token: + type: string + "404": + description: Form not found + content: + application/json: + schema: + type: object + properties: + message: + type: string + "403": + description: Callback URL not allowed + content: + application/json: + schema: + type: object + properties: + message: + type: string + "400": + description: Both htmlMessage and message were provided + content: + application/json: + schema: + type: object + properties: + message: + type: string diff --git a/docs/runner/session-initialisation.md b/docs/runner/session-initialisation.md new file mode 100644 index 0000000000..877e446440 --- /dev/null +++ b/docs/runner/session-initialisation.md @@ -0,0 +1,96 @@ +# Session initialisation (rehydration) + +Sessions may be inserted into the form runner, and then activated by a user, given that they have the token. + +This is more suitable compared to [query-param-prepopulation](./designer/query-param-prepopulation.md) if you need to +prepopulate a lot of data or you do not want to send the user a URL with personal data in it. + +The general flow is: + +1. POST the user's session to `/session/{formId}` +1. The session will be stored in session storage (usually redis), as `{ [generatedToken]: sessionData }` +1. The POST request will respond with the generatedToken. The user will use this to activate their session +1. Your service sends the user (either by email, or showing them a URL on your service) + to `https://runner-url/session/{generatedToken}` +1. The user will be redirected to the configured pages (or to the summary page by default) +1. The session data is copied from `{ [generatedToken]: sessionData }`, to where it would "usually" go, which + is `{ [formId]: sessionData }` +1. Once activated, the token will be revoked, it cannot be used again + +## Environment variables + +| variable | type | example | description | +| ----------------------------- | -------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| SAFELIST | string[] | your.service.gov.uk | These are the allowed hostnames you wish to PUT data to, after the user has completed the form from a rehydrated session | +| INITIALISED_SESSION_TIMEOUT | number | 2419200000 | Time, in ms, you wish to keep a rehydrated session in the redis instance for. It will delete after this time if a user does not activate it | +| INITIALISED_SESSION_KEY | string | super-s3cure-p4ssw0rd | The user's token is generated with this key, similarly, the user's session is decrypted with this key. ⚠️ You must ensure this is set if you are deploying replicas. You must also ensure you re-issue tokens if you change this key. | +| INITIALISED_SESSION_ALGORITHM | string | HS512 | HS512 is the default. You may use: `RS256`, `RS384`, `RS512`,`PS256`, `PS384`, `PS512`, `ES256`, `ES384`, `ES512`, `EdDSA`, `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `HS256`, `HS384`, `HS512`. ⚠️ You must reissue your tokens if you change this algorithm. | + +## Initialising a session + +See [session-initialisation-oas.yaml](./session-initialisation-oas.yaml) for the Open API specification. + +Sample payload for POSTing to `/session/{formId}`: + +```json5 +{ + options: { + callbackUrl: "https://b4bf0fcd-1dd3-4650-92fe-d1f83885a447.mock.pstmn.io", + redirectPath: "/summary", // after session is activated, user will be redirected to ${formId}/${redirectPath} + message: "Please fix this thing..", //message to display to the user on the summary page + customText: { + //same as ConfirmationPage["customText"] + paymentSkipped: false, + nextSteps: false, + }, + components: [ + // same as ConfirmationPage["components"] + { + name: "WLskhZ", + options: {}, + type: "Html", + content: "Thanks!", + schema: {}, + }, + ], + }, + questions: [ + { + fields: [ + { + key: "size", + answer: "Large firm (350+ legal professionals)", + }, + ], + }, + { + question: "Can you provide legal services and support to customers in English?", // optional. This makes no difference, but it is what is originally sent on a "fresh" application + category: "mySection", //optional - category is renamed to "section". You MUST provide the category/section if your form uses sections. + fields: [ + { + key: "speakEnglish", + answer: true, + }, + ], + }, + ], + metadata: { id: "abc-001" }, // any additional information you'd like to send to the callback Url +} +``` + +Sample response for POSTing to `/session/{formId}`: + +```json5 +{ + token: "efg-hi5-jk7", +} +``` + +The session will now be available for one time use at `localhost:3009/session/efg-hi5-jk7`. The user must submit the form, +otherwise they will need to request a token from you again. + +You may generate and email tokens on an automated basis, for example, once a year. But it is recommended that you have a +"landing page" on an external application, which presents the user with a link or button. After clicking this link, +your external application should then generate the token, and redirect the user to it. +It means you do not have to worry about tokens expiring, or reissuing tokens if your INITIALISED_SESSION_KEY +or INITIALISE_SESSION_ALGORITHM has changed. diff --git a/docs/runner/submission-queue.md b/docs/runner/submission-queue.md new file mode 100644 index 0000000000..a82ed057f1 --- /dev/null +++ b/docs/runner/submission-queue.md @@ -0,0 +1,200 @@ +# Submission queue + +The runner can be configured to add new submissions to a queue and, if using the MYSQL queue type, for this queue to be +processed by the submitter module. + +Two queue types are currently allowed, MYSQL and PGBOSS. + +For `MYSQL`, enabling the queue service this will change the webhook process, so that the runner will push the +submission to a +specified database, and will await a response from the submitter for a few seconds before returning the success screen +to the user. + +For `PGBOSS`, which handles events and queues as expected from event based architecture. The `PGBOSS` queue type +uses [pg-boss](https://www.npmjs.com/package/pg-boss). +You must have a postgres >v11 database configured. The runner will add job to the queue. It will then +poll `pgBoss.getJobById` for the reference number you wish to return to the user. You must implement this yourself. + +In future, we may add support for different types of queues, like SQS. + +## Setup + +### Prerequisites + +Decide if event or message based architecture is the right approach for your service, and if you have the digital +capability to support it in your organisation. +You may need queuing if your service expects high volume of submissions, but your webhook endpoints or further +downstream endpoints change frequently or have slow response times. + +You will need to set up a MySQL or PostgreSQL database. + +Use `PGBOSS` and PostgreSQL for higher availability and features like exponential backoff. +It is highly recommended you use `PGBOSS` and PostgreSQL. MYSQL may be deprecated due to the additional overhead and +support that is required. + +#### PGBOSS Prerequisites + +- PostgreSQL database >=v11 +- A worker process which can connect to the PostgreSQL database, via PgBoss. Your implementation should look something like this + +```ts +export async function setupWorker() { + const pgboss = new PgBoss(config.get("Queue.url")); + await consumer.work( + "submission", + { newJobCheckInterval: 500 }, + submitHandler + ); +} + +setupWorker(); + +/** + * When a "submission" event is detected, this worker POSTs the data to `job.data.data.webhook_url` + * The source of this event is the runner, after a user has submitted a form. + */ +export async function submitHandler(job: Job) { + const { data } = job; + const requestBody = data.data; + const url = data.webhook_url; + try { + const res = await axios.post(url, requestBody); + const reference = res.data.reference; + if (reference) { + return { reference }; + } + } catch (e: any) { + throw e; + } +} +``` + +When using pgboss, it is important that successful work returns `{ reference }` so that the runner can retrieve the successful response. Thrown errors will be recorded in the database for you to investigate later. Logging has been omitted for brevity, but you should include it! + +- The `jobId` is generated when a users' submission is successfully inserted into the queue +- The webhook endpoint should respond with application/json `{ "reference": "FCDO-3252" }` + +#### MYSQL Prerequisites + +- MySQL database + +### Environment variables + +| Variable name | Definition | Default | Example | +| ------------------------------ | ---------------------------------------------------------------------------------------- | ------- | ------------------------------------------- | +| ENABLE_QUEUE_SERVICE | Whether the queue service is enabled or not | `false` | | +| QUEUE_DATABASE_TYPE | PGBOSS or MYSQL | | | +| QUEUE_DATABASE_URL | Used for configuring the endpoint of the database instance | | mysql://username:password@endpoint/database | +| QUEUE_DATABASE_USERNAME | Used for configuring the user being used to access the database | | root | +| QUEUE_DATABASE_PASSWORD | Used for configuring the password used for accessing the database | | password | +| QUEUE_SERVICE_POLLING_INTERVAL | The amount of time, in milliseconds, between poll requests for updates from the database | 500 | | +| QUEUE_SERVICE_POLLING_TIMEOUT | The total amount of time, in milliseconds, to poll requests for from the database | 2000 | | + +Webhooks can be configured so that the submitter only attempts to post to the webhook URL once. + +```.json +{ + "outputs": [ + { + "type": "webhook", + "name": "api", + "outputConfiguration": { + "url":"“https://api:9000", + "allowRetry": false + } + } + ] +} +``` + +## Running locally + +To use the submission queue locally, you will need to have a running instance of a database, the runner, and the +submitter. The easiest way to do this is by using the provided `docker-compose.yml` file. + +In that file, you will see the following lines commented out: + +```yaml +# - ENABLE_QUEUE_SERVICE=true +# - QUEUE_DATABASE_URL=mysql://root:root@mysql:3306/queue +# - DEBUG="prisma*" +``` + +```yaml +# if using MYSQL, uncomment submitter +# submitter: +# image: digital-form-builder-submitter +# build: +# context: . +# dockerfile: ./submitter/Dockerfile +# ports: +# - "9000:9000" +# environment: +# - PORT=9000 +# - QUEUE_DATABASE_URL=mysql://root:root@mysql:3306/queue +# - QUEUE_POLLING_INTERVAL=5000 +# - DEBUG="prisma*" +# command: yarn submitter start +# depends_on: +# mysql: +# condition: service_healthy +# mysql: +# container_name: mysql +# image: "mysql:latest" +# command: --default-authentication-plugin=mysql_native_password +# ports: +# - "3306:3306" +# environment: +# MYSQL_ROOT_PASSWORD: root +# MYSQL_DATABASE: queue +# healthcheck: +# test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] +# timeout: 20s +# retries: 10 + +# use psql if you want a PostgreSQL based queue (recommended) +# postgres: +# container_name: postgres +# image: "postgres:16" +# ports: +# - "5432:5432" +# environment: +# POSTGRES_DB: queue +# POSTGRES_PASSWORD: root +# POSTGRES_USER: user +``` + +Uncommenting the environment variables under the runner configuration will enable the queue service, set the database +url to the url of your mysql container, and turn on debug messages for prisma (the ORM used to communicate with the +database). +Uncommenting the mysql dependency will make sure the mysql server is started before prisma starts trying to connect to +it. +Uncommenting the submitter configuration will trigger the submitter to be created, exposed on port 9000, connecting to +the mysql container, with a polling interval of 5 seconds. + +Once your docker-compose file is ready, start all of your containers by using the command `docker compose up` +or `docker compose up -d` to run the containers in detached mode. + +## Error codes + +If sending the form submission to the queue, or polling the database for the form reference, is not successful the +following errors will be thrown: + +| Tags | Example | +| ------------------------------------------- | ----------------------------------------------------------------- | +| QueueStatusService, outputRequests | There was an issue sending the submission to the submission queue | +| QueueService, pollForRef, Row ref: [row_id] | Submission row not found | + +## Migration guide + +If you are moving from MYSQL to PGBOSS, ensure you have a worker which will handle the jobs added to your queue. For "zero downtime", + +1. Set up any new infrastructure components if necessary (e.g. database and worker) +1. Point the runner to the new components via `QUEUE_DATABASE_URL` +1. Keep the MySQL database as well as the submitter running. Do not delete these yet +1. Deploy new infrastructure components alongside the existing components + +Any submissions that have previously failed, or were submitted during deployment, can continue to run and submit to your webhook endpoints. +Check the database to ensure that there are no more failed entries. + +You may then safely remove the submitter, and MySQL database (if it is not used for any other purpose). diff --git a/docs/runner/templating.md b/docs/runner/templating.md new file mode 100644 index 0000000000..92c0ea7eba --- /dev/null +++ b/docs/runner/templating.md @@ -0,0 +1,29 @@ +# Templating + +If you find yourself faced with a form with content that needs to appear based on different field values, and there's a lot of options to choose from, putting all of this content in conditions may be at best very time-consuming, and at worst crash your form runner. + +With this in mind, templating may be a good solution for you. + +## How it works + +To enable templating on your form runner, you will need to set the environment variable `ALLOW_USER_TEMPLATES=true`. + +After this, you can allow fields to be exposed to the additional context by adding an `exposeToContext` flag to the component's options. This can be done manually, or through the "expose to context" field in the designer. + +Once your field is exposed, the field can be used with additional context by adding the field in titles and html components, using nunjucks templating syntax, `{{ fieldName }}`. + +You can also access additional values (such as custom html) using the additional context file. This will allow you to populate different variables based of the same user input, and these can be accessed using the format `{{ additionalContexts.contextName[fieldName].variableName }}`. + +There is an example form set up to demonstrate this. If you start your runner, and navigate to http://localhost:3009/html-templating-example, you can choose either option and see the dynamic content on the next page. + +## Adding your own additional context + +You can add your own additional context by modifying the additional context json, located at `runner/src/server/templates/additionalContexts.json`. + +Once you have added your own additionalContext namespace in the same way the example namespace is populated, you'll be able to add your context variables to your html component as stated above e.g for the example form, the list is set by referencing `{{ additionalContexts.example[contentToDisplay].listItems }}`. + +### Using nunjucks filters + +You can also apply nunjucks filters to your context, for example you may want to add the `safe` filter for printing html content. You would do this the same way you would in normal nunjucks, e.g. `{{ additionalContexts.example[contentToDisplay].listItems | safe }}`. + +For more information about what nunjucks filters are available to you, [visit the Nunjucks docs](https://mozilla.github.io/nunjucks/templating.html#filters). diff --git a/e2e/cypress/e2e/designer/notifyOutput.feature b/e2e/cypress/e2e/designer/notifyOutput.feature new file mode 100644 index 0000000000..4b28ffbdf2 --- /dev/null +++ b/e2e/cypress/e2e/designer/notifyOutput.feature @@ -0,0 +1,16 @@ +Feature: Notify output allows lists + As a user + I want to add a notify output + So that I can send emails to customers using values from the form submission + + Background: + Given the form "notifyOutput" exists + When I am viewing the designer at "/app/designer/notifyOutput" + Then The list "New list" should exist + + Scenario: Create GOVNotify output + When I open Outputs + * I choose Add output + * I use the GOVUK notify output type + * I add a personalisation + Then "New list (List)" should appear in the Description dropdown diff --git a/e2e/cypress/e2e/designer/notifyOutput.js b/e2e/cypress/e2e/designer/notifyOutput.js new file mode 100644 index 0000000000..d8ff4eecaa --- /dev/null +++ b/e2e/cypress/e2e/designer/notifyOutput.js @@ -0,0 +1,27 @@ +import { When, Then } from "@badeball/cypress-cucumber-preprocessor"; + +Then("The list {string} should exist", (listName) => { + cy.findByTestId("menu-lists").click(); + cy.findAllByTestId("edit-list").findByText(listName); + cy.findByText("Close").click(); +}); + +When("I open Outputs", () => { + cy.findByTestId("menu-outputs").click(); +}); + +When("I choose Add output", () => { + cy.findByTestId("add-output").click(); +}); + +When("I use the GOVUK notify output type", () => { + cy.findByLabelText("Output type").select("Email via GOVUK Notify"); +}); + +When("I add a personalisation", () => { + cy.findByTestId("add-notify-personalisation").click(); +}); + +Then("{string} should appear in the Description dropdown", (string) => { + cy.contains('[id="link-source"] option', string); +}); diff --git a/e2e/cypress/e2e/runner/backLinkFallback.feature b/e2e/cypress/e2e/runner/backLinkFallback.feature new file mode 100644 index 0000000000..cdf1a6ed46 --- /dev/null +++ b/e2e/cypress/e2e/runner/backLinkFallback.feature @@ -0,0 +1,20 @@ +Feature: Back link fallback + As a service team, + I want to be able to configure a back link fallback, + so that there is seamless integration between my different services + + As a user, + I want to click the back link, + so that I can return to the previous page or service. + + Scenario: Back link is displayed when there is no history + Given the form "backLinkFallback" exists + When I navigate to the "backLinkFallback" form + Then The back link href is "/help/cookies" + + Scenario: Back link fallback is not used if there is session history + Given the form "backLinkFallback" exists + When I navigate to the "backLinkFallback" form + Then The back link href is "/help/cookies" + When I continue + Then The back link href is "/backLinkFallback/start" \ No newline at end of file diff --git a/e2e/cypress/e2e/runner/backLinkFallback.js b/e2e/cypress/e2e/runner/backLinkFallback.js new file mode 100644 index 0000000000..cdd21c3ed7 --- /dev/null +++ b/e2e/cypress/e2e/runner/backLinkFallback.js @@ -0,0 +1,7 @@ +import { When, Then } from "@badeball/cypress-cucumber-preprocessor"; + +Then("The back link href is {string}", (href) => { + cy.findByRole("link", { name: "Back" }) + .should("have.attr", "href") + .and("eq", href); +}); diff --git a/e2e/cypress/e2e/runner/completeAForm.feature b/e2e/cypress/e2e/runner/completeAForm.feature index f7cb81250c..66f0f777d3 100644 --- a/e2e/cypress/e2e/runner/completeAForm.feature +++ b/e2e/cypress/e2e/runner/completeAForm.feature @@ -11,7 +11,7 @@ Feature: Complete a form * I continue * I choose "No, I don't have evidence" * I continue - * I enter "the additional info" for "Additional Info (Optional)" + * I enter "the additional info" for "Additional Info (optional)" * I continue Then I see a summary list with the values | title | value | @@ -51,7 +51,7 @@ Feature: Complete a form * I enter "jen+forms@cautionyourblast.com" for "Email address field" * I enter "123" for "Telephone number field" * I enter "line 1" for "Address line 1" - * I enter "line 2" for "Address line 2 (Optional)" + * I enter "line 2" for "Address line 2 (optional)" * I enter "London" for "Town or city" * I enter "ec2a4ps" for "Postcode" * I choose "Sole trader" @@ -67,7 +67,7 @@ Feature: Complete a form When I choose "Yes" And I continue * I enter "line 1" for "Address line 1" - * I enter "line 2" for "Address line 2 (Optional)" + * I enter "line 2" for "Address line 2 (optional)" * I enter "London" for "Town or city" * I enter "ec2a4ps" for "Postcode" * I enter "2025-12-25" for "What date was the vehicle registered at this address?" @@ -93,5 +93,5 @@ Feature: Complete a form Scenario: Error messages are displayed and can be resolved Given I navigate to the "report-a-terrorist" form When I continue - Then I see the error "Do you have a link to the material? is required" for "Do you have a link to the material?" + Then I see the error "Select do you have a link to the material?" for "Do you have a link to the material?" diff --git a/e2e/cypress/e2e/runner/dateValidation.feature b/e2e/cypress/e2e/runner/dateValidation.feature new file mode 100644 index 0000000000..6f7afd3784 --- /dev/null +++ b/e2e/cypress/e2e/runner/dateValidation.feature @@ -0,0 +1,35 @@ +Feature: Date validation + + Background: + Given the form "date" exists + + Scenario: Errors appear for missing date parts + When I navigate to the "date" form + When I enter the day "25" for "maxFiveDaysInFuture" + And I continue + Then I see the error "Enter a date at most 5 days in the future must include a month" for "Enter a date at most 5 days in the future" + When I enter the month "12" for "maxFiveDaysInFuture" + And I continue + Then I see the error "Enter a date at most 5 days in the future must include a year" for "Enter a date at most 5 days in the future" + When I enter the year "2000" for "maxFiveDaysInFuture" + And I continue + Then I don't see "Enter a date at most 5 days in the future must include a year" + + Scenario: Errors appear for invalid date parts + When I navigate to the "date" form + When I enter the day "50" for "maxFiveDaysInFuture" + When I enter the month "30" for "maxFiveDaysInFuture" + When I enter the year "1" for "maxFiveDaysInFuture" + And I continue + Then I see the date parts error "day must be between 1 and 31" + Then I see the date parts error "month must be between 1 and 12" + Then I see the date parts error "year must be 1000 or higher" + + + Scenario: Errors appear for max days in future and max days in past + When I navigate to the "date" form + When I enter a date 30 days in the future for "maxFiveDaysInFuture" + When I enter a date 30 days in the past for "maxFiveDaysInPast" + And I continue + Then I see the date parts with a partial error string "enter a date at most 5 days in the future must be the same as or before" for "maxFiveDaysInFuture" + Then I see the date parts with a partial error string "enter a date at most 5 days in the past must be the same as or after" for "maxFiveDaysInPast" diff --git a/e2e/cypress/e2e/runner/dateValidation.js b/e2e/cypress/e2e/runner/dateValidation.js new file mode 100644 index 0000000000..d0080e1a78 --- /dev/null +++ b/e2e/cypress/e2e/runner/dateValidation.js @@ -0,0 +1,78 @@ +import { When, Then } from "@badeball/cypress-cucumber-preprocessor"; + +When("I enter the day {string} for {string}", (day, fieldName) => { + cy.get(`#${fieldName}`).within(() => { + cy.findByLabelText("Day").type(day); + }); +}); + +When("I enter the month {string} for {string}", (month, fieldName) => { + cy.get(`#${fieldName}`).within(() => { + cy.findByLabelText("Month").type(month); + }); +}); + +When("I enter the year {string} for {string}", (year, fieldName) => { + cy.get(`#${fieldName}`).within(() => { + cy.findByLabelText("Year").type(year); + }); +}); + +Then("I see the date parts error {string}", (error) => { + /** + * Date parts only show one error at a time. + */ + cy.findByText("Fix the following errors"); + cy.findByRole("link", { name: error, exact: false }); +}); + +Then( + "I see the date parts with a partial error string {string} for {string}", + (error, fieldName) => { + /** + * Date parts only show one error at a time. + */ + cy.findByText("Fix the following errors"); + cy.get(`#${fieldName}-error`).within(() => { + cy.findByText(error, { exact: false }); + }); + } +); + +When( + "I enter a date {int} days in the future for {string}", + (days, fieldName) => { + const today = new Date(); + const date = new Date(today); + date.setDate(today.getDate() + days); + + const day = date.getDate(); + const month = date.getMonth() + 1; + const year = date.getFullYear(); + + cy.get(`#${fieldName}`).within(() => { + cy.findByLabelText("Day").type(day); + cy.findByLabelText("Month").type(month); + cy.findByLabelText("Year").type(year); + }); + } +); + +When( + "I enter a date {int} days in the past for {string}", + (days, fieldName) => { + const today = new Date(); + const date = new Date(today); + date.setDate(today.getDate() - days); + + const day = date.getDate(); + const month = date.getMonth() + 1; + const year = date.getFullYear(); + + cy.get(`#${fieldName}`).within(() => { + cy.findByLabelText("Day").type(day); + cy.findByLabelText("Month").type(month); + cy.findByLabelText("Year").type(year); + }); + } +); diff --git a/e2e/cypress/e2e/runner/htmlTemplating.feature b/e2e/cypress/e2e/runner/htmlTemplating.feature new file mode 100644 index 0000000000..5f9d53282c --- /dev/null +++ b/e2e/cypress/e2e/runner/htmlTemplating.feature @@ -0,0 +1,17 @@ +Feature: HTML templating in forms + + Scenario: Correct content should be shown for option one + When the form "html-templating-example" exists + And I choose "Answer 1" + And I continue + Then I see "This content is based on answer 1" + And I see "Item 1" + And I see "Item 2" + + Scenario: Correct content should be shown for option 2 + When the form "html-templating-example" exists + And I choose "Answer 2" + And I continue + Then I see "This content is based on answer 2" + And I see "Item 3" + And I see "Item 4" \ No newline at end of file diff --git a/e2e/cypress/e2e/runner/imageQualityPlayback.feature b/e2e/cypress/e2e/runner/imageQualityPlayback.feature new file mode 100644 index 0000000000..328b0fc04a --- /dev/null +++ b/e2e/cypress/e2e/runner/imageQualityPlayback.feature @@ -0,0 +1,24 @@ +Feature: Image quality playback page + + Background: + Given the form "image-quality-playback" exists + + Scenario Outline: Handling upload + Given I navigate to the "image-quality-playback" form + When I upload a file that "" + Then I see the heading "" + Examples: + | case | heading | + | fails-ocr | Check your image | + | passes | Summary | + + Scenario Outline: Navigating away from the playback page + Given I navigate to the "image-quality-playback" form + When I upload a file that "fails-ocr" + And I choose "