diff --git a/.env.example b/.env.example index d30382d9e..94596a0da 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,2 @@ DB_USERNAME=postgres-user DB_PASSWORD=postgres-password -CORE_EMAIL_USERNAME=email@example.com -CORE_EMAIL_PASSWORD=password123 diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index c64e3d581..254cf36bc 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -100,14 +100,10 @@ jobs: API_USER: ${{ secrets.API_USER }} API_KEY: ${{ secrets.API_KEY }} APP_NAME: dluhc-core - CORE_EMAIL_USERNAME: ${{ secrets.CORE_EMAIL_USERNAME }} - CORE_EMAIL_PASSWORD: ${{ secrets.CORE_EMAIL_PASSWORD }} run: | cf7 api $CF_API_ENDPOINT cf7 auth cf7 target -o $CF_ORG -s $CF_SPACE cf7 set-env $APP_NAME API_USER $API_USER cf7 set-env $APP_NAME API_KEY $API_KEY - cf7 set-env $APP_NAME CORE_EMAIL_USERNAME $CORE_EMAIL_USERNAME - cf7 set-env $APP_NAME CORE_EMAIL_PASSWORD $CORE_EMAIL_PASSWORD cf7 push --strategy rolling diff --git a/Gemfile b/Gemfile index f2895387e..dcb8a18b3 100644 --- a/Gemfile +++ b/Gemfile @@ -33,10 +33,8 @@ gem "chartkick" gem "roo" # Json Schema gem "json-schema" -# Authentication -gem "devise" -gem "turbo-rails", "~> 0.8" gem "uk_postcode" +gem "turbo-rails", "~> 0.8" group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console diff --git a/Gemfile.lock b/Gemfile.lock index 322fcc403..cd5df20e9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -122,7 +122,6 @@ GEM activesupport (>= 3.0.0, < 6.2) ruby2_keywords (>= 0.0.2, < 1.0) ast (2.4.2) - bcrypt (3.1.16) bindex (0.8.1) bootsnap (1.9.1) msgpack (~> 1.0) @@ -147,12 +146,6 @@ GEM database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) deep_merge (1.2.1) - devise (4.8.0) - bcrypt (~> 3.0) - orm_adapter (~> 0.1) - railties (>= 4.1.0) - responders - warden (~> 1.2.3) diff-lcs (1.4.4) discard (1.2.0) activerecord (>= 4.2, < 7) @@ -234,7 +227,6 @@ GEM nio4r (2.5.8) nokogiri (1.12.5-x86_64-linux) racc (~> 1.4) - orm_adapter (0.5.0) overcommit (0.58.0) childprocess (>= 0.6.3, < 5) iniparse (~> 1.4) @@ -373,8 +365,6 @@ GEM view_component (2.39.0) activesupport (>= 5.0.0, < 8.0) method_source (~> 1.0) - warden (1.2.9) - rack (>= 2.0.9) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -403,7 +393,6 @@ DEPENDENCIES capybara chartkick database_cleaner-active_record - devise discard dotenv-rails factory_bot_rails diff --git a/app/admin/admin_users.rb b/app/admin/admin_users.rb deleted file mode 100644 index fed0ec1a8..000000000 --- a/app/admin/admin_users.rb +++ /dev/null @@ -1,27 +0,0 @@ -ActiveAdmin.register AdminUser do - permit_params :email, :password, :password_confirmation - - index do - selectable_column - id_column - column :email - column :current_sign_in_at - column :sign_in_count - column :created_at - actions - end - - filter :email - filter :current_sign_in_at - filter :sign_in_count - filter :created_at - - form do |f| - f.inputs do - f.input :email - f.input :password - f.input :password_confirmation - end - f.actions - end -end diff --git a/app/controllers/case_logs_controller.rb b/app/controllers/case_logs_controller.rb index 48e546236..68c8322bd 100644 --- a/app/controllers/case_logs_controller.rb +++ b/app/controllers/case_logs_controller.rb @@ -1,7 +1,6 @@ class CaseLogsController < ApplicationController skip_before_action :verify_authenticity_token, if: :json_api_request? before_action :authenticate, if: :json_api_request? - before_action :authenticate_user!, unless: :json_api_request? def index @completed_case_logs = CaseLog.completed @@ -57,15 +56,15 @@ class CaseLogsController < ApplicationController def submit_form form = FormHandler.instance.get_form("2021_2022") @case_log = CaseLog.find(params[:id]) - @case_log.page_id = params[:case_log][:page] - page = form.get_page(@case_log.page_id) - responses_for_page = responses_for_page(page) + @case_log.page = params[:case_log][:page] + responses_for_page = responses_for_page(@case_log.page) if @case_log.update(responses_for_page) && @case_log.has_no_unresolved_soft_errors? - redirect_path = form.next_page_redirect_path(page, @case_log) + redirect_path = form.next_page_redirect_path(@case_log.page, @case_log) redirect_to(send(redirect_path, @case_log)) else - subsection = form.subsection_for_page(page) - render "form/page", locals: { form: form, page: page, subsection: subsection.label }, status: :unprocessable_entity + page_info = form.all_pages[@case_log.page] + subsection = form.subsection_for_page(@case_log.page) + render "form/page", locals: { form: form, page_key: @case_log.page, page_info: page_info, subsection: subsection.humanize }, status: :unprocessable_entity end end @@ -85,16 +84,16 @@ class CaseLogsController < ApplicationController form = FormHandler.instance.get_form("2021_2022") @case_log = CaseLog.find(params[:case_log_id]) current_url = request.env["PATH_INFO"] - subsection = form.get_subsection(current_url.split("/")[-2]) + subsection = current_url.split("/")[-2] render "form/check_answers", locals: { subsection: subsection, form: form } end form = FormHandler.instance.get_form("2021_2022") - form.pages.map do |page| - define_method(page.id) do |_errors = {}| + form.all_pages.map do |page_key, page_info| + define_method(page_key) do |_errors = {}| @case_log = CaseLog.find(params[:case_log_id]) - subsection = form.subsection_for_page(page) - render "form/page", locals: { form: form, page: page, subsection: subsection.label } + subsection = form.subsection_for_page(page_key) + render "form/page", locals: { form: form, page_key: page_key, page_info: page_info, subsection: subsection.humanize } end end @@ -103,28 +102,29 @@ private API_ACTIONS = %w[create show update destroy].freeze def responses_for_page(page) - page.expected_responses.each_with_object({}) do |question, result| - question_params = params["case_log"][question.id] - if question.type == "date" - day = params["case_log"]["#{question.id}(3i)"] - month = params["case_log"]["#{question.id}(2i)"] - year = params["case_log"]["#{question.id}(1i)"] + form = FormHandler.instance.get_form("2021_2022") + form.expected_responses_for_page(page).each_with_object({}) do |(question_key, question_info), result| + question_params = params["case_log"][question_key] + if question_info["type"] == "date" + day = params["case_log"]["#{question_key}(3i)"] + month = params["case_log"]["#{question_key}(2i)"] + year = params["case_log"]["#{question_key}(1i)"] next unless [day, month, year].any?(&:present?) - result[question.id] = if day.to_i.between?(1, 31) && month.to_i.between?(1, 12) && year.to_i.between?(2000, 2200) - Date.new(year.to_i, month.to_i, day.to_i) - else - Date.new(0, 1, 1) - end + result[question_key] = if day.to_i.between?(1, 31) && month.to_i.between?(1, 12) && year.to_i.between?(2000, 2200) + Date.new(year.to_i, month.to_i, day.to_i) + else + Date.new(0, 1, 1) + end end next unless question_params - if %w[checkbox validation_override].include?(question.type) - question.answer_options.keys.reject { |x| x.match(/divider/) }.each do |option| + if %w[checkbox validation_override].include?(question_info["type"]) + question_info["answer_options"].keys.reject { |x| x.match(/divider/) }.each do |option| result[option] = question_params.include?(option) ? 1 : 0 end else - result[question.id] = question_params + result[question_key] = question_params end result end diff --git a/app/controllers/soft_validations_controller.rb b/app/controllers/soft_validations_controller.rb index 4f9881de6..ad28ea25e 100644 --- a/app/controllers/soft_validations_controller.rb +++ b/app/controllers/soft_validations_controller.rb @@ -1,9 +1,9 @@ class SoftValidationsController < ApplicationController def show @case_log = CaseLog.find(params[:case_log_id]) - page_id = request.env["PATH_INFO"].split("/")[-2] + page_key = request.env["PATH_INFO"].split("/")[-2] form = FormHandler.instance.get_form("2021_2022") - page = form.get_page(page_id) + page = form.all_pages[page_key] if page_requires_soft_validation_override?(page) errors = @case_log.soft_errors.values.first render json: { show: true, label: errors.message, hint: errors.hint_text } @@ -15,6 +15,6 @@ class SoftValidationsController < ApplicationController private def page_requires_soft_validation_override?(page) - @case_log.soft_errors.present? && @case_log.soft_errors.keys.first == page.soft_validations&.first&.id + @case_log.soft_errors.present? && @case_log.soft_errors.keys.first == page["soft_validations"]&.keys&.first end end diff --git a/app/controllers/users/passwords_controller.rb b/app/controllers/users/passwords_controller.rb deleted file mode 100644 index da3b39158..000000000 --- a/app/controllers/users/passwords_controller.rb +++ /dev/null @@ -1,20 +0,0 @@ -class Users::PasswordsController < Devise::PasswordsController - def reset_confirmation - @email = params["email"] - flash[:notice] = "Reset password instructions have been sent to #{@email}" - render "devise/confirmations/reset" - end - - def create - self.resource = resource_class.send_reset_password_instructions(resource_params) - yield resource if block_given? - - respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name)) - end - -protected - - def after_sending_reset_password_instructions_path_for(_resource) - confirmations_reset_path(email: params.dig("user", "email")) - end -end diff --git a/app/helpers/check_answers_helper.rb b/app/helpers/check_answers_helper.rb index ba0237f58..fed58b71e 100644 --- a/app/helpers/check_answers_helper.rb +++ b/app/helpers/check_answers_helper.rb @@ -1,20 +1,57 @@ module CheckAnswersHelper - def display_answered_questions_summary(subsection, case_log) - total = subsection.applicable_questions_count(case_log) - answered = subsection.answered_questions_count(case_log) - if total == answered - '

You answered all the questions

'.html_safe - else - "

You answered #{answered} of #{total} questions

- #{create_next_missing_question_link(subsection, case_log)}".html_safe + def total_answered_questions(subsection, case_log, form) + total_questions(subsection, case_log, form).keys.count do |question_key| + case_log[question_key].present? + end + end + + def total_number_of_questions(subsection, case_log, form) + total_questions(subsection, case_log, form).count + end + + def total_questions(subsection, case_log, form) + questions = form.questions_for_subsection(subsection) + form.filter_conditional_questions(questions, case_log) + end + + def get_next_page_name(form, page_name, case_log) + page = form.all_pages[page_name] + if page.key?("conditional_route_to") + page["conditional_route_to"].each do |conditional_page_name, condition| + unless condition.any? { |field, value| case_log[field].blank? || !value.include?(case_log[field]) } + return conditional_page_name + end + end end + form.next_page(page_name) end -private + def create_update_answer_link(question_title, question_info, case_log, form) + page = form.page_for_question(question_title) + link_name = if question_info["type"] == "checkbox" + question_info["answer_options"].keys.any? { |key| case_log[key] == "Yes" } ? "Change" : "Answer" + else + case_log[question_title].blank? ? "Answer" : "Change" + end + link_to(link_name, "/case_logs/#{case_log.id}/#{page}", class: "govuk-link").html_safe + end - def create_next_missing_question_link(subsection, case_log) - pages_to_fill_in = subsection.unanswered_questions(case_log).map(&:page) - url = "/case_logs/#{case_log.id}/#{pages_to_fill_in.first.id}" + def create_next_missing_question_link(case_log_id, subsection, case_log, form) + pages_to_fill_in = [] + form.pages_for_subsection(subsection).each do |page_title, page_info| + page_info["questions"].any? { |question| case_log[question].blank? } + pages_to_fill_in << page_title + end + url = "/case_logs/#{case_log_id}/#{pages_to_fill_in.first}" link_to("Answer the missing questions", url, class: "govuk-link").html_safe end + + def display_answered_questions_summary(subsection, case_log, form) + if total_answered_questions(subsection, case_log, form) == total_number_of_questions(subsection, case_log, form) + '

You answered all the questions

'.html_safe + else + "

You answered #{total_answered_questions(subsection, case_log, form)} of #{total_number_of_questions(subsection, case_log, form)} questions

+ #{create_next_missing_question_link(case_log['id'], subsection, case_log, form)}".html_safe + end + end end diff --git a/app/helpers/conditional_questions_helper.rb b/app/helpers/conditional_questions_helper.rb index ec9ccae60..c77119243 100644 --- a/app/helpers/conditional_questions_helper.rb +++ b/app/helpers/conditional_questions_helper.rb @@ -1,9 +1,11 @@ module ConditionalQuestionsHelper def conditional_questions_for_page(page) - page.questions.map(&:conditional_for).compact.map(&:keys).flatten + page["questions"].values.map { |question| + question["conditional_for"] + }.compact.map(&:keys).flatten end - def display_question_key_div(page, question) - "style='display:none;'".html_safe if conditional_questions_for_page(page).include?(question.id) + def display_question_key_div(page_info, question_key) + "style='display:none;'".html_safe if conditional_questions_for_page(page_info).include?(question_key) end end diff --git a/app/helpers/question_attribute_helper.rb b/app/helpers/question_attribute_helper.rb index d292239d8..1010591f0 100644 --- a/app/helpers/question_attribute_helper.rb +++ b/app/helpers/question_attribute_helper.rb @@ -10,23 +10,23 @@ module QuestionAttributeHelper private def numeric_question_html_attributes(question) - return {} if question.fields_to_add.blank? || question.result_field.blank? + return {} if question["fields-to-add"].blank? || question["result-field"].blank? { "data-controller": "numeric-question", "data-action": "numeric-question#calculateFields", - "data-target": "case-log-#{question.result_field.to_s.dasherize}-field", - "data-calculated": question.fields_to_add.to_json, + "data-target": "case-log-#{question['result-field'].to_s.dasherize}-field", + "data-calculated": question["fields-to-add"].to_json, } end def conditional_html_attributes(question) - return {} if question.conditional_for.blank? + return {} if question["conditional_for"].blank? { "data-controller": "conditional-question", "data-action": "conditional-question#displayConditional", - "data-info": question.conditional_for.to_json, + "data-info": question["conditional_for"].to_json, } end end diff --git a/app/helpers/tasklist_helper.rb b/app/helpers/tasklist_helper.rb index d31257f25..1d3f376c5 100644 --- a/app/helpers/tasklist_helper.rb +++ b/app/helpers/tasklist_helper.rb @@ -13,31 +13,48 @@ module TasklistHelper in_progress: "govuk-tag--blue", }.freeze + def get_subsection_status(subsection_name, case_log, form, questions) + applicable_questions = form.filter_conditional_questions(questions, case_log).keys + if subsection_name == "declaration" + return case_log.completed? ? :not_started : :cannot_start_yet + end + + return :not_started if applicable_questions.all? { |question| case_log[question].blank? } + return :completed if applicable_questions.all? { |question| case_log[question].present? } + + :in_progress + end + def get_next_incomplete_section(form, case_log) - form.subsections.find { |subsection| subsection.is_incomplete?(case_log) } + subsections = form.all_subsections.keys + subsections.find { |subsection| is_incomplete?(subsection, case_log, form, form.questions_for_subsection(subsection)) } end def get_subsections_count(form, case_log, status = :all) - return form.subsections.count if status == :all + subsections = form.all_subsections.keys + return subsections.count if status == :all - form.subsections.count { |subsection| subsection.status(case_log) == status } + subsections.count { |subsection| get_subsection_status(subsection, case_log, form, form.questions_for_subsection(subsection)) == status } end - def first_page_or_check_answers(subsection, case_log) - path = if subsection.is_started?(case_log) - "case_log_#{subsection.id}_check_answers_path" + def get_first_page_or_check_answers(subsection, case_log, form, questions) + path = if is_started?(subsection, case_log, form, questions) + "case_log_#{subsection}_check_answers_path" else - "case_log_#{subsection.pages.first.id}_path" + "case_log_#{form.first_page_for_subsection(subsection)}_path" end send(path, case_log) end - def subsection_link(subsection, case_log) - next_page_path = if subsection.status(case_log) != :cannot_start_yet - first_page_or_check_answers(subsection, case_log) - else - "#" - end - link_to(subsection.label, next_page_path, class: "task-name govuk-link") +private + + def is_incomplete?(subsection, case_log, form, questions) + status = get_subsection_status(subsection, case_log, form, questions) + %i[not_started in_progress].include?(status) + end + + def is_started?(subsection, case_log, form, questions) + status = get_subsection_status(subsection, case_log, form, questions) + %i[in_progress completed].include?(status) end end diff --git a/app/models/admin_user.rb b/app/models/admin_user.rb deleted file mode 100644 index 14ea71789..000000000 --- a/app/models/admin_user.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AdminUser < ApplicationRecord - # Include default devise modules. Others available are: - # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable - devise :database_authenticatable, :recoverable, :rememberable, :validatable -end diff --git a/app/models/case_log.rb b/app/models/case_log.rb index 542a6997a..32bc40739 100644 --- a/app/models/case_log.rb +++ b/app/models/case_log.rb @@ -11,7 +11,7 @@ class CaseLogValidator < ActiveModel::Validator # If we've come from the form UI we only want to validate the specific fields # that have just been submitted. If we're submitting a log via API or Bulk Upload # we want to validate all data fields. - page_to_validate = record.page_id + page_to_validate = record.page if page_to_validate public_send("validate_#{page_to_validate}", record) if respond_to?("validate_#{page_to_validate}") else @@ -44,7 +44,7 @@ class CaseLog < ApplicationRecord validates_with CaseLogValidator before_save :update_status! - attr_accessor :page_id + attr_accessor :page enum status: { "not_started" => 0, "in_progress" => 1, "completed" => 2 } diff --git a/app/models/form.rb b/app/models/form.rb index 5dc85384c..34385af99 100644 --- a/app/models/form.rb +++ b/app/models/form.rb @@ -1,34 +1,75 @@ class Form - attr_reader :form_definition, :sections, :subsections, :pages, :questions + attr_reader :form_definition def initialize(form_path) raise "No form definition file exists for given year".freeze unless File.exist?(form_path) @form_definition = JSON.parse(File.open(form_path).read) - @sections = form_definition["sections"].map { |id, s| Form::Section.new(id, s, self) } - @subsections = sections.flat_map(&:subsections) - @pages = subsections.flat_map(&:pages) - @questions = pages.flat_map(&:questions) end - def get_subsection(id) - subsections.find { |s| s.id == id } + # Returns a hash with sections as keys + def all_sections + @all_sections ||= @form_definition["sections"] end - def get_page(id) - pages.find { |p| p.id == id } + # Returns a hash with subsections as keys + def all_subsections + @all_subsections ||= all_sections.map { |_section_key, section_value| + section_value["subsections"] + }.reduce(:merge) + end + + # Returns a hash with pages as keys + def all_pages + @all_pages ||= all_subsections.map { |_subsection_key, subsection_value| + subsection_value["pages"] + }.reduce(:merge) + end + + # Returns a hash with the pages of a subsection as keys + def pages_for_subsection(subsection) + all_subsections[subsection]["pages"] + end + + # Returns a hash with the questions as keys + def questions_for_page(page) + all_pages[page]["questions"] + end + + # Returns a hash with the questions as keys + def questions_for_subsection(subsection) + pages_for_subsection(subsection).map { |title, _value| questions_for_page(title) }.reduce(:merge) + end + + # Returns a hash with soft validation questions as keys + def soft_validations_for_page(page) + all_pages[page]["soft_validations"] + end + + def expected_responses_for_page(page) + questions_for_page(page).merge(soft_validations_for_page(page) || {}) + end + + def first_page_for_subsection(subsection) + pages_for_subsection(subsection).keys.first end def subsection_for_page(page) - subsections.find { |s| s.pages.find { |p| p.id == page.id } } + all_subsections.find { |_subsection_key, subsection_value| + subsection_value["pages"].key?(page) + }.first + end + + def page_for_question(question) + all_pages.find { |_page_key, page_value| page_value["questions"].key?(question) }.first end def next_page(page, case_log) - page_ids = subsection_for_page(page).pages.map(&:id) - page_index = page_ids.index(page.id) - nxt_page = get_page(page_ids[page_index + 1]) + subsection = subsection_for_page(page) + page_idx = pages_for_subsection(subsection).keys.index(page) + nxt_page = pages_for_subsection(subsection).keys[page_idx + 1] return :check_answers if nxt_page.nil? - return nxt_page.id if nxt_page.routed_to?(case_log) + return nxt_page if page_routed_to?(nxt_page, case_log) next_page(nxt_page, case_log) end @@ -36,16 +77,73 @@ class Form def next_page_redirect_path(page, case_log) nxt_page = next_page(page, case_log) if nxt_page == :check_answers - "case_log_#{subsection_for_page(page).id}_check_answers_path" + subsection = subsection_for_page(page) + "case_log_#{subsection}_check_answers_path" else "case_log_#{nxt_page}_path" end end - def conditional_question_conditions - conditions = questions.map { |q| Hash(q.id => q.conditional_for) if q.conditional_for.present? }.compact - conditions.map { |c| - c.map { |k, v| v.keys.map { |key| Hash(from: k, to: key, cond: v[key]) } } - }.flatten + def all_questions + @all_questions ||= all_pages.map { |_page_key, page_value| + page_value["questions"] + }.reduce(:merge) + end + + def filter_conditional_questions(questions, case_log) + applicable_questions = questions + + questions.each do |k, question| + unless page_routed_to?(page_for_question(k), case_log) + applicable_questions = applicable_questions.reject { |z| z == k } + end + + question.fetch("conditional_for", []).each do |conditional_question_key, condition| + if condition_not_met(case_log, k, question, condition) + applicable_questions = applicable_questions.reject { |z| z == conditional_question_key } + end + end + end + applicable_questions + end + + def page_routed_to?(page, case_log) + return true unless (conditions = page_dependencies(page)) + + conditions.all? do |question, value| + case_log[question].present? && case_log[question] == value + end + end + + def page_dependencies(page) + all_pages[page]["depends_on"] + end + + def condition_not_met(case_log, question_key, question, condition) + case question["type"] + when "numeric" + operator = condition[/[<>=]+/].to_sym + operand = condition[/\d+/].to_i + case_log[question_key].blank? || !case_log[question_key].send(operator, operand) + when "text" + case_log[question_key].blank? || !condition.include?(case_log[question_key]) + when "radio" + case_log[question_key].blank? || !condition.include?(case_log[question_key]) + when "select" + case_log[question_key].blank? || !condition.include?(case_log[question_key]) + else + raise "Not implemented yet" + end + end + + def get_answer_label(case_log, question_title) + question = all_questions[question_title] + if question["type"] == "checkbox" + answer = [] + question["answer_options"].each { |key, value| case_log[key] == "Yes" ? answer << value : nil } + return answer.join(", ") + end + + case_log[question_title] end end diff --git a/app/models/form/page.rb b/app/models/form/page.rb deleted file mode 100644 index 73a1ee143..000000000 --- a/app/models/form/page.rb +++ /dev/null @@ -1,30 +0,0 @@ -class Form::Page - attr_accessor :id, :header, :description, :questions, :soft_validations, - :depends_on, :subsection - - def initialize(id, hsh, subsection) - @id = id - @header = hsh["header"] - @description = hsh["description"] - @questions = hsh["questions"].map { |q_id, q| Form::Question.new(q_id, q, self) } - @depends_on = hsh["depends_on"] - @soft_validations = hsh["soft_validations"]&.map { |v_id, s| Form::Question.new(v_id, s, self) } - @subsection = subsection - end - - def expected_responses - questions + (soft_validations || []) - end - - def has_soft_validations? - soft_validations.present? - end - - def routed_to?(case_log) - return true unless depends_on - - depends_on.all? do |question, value| - case_log[question].present? && case_log[question] == value - end - end -end diff --git a/app/models/form/question.rb b/app/models/form/question.rb deleted file mode 100644 index 2362441c8..000000000 --- a/app/models/form/question.rb +++ /dev/null @@ -1,80 +0,0 @@ -class Form::Question - attr_accessor :id, :header, :hint_text, :description, :questions, - :type, :min, :max, :step, :fields_to_add, :result_field, - :conditional_for, :readonly, :answer_options, :page, :check_answer_label - - def initialize(id, hsh, page) - @id = id - @check_answer_label = hsh["check_answer_label"] - @header = hsh["header"] - @hint_text = hsh["hint_text"] - @type = hsh["type"] - @min = hsh["min"] - @max = hsh["max"] - @step = hsh["step"] - @fields_to_add = hsh["fields-to-add"] - @result_field = hsh["result-field"] - @readonly = hsh["readonly"] - @answer_options = hsh["answer_options"] - @conditional_for = hsh["conditional_for"] - @page = page - end - - delegate :subsection, to: :page - delegate :form, to: :subsection - - def answer_label(case_log) - return checkbox_answer_label(case_log) if type == "checkbox" - - case_log[id].to_s - end - - def read_only? - !!readonly - end - - def conditional_on - @conditional_on ||= form.conditional_question_conditions.select do |condition| - condition[:to] == id - end - end - - def enabled?(case_log) - return true if conditional_on.blank? - - conditional_on.map { |condition| evaluate_condition(condition, case_log) }.all? - end - - def update_answer_link_name(case_log) - if type == "checkbox" - answer_options.keys.any? { |key| case_log[key] == "Yes" } ? "Change" : "Answer" - else - case_log[id].blank? ? "Answer" : "Change" - end - end - -private - - def checkbox_answer_label(case_log) - answer = [] - answer_options.each { |key, value| case_log[key] == "Yes" ? answer << value : nil } - answer.join(", ") - end - - def evaluate_condition(condition, case_log) - case page.questions.find { |q| q.id == condition[:from] }.type - when "numeric" - operator = condition[:cond][/[<>=]+/].to_sym - operand = condition[:cond][/\d+/].to_i - case_log[condition[:from]].present? && case_log[condition[:from]].send(operator, operand) - when "text" - case_log[condition[:from]].present? && condition[:cond].include?(case_log[condition[:from]]) - when "radio" - case_log[condition[:from]].present? && condition[:cond].include?(case_log[condition[:from]]) - when "select" - case_log[condition[:from]].present? && condition[:cond].include?(case_log[condition[:from]]) - else - raise "Not implemented yet" - end - end -end diff --git a/app/models/form/section.rb b/app/models/form/section.rb deleted file mode 100644 index 477fc9f18..000000000 --- a/app/models/form/section.rb +++ /dev/null @@ -1,10 +0,0 @@ -class Form::Section - attr_accessor :id, :label, :subsections, :form - - def initialize(id, hsh, form) - @id = id - @label = hsh["label"] - @form = form - @subsections = hsh["subsections"].map { |s_id, s| Form::Subsection.new(s_id, s, self) } - end -end diff --git a/app/models/form/subsection.rb b/app/models/form/subsection.rb deleted file mode 100644 index 19700d935..000000000 --- a/app/models/form/subsection.rb +++ /dev/null @@ -1,65 +0,0 @@ -class Form::Subsection - attr_accessor :id, :label, :section, :pages, :depends_on, :form - - def initialize(id, hsh, section) - @id = id - @label = hsh["label"] - @depends_on = hsh["depends_on"] - @pages = hsh["pages"].map { |s_id, p| Form::Page.new(s_id, p, self) } - @section = section - end - - delegate :form, to: :section - - def questions - @questions ||= pages.flat_map(&:questions) - end - - def enabled?(case_log) - return true unless depends_on - - depends_on.all? do |subsection_id, dependent_status| - form.get_subsection(subsection_id).status(case_log) == dependent_status.to_sym - end - end - - def status(case_log) - unless enabled?(case_log) - return :cannot_start_yet - end - - qs = applicable_questions(case_log) - return :not_started if qs.all? { |question| case_log[question.id].blank? } - return :completed if qs.all? { |question| case_log[question.id].present? } - - :in_progress - end - - def is_incomplete?(case_log) - %i[not_started in_progress].include?(status(case_log)) - end - - def is_started?(case_log) - %i[in_progress completed].include?(status(case_log)) - end - - def applicable_questions_count(case_log) - applicable_questions(case_log).count - end - - def answered_questions_count(case_log) - answered_questions(case_log).count - end - - def applicable_questions(case_log) - questions.select { |q| q.page.routed_to?(case_log) && q.enabled?(case_log) } - end - - def answered_questions(case_log) - applicable_questions(case_log).select { |question| case_log[question.id].present? } - end - - def unanswered_questions(case_log) - applicable_questions(case_log) - answered_questions(case_log) - end -end diff --git a/app/models/user.rb b/app/models/user.rb deleted file mode 100644 index 0ef982f25..000000000 --- a/app/models/user.rb +++ /dev/null @@ -1,5 +0,0 @@ -class User < ApplicationRecord - # Include default devise modules. Others available are: - # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable - devise :database_authenticatable, :recoverable, :rememberable, :validatable -end diff --git a/app/validations/household_validations.rb b/app/validations/household_validations.rb index 6286f2884..5671b1b75 100644 --- a/app/validations/household_validations.rb +++ b/app/validations/household_validations.rb @@ -5,12 +5,12 @@ module HouseholdValidations if record.homeless == "No" && record.reasonpref == "Yes" record.errors.add :reasonpref, "Can not be Yes if Not Homeless immediately prior to this letting has been selected" elsif record.reasonpref == "Yes" - if [record.rp_homeless, record.rp_insan_unsat, record.rp_medwel, record.rp_hardship, record.rp_dontknow].none? { |a| a == "Yes" } - record.errors.add :reasonable_preference_reason, 'If reasonable preference is "Yes", a reason must be given' + if !record.rp_homeless && !record.rp_insan_unsat && !record.rp_medwel && !record.rp_hardship && !record.rp_dontknow + record.errors.add :reasonable_preference_reason, "If reasonable preference is Yes, a reason must be given" end elsif record.reasonpref == "No" - if [record.rp_homeless, record.rp_insan_unsat, record.rp_medwel, record.rp_hardship, record.rp_dontknow].any? { |a| a == "Yes" } - record.errors.add :reasonable_preference_reason, 'If reasonable preference is "No", no reasons should be given' + if record.rp_homeless || record.rp_insan_unsat || record.rp_medwel || record.rp_hardship || record.rp_dontknow + record.errors.add :reasonable_preference_reason, "If reasonable preference is No, no reasons should be given" end end end @@ -66,7 +66,7 @@ module HouseholdValidations return unless record.age1 if !record.age1.is_a?(Integer) || record.age1 < 16 || record.age1 > 120 - record.errors.add :age1, "Tenant age must be an integer between 16 and 120" + record.errors.add "age1", "Tenant age must be an integer between 16 and 120" end end diff --git a/app/views/case_logs/_tasklist.html.erb b/app/views/case_logs/_tasklist.html.erb index 87eb00a7b..1e75f207b 100644 --- a/app/views/case_logs/_tasklist.html.erb +++ b/app/views/case_logs/_tasklist.html.erb @@ -1,16 +1,18 @@
    - <% @form.sections.map do |section| %> + <% @form.all_sections.map do |section_key, section_value| %>
  1. - <%= section.label %> + <%= section_value["label"] %>