From 389667a8c8618f0440ae3b5a6eef8c8b05041be7 Mon Sep 17 00:00:00 2001 From: Leonid Brujev Date: Thu, 29 Aug 2024 14:48:19 +0100 Subject: [PATCH 1/5] [RUBY-3142] make PFC requirement optional for some project types --- .../pafs_core/project_summary_presenter.rb | 26 +++++--- .../pafs_core/validation_presenter.rb | 2 + lib/pafs_core/project_types.rb | 3 + .../project_summary_presenter_spec.rb | 16 +++++ .../pafs_core/validation_presenter_spec.rb | 61 ++++++++++++------- 5 files changed, 76 insertions(+), 32 deletions(-) diff --git a/app/presenters/pafs_core/project_summary_presenter.rb b/app/presenters/pafs_core/project_summary_presenter.rb index bbeb9b4c..9f99fca2 100644 --- a/app/presenters/pafs_core/project_summary_presenter.rb +++ b/app/presenters/pafs_core/project_summary_presenter.rb @@ -307,15 +307,19 @@ def summary_label(id) end def articles - if project_protects_households? - if risks_started? - all_articles - else - all_articles - [:standard_of_protection] - end - else - all_articles - %i[risks standard_of_protection] - end + articles = if project_protects_households? + if risks_started? + all_articles + else + all_articles - [:standard_of_protection] + end + else + all_articles - %i[risks standard_of_protection] + end + + articles -= %i[funding_calculator] unless pfc_required? + + articles end def not_provided @@ -342,6 +346,10 @@ def kilometres_created_or_enhanced(attribute:, applicable: false) "#{send(attribute)} kilometres" end + def pfc_required? + PROJECT_TYPES_REQUIRE_PFC.include?(project.project_type) + end + private def project diff --git a/app/presenters/pafs_core/validation_presenter.rb b/app/presenters/pafs_core/validation_presenter.rb index b074552d..6b9043c6 100644 --- a/app/presenters/pafs_core/validation_presenter.rb +++ b/app/presenters/pafs_core/validation_presenter.rb @@ -399,6 +399,8 @@ def urgency_complete? end def funding_calculator_complete? + return true if project_type.present? && !pfc_required? + if funding_calculator_file_name.blank? return add_error(:funding_calculator, "Upload the project's partnership funding calculator") end diff --git a/lib/pafs_core/project_types.rb b/lib/pafs_core/project_types.rb index a2304698..399f7a3b 100644 --- a/lib/pafs_core/project_types.rb +++ b/lib/pafs_core/project_types.rb @@ -9,4 +9,7 @@ module PafsCore # STR - strategies # ENV - environmental projects (not SSSI or BAP) PROJECT_TYPES = %w[DEF CM PLP STR ENV_WITH_HOUSEHOLDS ENV_WITHOUT_HOUSEHOLDS].freeze + + # Project types that require a Project Funding Calculator to be provided + PROJECT_TYPES_REQUIRE_PFC = %w[DEF CM].freeze end diff --git a/spec/presenters/pafs_core/project_summary_presenter_spec.rb b/spec/presenters/pafs_core/project_summary_presenter_spec.rb index f4fbbaaf..d1db3969 100644 --- a/spec/presenters/pafs_core/project_summary_presenter_spec.rb +++ b/spec/presenters/pafs_core/project_summary_presenter_spec.rb @@ -707,4 +707,20 @@ def make_coastal_outcome(year, project_id) financial_year: year, project_id: project_id) end + + describe "#pfc_required?" do + context "when project type is DEF or CM" do + it "returns true" do + subject.project_type = "DEF" + expect(subject.pfc_required?).to be true + end + end + + context "when project type is not DEF or CM" do + it "returns false" do + subject.project_type = "PLP" + expect(subject.pfc_required?).to be false + end + end + end end diff --git a/spec/presenters/pafs_core/validation_presenter_spec.rb b/spec/presenters/pafs_core/validation_presenter_spec.rb index 022bc2d3..37c7749c 100644 --- a/spec/presenters/pafs_core/validation_presenter_spec.rb +++ b/spec/presenters/pafs_core/validation_presenter_spec.rb @@ -363,41 +363,56 @@ describe "#funding_calculator_complete?" do subject { described_class.new(project) } - let(:project) { create(:full_project) } + let(:project_type) { "DEF" } + let(:project) { create(:full_project, project_type: project_type) } - context "with no PFC attached" do - it_behaves_like "failed validation example", :funding_calculator_complete? - end - - context "with a PFC attached" do - before do - file_path = Rails.root.join("..", "fixtures", "calculators", filename) - file = File.open file_path - storage = PafsCore::DevelopmentFileStorageService.new - dest_file = File.join(project.storage_path, filename) - storage.upload(file, dest_file) - project.funding_calculator_file_name = filename - end - - context "with a v8 PFC attached" do - let(:filename) { "v8.xlsx" } + context "when project type is not DEF or CM" do + let(:project_type) { "PLP" } + context "with no PFC attached" do it "returns true" do expect(subject.funding_calculator_complete?).to be true end end + end - context "with a 2020 v1 PFC attached" do - let(:filename) { "v9old.xlsx" } + context "when project type is DEF or CM" do + let(:project_type) { "DEF" } + context "with no PFC attached" do it_behaves_like "failed validation example", :funding_calculator_complete? end - context "with a 2020 v2 PFC attached" do - let(:filename) { "v9.xlsx" } + context "with a PFC attached" do + before do + file_path = Rails.root.join("..", "fixtures", "calculators", filename) + file = File.open file_path + storage = PafsCore::DevelopmentFileStorageService.new + dest_file = File.join(project.storage_path, filename) + storage.upload(file, dest_file) + project.funding_calculator_file_name = filename + end - it "returns true" do - expect(subject.funding_calculator_complete?).to be true + context "with a v8 PFC attached" do + let(:filename) { "v8.xlsx" } + + it "returns true" do + expect(subject.funding_calculator_complete?).to be true + end + end + + context "with a 2020 v1 PFC attached" do + let(:filename) { "v9old.xlsx" } + + it_behaves_like "failed validation example", :funding_calculator_complete? + end + + context "with a 2020 v2 PFC attached" do + let(:filename) { "v9.xlsx" } + + it "returns true" do + expect(subject.funding_calculator_complete?).to be true + end end end end From 709ffa4f237f5841848bbe186e2dbe6189e6a6aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:20:46 +0100 Subject: [PATCH 2/5] Bump rexml from 3.3.5 to 3.3.6 (#896) Bumps [rexml](https://github.com/ruby/rexml) from 3.3.5 to 3.3.6. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.3.5...v3.3.6) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index fd9c7128..c3c29aa4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -366,7 +366,7 @@ GEM regexp_parser (2.9.2) reline (0.5.9) io-console (~> 0.5) - rexml (3.3.5) + rexml (3.3.6) strscan roo (2.10.1) nokogiri (~> 1) From c8c8efbb2163b2a7b7a3517edf1bcc92bc1c2137 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:21:10 +0100 Subject: [PATCH 3/5] Bump faraday from 2.10.1 to 2.11.0 (#898) Bumps [faraday](https://github.com/lostisland/faraday) from 2.10.1 to 2.11.0. - [Release notes](https://github.com/lostisland/faraday/releases) - [Changelog](https://github.com/lostisland/faraday/blob/main/CHANGELOG.md) - [Commits](https://github.com/lostisland/faraday/compare/v2.10.1...v2.11.0) --- updated-dependencies: - dependency-name: faraday dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c3c29aa4..6f25c4ed 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -200,12 +200,12 @@ GEM railties (>= 5.0.0) faker (3.4.2) i18n (>= 1.8.11, < 2) - faraday (2.10.1) - faraday-net_http (>= 2.0, < 3.2) + faraday (2.11.0) + faraday-net_http (>= 2.0, < 3.4) logger faraday-http-cache (2.5.1) faraday (>= 0.8) - faraday-net_http (3.1.1) + faraday-net_http (3.3.0) net-http faraday-retry (2.2.1) faraday (~> 2.0) From 2db8d675a5ea56e9737e6adc76c9d41a4e2d7beb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:21:34 +0100 Subject: [PATCH 4/5] Bump rubocop-rails from 2.25.1 to 2.26.0 (#899) Bumps [rubocop-rails](https://github.com/rubocop/rubocop-rails) from 2.25.1 to 2.26.0. - [Release notes](https://github.com/rubocop/rubocop-rails/releases) - [Changelog](https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop/rubocop-rails/compare/v2.25.1...v2.26.0) --- updated-dependencies: - dependency-name: rubocop-rails dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6f25c4ed..b1beb54c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -405,10 +405,10 @@ GEM rubocop (~> 1.41) rubocop-factory_bot (2.26.1) rubocop (~> 1.61) - rubocop-rails (2.25.1) + rubocop-rails (2.26.0) activesupport (>= 4.2.0) rack (>= 1.1) - rubocop (>= 1.33.0, < 2.0) + rubocop (>= 1.52.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) rubocop-rake (0.6.0) rubocop (~> 1.0) From 6e93e313c2d8912e72b668784eee42063292099f Mon Sep 17 00:00:00 2001 From: Jerome Pratt Date: Wed, 4 Sep 2024 11:54:19 +0100 Subject: [PATCH 5/5] [RUBY-3220] Add validation for project name format (#902) * [RUBY-3220] Add format validation for project name and update tests - Add regex format validation to `name` attribute in `ProjectNameStep` to ensure it only contains letters, underscores, hyphens, and numbers. - Update project factory to remove periods from generated project names. - Enhance `ProjectNameStep` spec to test valid and invalid name formats, ensuring proper validation messages are displayed. * [RUBY-3220] Add conditional validation for project name and refactor tests - Updated `project_name_step.rb` to include a conditional validation for `name` presence. - Refactored `project_name_step_spec.rb` to improve readability and organization. - Grouped test cases logically and used more descriptive variable names. * [RUBY-3220] Add back shared example to `project_name_step_spec.rb` --- app/steps/pafs_core/project_name_step.rb | 5 ++ spec/factories/projects.rb | 2 +- .../steps/pafs_core/project_name_step_spec.rb | 50 +++++++++++++------ 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/app/steps/pafs_core/project_name_step.rb b/app/steps/pafs_core/project_name_step.rb index 3a40e67a..abf3ab41 100644 --- a/app/steps/pafs_core/project_name_step.rb +++ b/app/steps/pafs_core/project_name_step.rb @@ -6,6 +6,11 @@ class ProjectNameStep < BasicStep validates :name, presence: { message: "Tell us the project name" } + validates :name, format: { + with: /\A[A-Za-z0-9 _-]+\z/, + message: "The project name must only contain letters, underscores, hyphens and numbers" + }, if: -> { name.present? } + private def step_params(params) diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 2835bac5..7ea19aeb 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -5,7 +5,7 @@ FactoryBot.define do factory :project, class: "PafsCore::Project" do reference_number { PafsCore::ProjectService.generate_reference_number("TH") } - name { Faker::Lorem.sentence } + name { Faker::Lorem.sentence.remove(".") } version { 0 } created_at { 1.day.ago } updated_at { 1.day.ago } diff --git a/spec/steps/pafs_core/project_name_step_spec.rb b/spec/steps/pafs_core/project_name_step_spec.rb index 7bc54c1e..693ca0f3 100644 --- a/spec/steps/pafs_core/project_name_step_spec.rb +++ b/spec/steps/pafs_core/project_name_step_spec.rb @@ -3,28 +3,46 @@ require "rails_helper" RSpec.describe PafsCore::ProjectNameStep, type: :model do - describe "attributes" do - subject { build(:project_name_step) } - - it_behaves_like "a project step" + describe "#update" do + subject(:project_name_step) { create(:project_name_step) } - it { is_expected.to validate_presence_of(:name).with_message("Tell us the project name") } - end + let(:valid_params) { ActionController::Parameters.new({ project_name_step: { name: "Wigwam waste water" } }) } + let(:blank_name_params) { ActionController::Parameters.new({ project_name_step: { name: nil } }) } + let(:error_message) { "The project name must only contain letters, underscores, hyphens and numbers" } - describe "#update" do - subject { create(:project_name_step) } + it_behaves_like "a project step" - let(:params) { ActionController::Parameters.new({ project_name_step: { name: "Wigwam waste water" } }) } - let(:error_params) { ActionController::Parameters.new({ project_name_step: { name: nil } }) } + context "when name is valid" do + it "returns true and saves the name" do + expect(project_name_step.name).not_to eq "Wigwam waste water" + expect(project_name_step.update(valid_params)).to be true + expect(project_name_step.name).to eq "Wigwam waste water" + end + end - it "saves the :name when valid" do - expect(subject.name).not_to eq "Wigwam waste water" - expect(subject.update(params)).to be true - expect(subject.name).to eq "Wigwam waste water" + context "when name is blank" do + it "returns false and sets the correct error message" do + expect(project_name_step.update(blank_name_params)).to be false + expect(project_name_step.errors[:name].first).to eq("Tell us the project name") + end end - it "returns false when validation fails" do - expect(subject.update(error_params)).to be false + context "when name has an invalid format" do + invalid_names = { + "slash" => "Invalid/Name", + "backslash" => "Invalid\\Name", + "ampersand" => "Invalid&Name", + "at symbol" => "Invalid@Name", + "hash symbol" => "Invalid#Name" + } + + invalid_names.each do |description, name| + it "returns false and sets the correct error message for #{description} character" do + project_name_step.name = name + expect(project_name_step).not_to be_valid + expect(project_name_step.errors[:name].first).to eq(error_message) + end + end end end end