Browse Source

Merge branch 'main' into import-users

pull/276/head
Stéphane Meny 3 years ago committed by GitHub
parent
commit
873b378c9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      Dockerfile
  2. 33
      Dockerfile_dev
  3. 8
      Gemfile.lock
  4. 28
      README.md
  5. 6
      app/models/form/question.rb
  6. 12
      app/views/devise/two_factor_authentication/max_login_attempts_reached.html.erb
  7. 4
      config/database.yml
  8. 9
      config/forms/2021_2022.json
  9. 7
      config/locales/en.yml
  10. 9
      db/migrate/20220203145845_remove_why_dont_you_know_la.rb
  11. 6
      db/schema.rb
  12. 8
      docker-compose.yml
  13. 2
      spec/features/form/check_answers_page_spec.rb
  14. 4
      spec/features/form/tasklist_page_spec.rb
  15. 1
      spec/fixtures/complete_case_log.json
  16. 38
      spec/fixtures/forms/2021_2022.json
  17. 4
      spec/helpers/tasklist_helper_spec.rb
  18. 26
      spec/models/form/question_spec.rb
  19. 9
      spec/models/form_spec.rb
  20. 4
      spec/requests/case_logs_controller_spec.rb

2
Dockerfile

@ -16,7 +16,7 @@ RUN apk add --no-cache build-base yarn postgresql-dev git
# Install bundler to run bundle exec # Install bundler to run bundle exec
# This should be the same version as the Gemfile.lock # This should be the same version as the Gemfile.lock
RUN gem install bundler:2.2.3 --no-document RUN gem install bundler:2.3.4 --no-document
# Install gems defined in Gemfile # Install gems defined in Gemfile
COPY .ruby-version Gemfile Gemfile.lock /app/ COPY .ruby-version Gemfile Gemfile.lock /app/

33
Dockerfile_dev

@ -0,0 +1,33 @@
# Build compilation image
FROM ruby:3.0.3-alpine3.14 as builder
# The application runs from /app
WORKDIR /app
# Add the timezone as it's not configured by default in Alpine
RUN apk add --update --no-cache tzdata && cp /usr/share/zoneinfo/Europe/London /etc/localtime && echo "Europe/London" > /etc/timezone
RUN apk add --no-cache build-base yarn postgresql-dev git bash
# Install bundler to run bundle exec
# This should be the same version as the Gemfile.lock
RUN gem install bundler:2.3.4 --no-document
# Install gems defined in Gemfile
COPY .ruby-version Gemfile Gemfile.lock /app/
ARG BUNDLE_FLAGS="--jobs=4 --no-binstubs --no-cache"
RUN bundle install ${BUNDLE_FLAGS}
# Install node packages defined in package.json, including webpack
COPY package.json yarn.lock /app/
RUN yarn install --frozen-lockfile
# Copy all files to /app (except what is defined in .dockerignore)
COPY . /app/
ENV PORT=8080
EXPOSE ${PORT}
CMD RAILS_ENV=${RAILS_ENV} bundle exec rake db:migrate && bundle exec rails s -e ${RAILS_ENV} -p ${PORT} --binding=0.0.0.0

8
Gemfile.lock

@ -8,7 +8,7 @@ GIT
GIT GIT
remote: https://github.com/baarkerlounger/devise.git remote: https://github.com/baarkerlounger/devise.git
revision: ac956cc2a58daa57e071202967a212a1dac08053 revision: 6d0b6b52a9d0e87ae6d9f9acb562169751623078
branch: dluhc-fixes branch: dluhc-fixes
specs: specs:
devise (4.8.1) devise (4.8.1)
@ -31,7 +31,7 @@ GIT
GIT GIT
remote: https://github.com/tagliala/activeadmin.git remote: https://github.com/tagliala/activeadmin.git
revision: d1492c54e76871d95f3a7ff20e445b48f455d4cb revision: 5d6dfbe086331ce0538cc726abfe2eebe0260f02
branch: feature/railties-7 branch: feature/railties-7
specs: specs:
activeadmin (2.9.0) activeadmin (2.9.0)
@ -116,7 +116,7 @@ GEM
public_suffix (>= 2.0.2, < 5.0) public_suffix (>= 2.0.2, < 5.0)
ast (2.4.2) ast (2.4.2)
aws-eventstream (1.2.0) aws-eventstream (1.2.0)
aws-partitions (1.552.0) aws-partitions (1.553.0)
aws-sdk-core (3.126.0) aws-sdk-core (3.126.0)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0) aws-partitions (~> 1, >= 1.525.0)
@ -327,7 +327,7 @@ GEM
activerecord (>= 5.2.4) activerecord (>= 5.2.4)
activesupport (>= 5.2.4) activesupport (>= 5.2.4)
i18n i18n
rb-fsevent (0.11.0) rb-fsevent (0.11.1)
rb-inotify (0.10.1) rb-inotify (0.10.1)
ffi (~> 1.0) ffi (~> 1.0)
regexp_parser (2.2.0) regexp_parser (2.2.0)

28
README.md

@ -29,25 +29,37 @@ Pre-requisites:
4. Run the database migrations:\ 4. Run the database migrations:\
`rake db:migrate` `rake db:migrate`
5. Install the frontend depenencies:\ 5. Seed the database if required:\
`rake db:seed`
6. Install the frontend depenencies:\
`yarn install` `yarn install`
6. Start the Rails server:\ 7. Start the Rails server:\
`bundle exec rails s` `bundle exec rails s`
The Rails server will start on <http://localhost:3000>. The Rails server will start on <http://localhost:3000>.
### Using Docker ### Using Docker
```sh 1. Build the image:\
docker-compose build `docker-compose build`
docker-compose run --rm app rails db:create
docker-compose up 2. Run the database migrations:\
``` `docker-compose run --rm app /bin/bash -c 'rake db:migrate'`
3. Seed the database if required:\
`docker-compose run --rm app /bin/bash -c 'rake db:seed'`
4. To be able to debug with Pry run the app using:\
`docker-compose run --service-ports app`
If this is not needed you can run `docker-compose up` as normal
The Rails server will start on <http://localhost:8080>. The Rails server will start on <http://localhost:8080>.
Note `docker-compose` runs the production docker image (`RAILS_ENV=production`) as the Dockerfile doesn’t include development gems to keep the image size down.
## Infrastructure ## Infrastructure

6
app/models/form/question.rb

@ -83,11 +83,15 @@ class Form::Question
return false if id == "gdpr_acceptance" && case_log[id] == "No" return false if id == "gdpr_acceptance" && case_log[id] == "No"
return answer_options.keys.any? { |key| case_log[key] == "Yes" } if type == "checkbox" return answer_options.keys.any? { |key| case_log[key] == "Yes" } if type == "checkbox"
case_log[id].present? || !case_log.respond_to?(id.to_sym) case_log[id].present? || !case_log.respond_to?(id.to_sym) || has_inferred_display_value?(case_log)
end end
private private
def has_inferred_display_value?(case_log)
inferred_check_answers_value.present? && case_log[inferred_check_answers_value["condition"].keys.first] == inferred_check_answers_value["condition"].values.first
end
def checkbox_answer_label(case_log) def checkbox_answer_label(case_log)
answer = [] answer = []
answer_options.each { |key, value| case_log[key] == "Yes" ? answer << value : nil } answer_options.each { |key, value| case_log[key] == "Yes" ? answer << value : nil }

12
app/views/devise/two_factor_authentication/max_login_attempts_reached.html.erb

@ -0,0 +1,12 @@
<% content_for :title, I18n.t("devise.two_factor_authentication.max_login_attempts_reached") %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<h1 class="govuk-heading-l">
<%= content_for(:title) %>
</h1>
<p><%= I18n.t("devise.two_factor_authentication.account_locked") %></p>
<p><%= I18n.t("devise.two_factor_authentication.contact_administrator") %></p>
</div>
</div>

4
config/database.yml

@ -28,8 +28,8 @@ default: &default
development: development:
<<: *default <<: *default
database: data_collector_development database: <%= ENV['DB_DATABASE'] || 'data_collector_development' %>
host: localhost host: <%= ENV['DB_HOST'] || 'localhost' %>
staging: staging:
<<: *default <<: *default

9
config/forms/2021_2022.json

@ -1716,16 +1716,7 @@
"answer_options": { "answer_options": {
"1": "Yes", "1": "Yes",
"0": "No" "0": "No"
},
"conditional_for": {
"why_dont_you_know_la": ["No"]
} }
},
"why_dont_you_know_la": {
"check_answer_label": "Reason you don’t know the postcode or local authority",
"header": "Give a reason why you don’t know the postcode or local authority",
"hint_text": "",
"type": "textarea"
} }
}, },
"depends_on": [{ "is_la_inferred": false }] "depends_on": [{ "is_la_inferred": false }]

7
config/locales/en.yml

@ -126,6 +126,9 @@ en:
two_factor_authentication: two_factor_authentication:
success: "Two factor authentication successful." success: "Two factor authentication successful."
attempt_failed: "Attempt failed." attempt_failed: "Attempt failed."
max_login_attempts_reached: "Access completely denied as you have reached your attempts limit" max_login_attempts_reached: "Too many incorrect login attempts"
contact_administrator: "Please contact your system administrator." account_locked: "Your account has been locked for security reasons."
contact_administrator: "Contact another helpdesk administrator for access."
code_has_been_sent: "Your security code has been sent." code_has_been_sent: "Your security code has been sent."
code_required: "Security code is required"
code_incorrect: "Security code is incorrect"

9
db/migrate/20220203145845_remove_why_dont_you_know_la.rb

@ -0,0 +1,9 @@
class RemoveWhyDontYouKnowLa < ActiveRecord::Migration[7.0]
def up
remove_column :case_logs, :why_dont_you_know_la
end
def down
add_column :case_logs, :why_dont_you_know_la, :string
end
end

6
db/schema.rb

@ -10,8 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 202202071123100) do ActiveRecord::Schema.define(version: 2022_02_07_1123100) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -93,7 +92,6 @@ ActiveRecord::Schema.define(version: 202202071123100) do
t.integer "beds" t.integer "beds"
t.integer "offered" t.integer "offered"
t.integer "wchair" t.integer "wchair"
t.integer "earnings"
t.integer "incfreq" t.integer "incfreq"
t.integer "benefits" t.integer "benefits"
t.integer "period" t.integer "period"
@ -162,7 +160,6 @@ ActiveRecord::Schema.define(version: 202202071123100) do
t.datetime "startdate" t.datetime "startdate"
t.integer "armedforces" t.integer "armedforces"
t.integer "first_time_property_let_as_social_housing" t.integer "first_time_property_let_as_social_housing"
t.string "why_dont_you_know_la"
t.integer "unitletas" t.integer "unitletas"
t.integer "builtype" t.integer "builtype"
t.datetime "property_void_date" t.datetime "property_void_date"
@ -186,6 +183,7 @@ ActiveRecord::Schema.define(version: 202202071123100) do
t.integer "is_carehome" t.integer "is_carehome"
t.integer "letting_in_sheltered_accomodation" t.integer "letting_in_sheltered_accomodation"
t.integer "household_charge" t.integer "household_charge"
t.integer "earnings"
t.integer "referral" t.integer "referral"
t.decimal "brent", precision: 10, scale: 2 t.decimal "brent", precision: 10, scale: 2
t.decimal "scharge", precision: 10, scale: 2 t.decimal "scharge", precision: 10, scale: 2

8
docker-compose.yml

@ -5,7 +5,7 @@ volumes:
services: services:
db: db:
image: postgres:13.3-alpine image: postgres:13.5-alpine
restart: always restart: always
# To preserve data between runs of docker-compose, we mount a folder from the host machine. # To preserve data between runs of docker-compose, we mount a folder from the host machine.
volumes: volumes:
@ -20,9 +20,7 @@ services:
app: app:
build: build:
context: . context: .
dockerfile: ./Dockerfile dockerfile: ./Dockerfile_dev
args:
GIT_COMMIT_SHA: DOCKER_COMPOSE_GIT_COMMIT_SHA
ports: ports:
- 8080:8080 - 8080:8080
depends_on: depends_on:
@ -32,7 +30,7 @@ services:
- DB_DATABASE=data_collector - DB_DATABASE=data_collector
- DB_USERNAME=postgres - DB_USERNAME=postgres
- DB_PASSWORD=password - DB_PASSWORD=password
- RAILS_ENV=production - RAILS_ENV=development
- RAILS_SERVE_STATIC_FILES=true - RAILS_SERVE_STATIC_FILES=true
- RAILS_LOG_TO_STDOUT=true - RAILS_LOG_TO_STDOUT=true
- SECRET_KEY_BASE=abcd1234 - SECRET_KEY_BASE=abcd1234

2
spec/features/form/check_answers_page_spec.rb

@ -209,7 +209,7 @@ RSpec.describe "Form Check Answers Page" do
end end
it "they can click a button to cycle around to the next incomplete section" do it "they can click a button to cycle around to the next incomplete section" do
visit("/logs/#{cycle_sections_case_log.id}/local-authority/check-answers") visit("/logs/#{cycle_sections_case_log.id}/setup/check-answers")
click_link("Save and go to next incomplete section") click_link("Save and go to next incomplete section")
expect(page).to have_current_path("/logs/#{cycle_sections_case_log.id}/tenant-code") expect(page).to have_current_path("/logs/#{cycle_sections_case_log.id}/tenant-code")
end end

4
spec/features/form/tasklist_page_spec.rb

@ -33,12 +33,12 @@ RSpec.describe "Task List" do
it "shows the number of completed sections if no sections are completed" do it "shows the number of completed sections if no sections are completed" do
visit("/logs/#{empty_case_log.id}") visit("/logs/#{empty_case_log.id}")
expect(page).to have_content("You have completed 0 of 9 sections.") expect(page).to have_content("You have completed 0 of 10 sections.")
end end
it "shows the number of completed sections if one section is completed" do it "shows the number of completed sections if one section is completed" do
answer_all_questions_in_income_subsection(empty_case_log) answer_all_questions_in_income_subsection(empty_case_log)
visit("/logs/#{empty_case_log.id}") visit("/logs/#{empty_case_log.id}")
expect(page).to have_content("You have completed 1 of 9 sections.") expect(page).to have_content("You have completed 1 of 10 sections.")
end end
end end

1
spec/fixtures/complete_case_log.json vendored

@ -136,7 +136,6 @@
"postcod2": "w3", "postcod2": "w3",
"ppostc1": "w3", "ppostc1": "w3",
"ppostc2": "w3", "ppostc2": "w3",
"why_dont_you_know_la": "Forgot",
"first_time_property_let_as_social_housing": "No", "first_time_property_let_as_social_housing": "No",
"unitletas": "Affordable rent basis", "unitletas": "Affordable rent basis",
"builtype": "Purpose built", "builtype": "Purpose built",

38
spec/fixtures/forms/2021_2022.json vendored

@ -593,18 +593,6 @@
} }
} }
}, },
"why_dont_you_know_la": {
"header": "",
"description": "",
"questions": {
"reason": {
"check_answer_label": "Reason for not knowing local authority",
"header": "Give a reason why you don’t know the postcode or local authority",
"hint_text": "",
"type": "textarea"
}
}
},
"property_postcode": { "property_postcode": {
"questions": { "questions": {
"property_postcode": { "property_postcode": {
@ -638,6 +626,32 @@
} }
} }
}, },
"setup": {
"label": "Before you start",
"subsections": {
"setup": {
"label": "Set up your lettings log",
"pages": {
"gdpr_acceptance": {
"header": "",
"description": "",
"questions": {
"gdpr_acceptance": {
"check_answer_label": "Privacy notice seen",
"header": "Has the tenant or buyer seen the Department for Levelling Up, Housing and Communities (DLUHC) privacy notice?",
"hint_text": "You must <a class=\"govuk-link\" href=\"/files/privacy-notice.pdf\">show the privacy notice</a> to the tenant or buyer before you can use this service.",
"type": "radio",
"answer_options": {
"0": "Yes",
"1": "No"
}
}
}
}
}
}
}
},
"submission": { "submission": {
"label": "Submission", "label": "Submission",
"subsections": { "subsections": {

4
spec/helpers/tasklist_helper_spec.rb

@ -22,7 +22,7 @@ RSpec.describe TasklistHelper do
describe "get sections count" do describe "get sections count" do
it "returns the total of sections if no status is given" do it "returns the total of sections if no status is given" do
expect(get_subsections_count(empty_case_log)).to eq(9) expect(get_subsections_count(empty_case_log)).to eq(10)
end end
it "returns 0 sections for completed sections if no sections are completed" do it "returns 0 sections for completed sections if no sections are completed" do
@ -30,7 +30,7 @@ RSpec.describe TasklistHelper do
end end
it "returns the number of not started sections" do it "returns the number of not started sections" do
expect(get_subsections_count(empty_case_log, :not_started)).to eq(8) expect(get_subsections_count(empty_case_log, :not_started)).to eq(9)
end end
it "returns the number of sections in progress" do it "returns the number of sections in progress" do

26
spec/models/form/question_spec.rb

@ -156,4 +156,30 @@ RSpec.describe Form::Question, type: :model do
end end
end end
end end
describe ".completed?" do
context "when the question has inferred value only for check answers display" do
let(:section_id) { "tenancy_and_property" }
let(:subsection_id) { "property_information" }
let(:page_id) { "property_postcode" }
let(:question_id) { "property_postcode" }
it "returns true" do
case_log["postcode_known"] = "No"
expect(question.completed?(case_log)).to be(true)
end
end
context "when the gdpr acceptance is No" do
let(:section_id) { "setup" }
let(:subsection_id) { "setup" }
let(:page_id) { "gdpr_acceptance" }
let(:question_id) { "gdpr_acceptance" }
it "returns false" do
case_log["gdpr_acceptance"] = "No"
expect(question.completed?(case_log)).to be(false)
end
end
end
end end

9
spec/models/form_spec.rb

@ -36,7 +36,7 @@ RSpec.describe Form, type: :model do
describe "next_incomplete_section_redirect_path" do describe "next_incomplete_section_redirect_path" do
let(:case_log) { FactoryBot.build(:case_log, :in_progress) } let(:case_log) { FactoryBot.build(:case_log, :in_progress) }
let(:subsection) { form.get_subsection("household_characteristics") } let(:subsection) { form.get_subsection("household_characteristics") }
let(:later_subsection) { form.get_subsection("local_authority") } let(:later_subsection) { form.get_subsection("setup") }
context "when a user is on the check answers page for a subsection" do context "when a user is on the check answers page for a subsection" do
def answer_household_needs(case_log) def answer_household_needs(case_log)
@ -85,6 +85,10 @@ RSpec.describe Form, type: :model do
case_log.mrcdate = Time.zone.parse("03/11/2019") case_log.mrcdate = Time.zone.parse("03/11/2019")
end end
def answer_local_gdpr_acceptance(case_log)
case_log.gdpr_acceptance = "Yes"
end
before do before do
case_log.tenant_code = "123" case_log.tenant_code = "123"
case_log.age1 = 35 case_log.age1 = 35
@ -108,7 +112,7 @@ RSpec.describe Form, type: :model do
end end
it "returns the next incomplete section by cycling back around if next subsections are completed" do it "returns the next incomplete section by cycling back around if next subsections are completed" do
answer_local_authority(case_log) answer_local_gdpr_acceptance(case_log)
expect(form.next_incomplete_section_redirect_path(later_subsection, case_log)).to eq("armed-forces") expect(form.next_incomplete_section_redirect_path(later_subsection, case_log)).to eq("armed-forces")
end end
@ -124,6 +128,7 @@ RSpec.describe Form, type: :model do
answer_income_and_benefits(case_log) answer_income_and_benefits(case_log)
answer_rent_and_charges(case_log) answer_rent_and_charges(case_log)
answer_local_authority(case_log) answer_local_authority(case_log)
answer_local_gdpr_acceptance(case_log)
expect(form.next_incomplete_section_redirect_path(subsection, case_log)).to eq("declaration") expect(form.next_incomplete_section_redirect_path(subsection, case_log)).to eq("declaration")
end end

4
spec/requests/case_logs_controller_spec.rb

@ -200,7 +200,7 @@ RSpec.describe CaseLogsController, type: :request do
end end
it "displays a section status for a case log" do it "displays a section status for a case log" do
assert_select ".govuk-tag", text: /Not started/, count: 8 assert_select ".govuk-tag", text: /Not started/, count: 9
assert_select ".govuk-tag", text: /Completed/, count: 0 assert_select ".govuk-tag", text: /Completed/, count: 0
assert_select ".govuk-tag", text: /Cannot start yet/, count: 1 assert_select ".govuk-tag", text: /Cannot start yet/, count: 1
end end
@ -222,7 +222,7 @@ RSpec.describe CaseLogsController, type: :request do
end end
it "displays a section status for a case log" do it "displays a section status for a case log" do
assert_select ".govuk-tag", text: /Not started/, count: 7 assert_select ".govuk-tag", text: /Not started/, count: 8
assert_select ".govuk-tag", text: /Completed/, count: 1 assert_select ".govuk-tag", text: /Completed/, count: 1
assert_select ".govuk-tag", text: /Cannot start yet/, count: 1 assert_select ".govuk-tag", text: /Cannot start yet/, count: 1
end end

Loading…
Cancel
Save