diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml
new file mode 100644
index 000000000..1965a4034
--- /dev/null
+++ b/.github/workflows/run_tests.yml
@@ -0,0 +1,411 @@
+name: Run Tests
+
+on:
+ workflow_call:
+ pull_request:
+ types:
+ - opened
+ - synchronize
+ merge_group:
+ workflow_dispatch:
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ test:
+ name: Tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.5
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+ PARALLEL_TEST_PROCESSORS: 4
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake parallel:setup
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rake parallel:spec['spec\/(?!features|models|requests|services)']
+
+ feature_test:
+ name: Feature Tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.5
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake db:prepare
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rspec spec/features --fail-fast --exclude-pattern "spec/features/accessibility_spec.rb"
+
+ model_test:
+ name: Model tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.5
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake db:prepare
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rspec spec/models --fail-fast
+
+ requests_test:
+ name: Requests tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.5
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+ PARALLEL_TEST_PROCESSORS: 4
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake parallel:setup
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rake parallel:spec['spec/requests']
+
+ services_test:
+ name: Services Tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.5
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+ PARALLEL_TEST_PROCESSORS: 4
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake parallel:setup
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rake parallel:spec['spec\/services']
+
+ accessibility_test:
+ name: Accessibility tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.5
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+ PARALLEL_TEST_PROCESSORS: 4
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake parallel:setup
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rspec spec/features/accessibility_spec.rb --fail-fast
+
+ lint:
+ name: Lint
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Install packages and symlink local dependencies
+ run: |
+ yarn install --immutable --immutable-cache --check-cache
+
+ - name: Lint
+ run: |
+ bundle exec rake lint
+
+ audit:
+ name: Audit dependencies
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Audit
+ run: |
+ bundle exec bundler-audit
diff --git a/.github/workflows/staging_pipeline.yml b/.github/workflows/staging_pipeline.yml
index aff0fe5f0..a2e777db0 100644
--- a/.github/workflows/staging_pipeline.yml
+++ b/.github/workflows/staging_pipeline.yml
@@ -4,11 +4,6 @@ on:
push:
branches:
- main
- pull_request:
- types:
- - opened
- - synchronize
- merge_group:
workflow_dispatch:
defaults:
@@ -21,347 +16,13 @@ env:
repository: core
jobs:
- test:
- name: Tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
- PARALLEL_TEST_PROCESSORS: 4
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake parallel:setup
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rake parallel:spec['spec\/(?!features|models|requests)']
-
- feature_test:
- name: Feature Tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake db:prepare
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rspec spec/features --fail-fast --exclude-pattern "spec/features/accessibility_spec.rb"
-
- model_test:
- name: Model tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake db:prepare
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rspec spec/models --fail-fast
-
- requests_test:
- name: Requests tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
- PARALLEL_TEST_PROCESSORS: 4
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake parallel:setup
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rake parallel:spec['spec/requests']
-
- accessibility_test:
- name: Accessibility tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
- PARALLEL_TEST_PROCESSORS: 4
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake parallel:setup
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rspec spec/features/accessibility_spec.rb --fail-fast
-
- lint:
- name: Lint
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v4
- with:
- cache: yarn
- node-version: 20
-
- - name: Install packages and symlink local dependencies
- run: |
- yarn install --immutable --immutable-cache --check-cache
-
- - name: Lint
- run: |
- bundle exec rake lint
-
- audit:
- name: Audit dependencies
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Audit
- run: |
- bundle exec bundler-audit
+ tests:
+ name: Run Tests
+ uses: ./.github/workflows/run_tests.yml
aws_deploy:
name: AWS Deploy
- if: github.ref == 'refs/heads/main'
- needs: [lint, test, feature_test, requests_test, model_test, audit]
+ needs: [tests]
uses: ./.github/workflows/aws_deploy.yml
with:
aws_account_id: 107155005276
diff --git a/Gemfile b/Gemfile
index b9ba79e16..1028f921a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,7 +6,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "3.1.4"
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
-gem "rails", "~> 7.0.8.5"
+gem "rails", "~> 7.0.8.7"
# Use postgresql as the database for Active Record
gem "pg", "~> 1.1"
# Use Puma as the app server
diff --git a/Gemfile.lock b/Gemfile.lock
index 055257574..66e4c9c41 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,71 +1,71 @@
GEM
remote: https://rubygems.org/
specs:
- actioncable (7.0.8.5)
- actionpack (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ actioncable (7.0.8.7)
+ actionpack (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
- actionmailbox (7.0.8.5)
- actionpack (= 7.0.8.5)
- activejob (= 7.0.8.5)
- activerecord (= 7.0.8.5)
- activestorage (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ actionmailbox (7.0.8.7)
+ actionpack (= 7.0.8.7)
+ activejob (= 7.0.8.7)
+ activerecord (= 7.0.8.7)
+ activestorage (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
mail (>= 2.7.1)
net-imap
net-pop
net-smtp
- actionmailer (7.0.8.5)
- actionpack (= 7.0.8.5)
- actionview (= 7.0.8.5)
- activejob (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ actionmailer (7.0.8.7)
+ actionpack (= 7.0.8.7)
+ actionview (= 7.0.8.7)
+ activejob (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
mail (~> 2.5, >= 2.5.4)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.0)
- actionpack (7.0.8.5)
- actionview (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ actionpack (7.0.8.7)
+ actionview (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
rack (~> 2.0, >= 2.2.4)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
- actiontext (7.0.8.5)
- actionpack (= 7.0.8.5)
- activerecord (= 7.0.8.5)
- activestorage (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ actiontext (7.0.8.7)
+ actionpack (= 7.0.8.7)
+ activerecord (= 7.0.8.7)
+ activestorage (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
- actionview (7.0.8.5)
- activesupport (= 7.0.8.5)
+ actionview (7.0.8.7)
+ activesupport (= 7.0.8.7)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
- activejob (7.0.8.5)
- activesupport (= 7.0.8.5)
+ activejob (7.0.8.7)
+ activesupport (= 7.0.8.7)
globalid (>= 0.3.6)
- activemodel (7.0.8.5)
- activesupport (= 7.0.8.5)
+ activemodel (7.0.8.7)
+ activesupport (= 7.0.8.7)
activemodel-serializers-xml (1.0.2)
activemodel (> 5.x)
activesupport (> 5.x)
builder (~> 3.1)
- activerecord (7.0.8.5)
- activemodel (= 7.0.8.5)
- activesupport (= 7.0.8.5)
- activestorage (7.0.8.5)
- actionpack (= 7.0.8.5)
- activejob (= 7.0.8.5)
- activerecord (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ activerecord (7.0.8.7)
+ activemodel (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
+ activestorage (7.0.8.7)
+ actionpack (= 7.0.8.7)
+ activejob (= 7.0.8.7)
+ activerecord (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
marcel (~> 1.0)
mini_mime (>= 1.1.0)
- activesupport (7.0.8.5)
+ activesupport (7.0.8.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@@ -149,7 +149,7 @@ GEM
crass (1.0.6)
cssbundling-rails (1.4.0)
railties (>= 6.0.0)
- date (3.3.4)
+ date (3.4.1)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.9.3)
@@ -258,13 +258,13 @@ GEM
matrix (0.4.2)
method_source (1.1.0)
mini_mime (1.1.5)
- minitest (5.25.1)
+ minitest (5.25.4)
msgpack (1.7.2)
multipart-post (2.4.1)
nested_form (0.3.2)
net-http (0.4.1)
uri
- net-imap (0.4.17)
+ net-imap (0.5.1)
date
net-protocol
net-pop (0.1.2)
@@ -273,12 +273,12 @@ GEM
timeout
net-smtp (0.5.0)
net-protocol
- nio4r (2.7.3)
- nokogiri (1.16.8-arm64-darwin)
+ nio4r (2.7.4)
+ nokogiri (1.17.1-arm64-darwin)
racc (~> 1.4)
- nokogiri (1.16.8-x86_64-darwin)
+ nokogiri (1.17.1-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.16.8-x86_64-linux)
+ nokogiri (1.17.1-x86_64-linux)
racc (~> 1.4)
notifications-ruby-client (6.0.0)
jwt (>= 1.5, < 3)
@@ -327,20 +327,20 @@ GEM
rack (>= 1.2.0)
rack-test (2.1.0)
rack (>= 1.3)
- rails (7.0.8.5)
- actioncable (= 7.0.8.5)
- actionmailbox (= 7.0.8.5)
- actionmailer (= 7.0.8.5)
- actionpack (= 7.0.8.5)
- actiontext (= 7.0.8.5)
- actionview (= 7.0.8.5)
- activejob (= 7.0.8.5)
- activemodel (= 7.0.8.5)
- activerecord (= 7.0.8.5)
- activestorage (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ rails (7.0.8.7)
+ actioncable (= 7.0.8.7)
+ actionmailbox (= 7.0.8.7)
+ actionmailer (= 7.0.8.7)
+ actionpack (= 7.0.8.7)
+ actiontext (= 7.0.8.7)
+ actionview (= 7.0.8.7)
+ activejob (= 7.0.8.7)
+ activemodel (= 7.0.8.7)
+ activerecord (= 7.0.8.7)
+ activestorage (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
bundler (>= 1.15.0)
- railties (= 7.0.8.5)
+ railties (= 7.0.8.7)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
@@ -354,9 +354,9 @@ GEM
nested_form (~> 0.3)
rails (>= 6.0, < 8)
turbo-rails (~> 1.0)
- railties (7.0.8.5)
- actionpack (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ railties (7.0.8.7)
+ actionpack (= 7.0.8.7)
+ activesupport (= 7.0.8.7)
method_source
rake (>= 12.2)
thor (~> 1.0)
@@ -465,7 +465,7 @@ GEM
thor (1.3.2)
thread_safe (0.3.6)
timecop (0.9.8)
- timeout (0.4.1)
+ timeout (0.4.2)
turbo-rails (1.5.0)
actionpack (>= 6.0.0)
activejob (>= 6.0.0)
@@ -553,7 +553,7 @@ DEPENDENCIES
rack (>= 2.2.6.3)
rack-attack
rack-mini-profiler (~> 2.0)
- rails (~> 7.0.8.5)
+ rails (~> 7.0.8.7)
rails_admin (~> 3.1)
redcarpet (~> 3.6)
redis (~> 4.8)
diff --git a/app/components/search_result_caption_component.html.erb b/app/components/search_result_caption_component.html.erb
index b8a9382b7..b2a28a505 100644
--- a/app/components/search_result_caption_component.html.erb
+++ b/app/components/search_result_caption_component.html.erb
@@ -7,7 +7,7 @@
<%= count %> <%= item_label.pluralize(count) %> matching filters
<% else %>
- <%= count %> total <%= item %>
+ <%= count %> total <%= item.pluralize(count) %>
<% end %>
diff --git a/app/controllers/bulk_upload_lettings_logs_controller.rb b/app/controllers/bulk_upload_lettings_logs_controller.rb
index a8ad14f9e..39bc05f7e 100644
--- a/app/controllers/bulk_upload_lettings_logs_controller.rb
+++ b/app/controllers/bulk_upload_lettings_logs_controller.rb
@@ -1,6 +1,7 @@
class BulkUploadLettingsLogsController < ApplicationController
before_action :authenticate_user!
- before_action :validate_data_protection_agrement_signed!
+ before_action :validate_data_protection_agreement_signed!
+ before_action :validate_year!, except: %w[start]
def start
if have_choice_of_year?
@@ -24,12 +25,26 @@ class BulkUploadLettingsLogsController < ApplicationController
private
- def validate_data_protection_agrement_signed!
+ def validate_data_protection_agreement_signed!
return if @current_user.organisation.data_protection_confirmed?
redirect_to lettings_logs_path
end
+ def validate_year!
+ return if params[:id] == "year"
+ return if params[:id] == "guidance" && params.dig(:form, :year).nil?
+
+ allowed_years = [current_year]
+ allowed_years.push(current_year - 1) if FormHandler.instance.lettings_in_crossover_period?
+ allowed_years.push(current_year + 1) if FeatureToggle.allow_future_form_use?
+
+ provided_year = params.dig(:form, :year)&.to_i
+ return if allowed_years.include?(provided_year)
+
+ render_not_found
+ end
+
def current_year
FormHandler.instance.current_collection_start_year
end
@@ -48,8 +63,6 @@ private
Forms::BulkUploadLettings::PrepareYourFile.new(form_params)
when "guidance"
Forms::BulkUploadLettings::Guidance.new(form_params.merge(referrer: params[:referrer]))
- when "needstype"
- Forms::BulkUploadLettings::Needstype.new(form_params)
when "upload-your-file"
Forms::BulkUploadLettings::UploadYourFile.new(form_params.merge(current_user:))
when "checking-file"
@@ -60,6 +73,6 @@ private
end
def form_params
- params.fetch(:form, {}).permit(:year, :needstype, :file, :organisation_id)
+ params.fetch(:form, {}).permit(:year, :file, :organisation_id)
end
end
diff --git a/app/controllers/bulk_upload_sales_logs_controller.rb b/app/controllers/bulk_upload_sales_logs_controller.rb
index 2fd312d10..cb04cea95 100644
--- a/app/controllers/bulk_upload_sales_logs_controller.rb
+++ b/app/controllers/bulk_upload_sales_logs_controller.rb
@@ -1,6 +1,7 @@
class BulkUploadSalesLogsController < ApplicationController
before_action :authenticate_user!
- before_action :validate_data_protection_agrement_signed!
+ before_action :validate_data_protection_agreement_signed!
+ before_action :validate_year!, except: %w[start]
def start
if have_choice_of_year?
@@ -24,12 +25,26 @@ class BulkUploadSalesLogsController < ApplicationController
private
- def validate_data_protection_agrement_signed!
+ def validate_data_protection_agreement_signed!
return if @current_user.organisation.data_protection_confirmed?
redirect_to sales_logs_path
end
+ def validate_year!
+ return if params[:id] == "year"
+ return if params[:id] == "guidance" && params.dig(:form, :year).nil?
+
+ allowed_years = [current_year]
+ allowed_years.push(current_year - 1) if FormHandler.instance.sales_in_crossover_period?
+ allowed_years.push(current_year + 1) if FeatureToggle.allow_future_form_use?
+
+ provided_year = params.dig(:form, :year)&.to_i
+ return if allowed_years.include?(provided_year)
+
+ render_not_found
+ end
+
def current_year
FormHandler.instance.current_collection_start_year
end
diff --git a/app/controllers/form_controller.rb b/app/controllers/form_controller.rb
index 7ce63e609..3e029371d 100644
--- a/app/controllers/form_controller.rb
+++ b/app/controllers/form_controller.rb
@@ -105,8 +105,13 @@ private
def restore_error_field_values(previous_responses)
return unless previous_responses
- previous_responses_to_reset = previous_responses.reject do |key, _|
- @log.form.get_question(key, @log)&.type == "date"
+ previous_responses_to_reset = previous_responses.reject do |key, value|
+ if @log.form.get_question(key, @log)&.type == "date" && value.present?
+ year = value.split("-").first.to_i
+ year&.zero?
+ else
+ false
+ end
end
@log.assign_attributes(previous_responses_to_reset)
@@ -433,7 +438,7 @@ private
@log.valid?
@log.reload
error_attributes = @log.errors.map(&:attribute)
- @questions = @log.form.questions.select { |q| error_attributes.include?(q.id.to_sym) }
+ @questions = @log.form.questions.select { |q| error_attributes.include?(q.id.to_sym) && q.page.routed_to?(@log, current_user) }
end
render "form/check_errors"
end
diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb
index 8ffe426d7..93b667a99 100644
--- a/app/controllers/organisations_controller.rb
+++ b/app/controllers/organisations_controller.rb
@@ -155,6 +155,7 @@ class OrganisationsController < ApplicationController
end
redirect_to details_organisation_path(@organisation)
else
+ @used_rent_periods = @organisation.lettings_logs.pluck(:period).uniq.compact.map(&:to_s)
@rent_periods = helpers.rent_periods_with_checked_attr(checked_periods: selected_rent_periods)
render :edit, status: :unprocessable_entity
end
diff --git a/app/helpers/form_page_error_helper.rb b/app/helpers/form_page_error_helper.rb
index 2c90bfd2a..bf4e1db08 100644
--- a/app/helpers/form_page_error_helper.rb
+++ b/app/helpers/form_page_error_helper.rb
@@ -13,7 +13,8 @@ module FormPageErrorHelper
end
end
- def all_questions_affected_by_errors(log)
- (log.errors.map(&:attribute) - [:base]).uniq
+ def all_pages_affected_by_errors(log)
+ question_ids = (log.errors.map(&:attribute) - [:base]).uniq
+ question_ids.map { |id| log.form.get_question(id, log)&.page&.id }.compact.uniq
end
end
diff --git a/app/mailers/bulk_upload_mailer.rb b/app/mailers/bulk_upload_mailer.rb
index e0115abb0..7c62f71a1 100644
--- a/app/mailers/bulk_upload_mailer.rb
+++ b/app/mailers/bulk_upload_mailer.rb
@@ -3,6 +3,7 @@ class BulkUploadMailer < NotifyMailer
COMPLETE_TEMPLATE_ID = "83279578-c890-4168-838b-33c9cf0dc9f0".freeze
FAILED_CSV_ERRORS_TEMPLATE_ID = "e27abcd4-5295-48c2-b127-e9ee4b781b75".freeze
+ FAILED_CSV_DUPLICATE_ERRORS_TEMPLATE_ID = "931d5bda-a08f-4de6-a455-38a63bff1956".freeze
FAILED_FILE_SETUP_ERROR_TEMPLATE_ID = "24c9f4c7-96ad-470a-ba31-eb51b7cbafd9".freeze
FAILED_SERVICE_ERROR_TEMPLATE_ID = "c3f6288c-7a74-4e77-99ee-6c4a0f6e125a".freeze
HOW_TO_FIX_UPLOAD_TEMPLATE_ID = "21a07b26-f625-4846-9f4d-39e30937aa24".freeze
@@ -95,6 +96,26 @@ class BulkUploadMailer < NotifyMailer
)
end
+ def send_correct_duplicates_and_upload_again_mail(bulk_upload:)
+ summary_report_link = if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
+ bulk_upload.sales? ? summary_bulk_upload_sales_result_url(bulk_upload) : summary_bulk_upload_lettings_result_url(bulk_upload)
+ else
+ bulk_upload.sales? ? bulk_upload_sales_result_url(bulk_upload) : bulk_upload_lettings_result_url(bulk_upload)
+ end
+
+ send_email(
+ bulk_upload.user.email,
+ FAILED_CSV_DUPLICATE_ERRORS_TEMPLATE_ID,
+ {
+ filename: bulk_upload.filename,
+ upload_timestamp: bulk_upload.created_at.to_fs(:govuk_date_and_time),
+ year_combo: bulk_upload.year_combo,
+ lettings_or_sales: bulk_upload.log_type,
+ summary_report_link:,
+ },
+ )
+ end
+
def send_bulk_upload_failed_file_setup_error_mail(bulk_upload:)
bulk_upload_link = if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
bulk_upload.sales? ? summary_bulk_upload_sales_result_url(bulk_upload) : summary_bulk_upload_lettings_result_url(bulk_upload)
diff --git a/app/models/form/sales/pages/owning_organisation.rb b/app/models/form/sales/pages/owning_organisation.rb
index f0c9e4e68..f1875d52d 100644
--- a/app/models/form/sales/pages/owning_organisation.rb
+++ b/app/models/form/sales/pages/owning_organisation.rb
@@ -20,11 +20,13 @@ class Form::Sales::Pages::OwningOrganisation < ::Form::Page
if current_user.organisation.holds_own_stock?
return true if current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?)
return true if stock_owners.count >= 1
+ return false if log.owning_organisation == current_user.organisation
log.update!(owning_organisation: current_user.organisation)
else
return false if stock_owners.count.zero?
return true if stock_owners.count > 1
+ return false if log.owning_organisation == stock_owners.first
log.update!(owning_organisation: stock_owners.first)
end
diff --git a/app/models/form/sales/questions/buyer2_working_situation.rb b/app/models/form/sales/questions/buyer2_working_situation.rb
index 38ab320b3..9105b8597 100644
--- a/app/models/form/sales/questions/buyer2_working_situation.rb
+++ b/app/models/form/sales/questions/buyer2_working_situation.rb
@@ -15,6 +15,10 @@ class Form::Sales::Questions::Buyer2WorkingSituation < ::Form::Question
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max]
end
+ def displayed_answer_options(_log, _user = nil)
+ answer_options.reject { |key, _| key == "9" }
+ end
+
def answer_options
if form.start_year_2025_or_later?
{
@@ -26,6 +30,7 @@ class Form::Sales::Questions::Buyer2WorkingSituation < ::Form::Question
"6" => { "value" => "Not seeking work" },
"7" => { "value" => "Full-time student" },
"8" => { "value" => "Unable to work due to long term sick or disability" },
+ "9" => { "value" => "Child under 16" },
"0" => { "value" => "Other" },
"10" => { "value" => "Buyer prefers not to say" },
}.freeze
@@ -41,6 +46,7 @@ class Form::Sales::Questions::Buyer2WorkingSituation < ::Form::Question
"0" => { "value" => "Other" },
"10" => { "value" => "Buyer prefers not to say" },
"7" => { "value" => "Full-time student" },
+ "9" => { "value" => "Child under 16" },
}.freeze
end
end
diff --git a/app/models/forms/bulk_upload_lettings/needstype.rb b/app/models/forms/bulk_upload_lettings/needstype.rb
deleted file mode 100644
index b15c05b52..000000000
--- a/app/models/forms/bulk_upload_lettings/needstype.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-module Forms
- module BulkUploadLettings
- class Needstype
- include ActiveModel::Model
- include ActiveModel::Attributes
- include Rails.application.routes.url_helpers
-
- attribute :needstype, :integer
- attribute :year, :integer
- attribute :organisation_id, :integer
-
- validates :needstype, presence: true
-
- def view_path
- "bulk_upload_lettings_logs/forms/needstype"
- end
-
- def options
- [OpenStruct.new(id: 1, name: "General needs"), OpenStruct.new(id: 2, name: "Supported housing")]
- end
-
- def back_path
- bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year:, needstype:, organisation_id: }.compact)
- end
-
- def next_path
- bulk_upload_lettings_log_path(id: "upload-your-file", form: { year:, needstype:, organisation_id: }.compact)
- end
-
- def year_combo
- "#{year} to #{year + 1}"
- end
-
- def save!
- true
- end
- end
- end
-end
diff --git a/app/models/organisation.rb b/app/models/organisation.rb
index 23f91f1ad..69c80d198 100644
--- a/app/models/organisation.rb
+++ b/app/models/organisation.rb
@@ -58,6 +58,7 @@ class Organisation < ApplicationRecord
alias_method :la?, :LA?
validates :name, presence: { message: I18n.t("validations.organisation.name_missing") }
+ validates :name, uniqueness: { case_sensitive: false, message: I18n.t("validations.organisation.name_not_unique") }
validates :provider_type, presence: { message: I18n.t("validations.organisation.provider_type_missing") }
def self.find_by_id_on_multiple_fields(id)
diff --git a/app/models/scheme.rb b/app/models/scheme.rb
index 1cd56ac7d..a9b479342 100644
--- a/app/models/scheme.rb
+++ b/app/models/scheme.rb
@@ -329,9 +329,9 @@ class Scheme < ApplicationRecord
def status_at(date)
return :deleted if discarded_at.present?
- return :incomplete unless confirmed && locations.confirmed.any?
return :deactivated if owning_organisation.status_at(date) == :deactivated || owning_organisation.status_at(date) == :merged ||
(open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date)
+ return :incomplete unless confirmed && locations.confirmed.any?
return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
return :reactivating_soon if last_deactivation_before(date)&.reactivation_date.present? && date < last_deactivation_before(date).reactivation_date
return :activating_soon if startdate.present? && date < startdate
diff --git a/app/models/validations/property_validations.rb b/app/models/validations/property_validations.rb
index e9eba8184..1cf710857 100644
--- a/app/models/validations/property_validations.rb
+++ b/app/models/validations/property_validations.rb
@@ -41,6 +41,8 @@ module Validations::PropertyValidations
def validate_property_postcode(record)
postcode = record.postcode_full
+ return unless postcode
+
if record.postcode_known? && (postcode.blank? || !postcode.match(POSTCODE_REGEXP))
error_message = I18n.t("validations.lettings.property.postcode_full.invalid")
record.errors.add :postcode_full, :wrong_format, message: error_message
diff --git a/app/models/validations/sales/property_validations.rb b/app/models/validations/sales/property_validations.rb
index 2238a634a..7fd4d2440 100644
--- a/app/models/validations/sales/property_validations.rb
+++ b/app/models/validations/sales/property_validations.rb
@@ -31,6 +31,8 @@ module Validations::Sales::PropertyValidations
def validate_property_postcode(record)
postcode = record.postcode_full
+ return unless postcode
+
if record.postcode_known? && (postcode.blank? || !postcode.match(POSTCODE_REGEXP))
error_message = I18n.t("validations.sales.property_information.postcode_full.invalid")
record.errors.add :postcode_full, :wrong_format, message: error_message
diff --git a/app/services/bulk_upload/lettings/validator.rb b/app/services/bulk_upload/lettings/validator.rb
index 116c3b745..291bf45e7 100644
--- a/app/services/bulk_upload/lettings/validator.rb
+++ b/app/services/bulk_upload/lettings/validator.rb
@@ -40,29 +40,25 @@ class BulkUpload::Lettings::Validator
end
end
- def create_logs?
- return false if any_setup_errors?
+ def block_log_creation_reason
+ return "setup_errors" if any_setup_errors?
if row_parsers.any?(&:block_log_creation?)
Sentry.capture_message("Bulk upload log creation blocked: #{bulk_upload.id}.")
- return false
+ return "row_parser_block_log_creation"
end
if any_logs_already_exist? && FeatureToggle.bulk_upload_duplicate_log_check_enabled?
- Sentry.capture_message("Bulk upload log creation blocked due to duplicate logs: #{bulk_upload.id}.")
- return false
+ return "duplicate_logs"
end
row_parsers.each do |row_parser|
row_parser.log.blank_invalid_non_setup_fields!
end
-
if any_logs_invalid?
Sentry.capture_message("Bulk upload log creation blocked due to invalid logs after blanking non setup fields: #{bulk_upload.id}.")
- return false
+ "logs_invalid"
end
-
- true
end
def self.question_for_field(field)
diff --git a/app/services/bulk_upload/processor.rb b/app/services/bulk_upload/processor.rb
index 38f67ede4..c54032fda 100644
--- a/app/services/bulk_upload/processor.rb
+++ b/app/services/bulk_upload/processor.rb
@@ -36,20 +36,28 @@ class BulkUpload::Processor
if validator.any_setup_errors?
send_setup_errors_mail
-
- elsif validator.create_logs?
- create_logs
-
- if validator.soft_validation_errors_only?
- send_check_soft_validations_mail
- elsif created_logs_but_incompleted?
- send_how_to_fix_upload_mail
- elsif created_logs_and_all_completed?
- bulk_upload.unpend
- send_success_mail
- end
else
- send_correct_and_upload_again_mail # summary/full report
+ block_creation_reason = validator.block_log_creation_reason
+
+ if block_creation_reason.present?
+ case block_creation_reason
+ when "duplicate_logs"
+ send_correct_duplicates_and_upload_again_mail
+ else
+ send_correct_and_upload_again_mail # summary/full report
+ end
+ else
+ create_logs
+
+ if validator.soft_validation_errors_only?
+ send_check_soft_validations_mail
+ elsif created_logs_but_incompleted?
+ send_how_to_fix_upload_mail
+ elsif created_logs_and_all_completed?
+ bulk_upload.unpend
+ send_success_mail
+ end
+ end
end
rescue StandardError => e
Sentry.capture_exception(e)
@@ -97,6 +105,12 @@ private
.deliver_later
end
+ def send_correct_duplicates_and_upload_again_mail
+ BulkUploadMailer
+ .send_correct_duplicates_and_upload_again_mail(bulk_upload:)
+ .deliver_later
+ end
+
def send_success_mail
BulkUploadMailer
.send_bulk_upload_complete_mail(user:, bulk_upload:)
diff --git a/app/services/bulk_upload/sales/validator.rb b/app/services/bulk_upload/sales/validator.rb
index 76fb6f1ae..7ad9638d7 100644
--- a/app/services/bulk_upload/sales/validator.rb
+++ b/app/services/bulk_upload/sales/validator.rb
@@ -39,17 +39,17 @@ class BulkUpload::Sales::Validator
end
end
- def create_logs?
- return false if any_setup_errors?
+ def block_log_creation_reason
+ return "setup_errors" if any_setup_errors?
if row_parsers.any?(&:block_log_creation?)
Sentry.capture_message("Bulk upload log creation blocked: #{bulk_upload.id}.")
- return false
+ return "row_parser_block_log_creation"
end
if any_logs_already_exist? && FeatureToggle.bulk_upload_duplicate_log_check_enabled?
Sentry.capture_message("Bulk upload log creation blocked due to duplicate logs: #{bulk_upload.id}.")
- return false
+ return "duplicate_logs"
end
row_parsers.each do |row_parser|
@@ -58,10 +58,8 @@ class BulkUpload::Sales::Validator
if any_logs_invalid?
Sentry.capture_message("Bulk upload log creation blocked due to invalid logs after blanking non setup fields: #{bulk_upload.id}.")
- return false
+ "logs_invalid"
end
-
- true
end
def any_setup_errors?
diff --git a/app/views/bulk_upload_lettings_logs/forms/needstype.erb b/app/views/bulk_upload_lettings_logs/forms/needstype.erb
deleted file mode 100644
index 644dd9f5f..000000000
--- a/app/views/bulk_upload_lettings_logs/forms/needstype.erb
+++ /dev/null
@@ -1,23 +0,0 @@
-<% content_for :before_content do %>
- <%= govuk_back_link href: @form.back_path %>
-<% end %>
-
-