diff --git a/app/models/custom/verification/residence.rb b/app/models/custom/verification/residence.rb deleted file mode 100644 index 598c71c38..000000000 --- a/app/models/custom/verification/residence.rb +++ /dev/null @@ -1,26 +0,0 @@ -require_dependency Rails.root.join("app", "models", "verification", "residence").to_s - -class Verification::Residence - validate :local_postal_code - validate :local_residence - - def local_postal_code - errors.add(:postal_code, I18n.t("verification.residence.new.error_not_allowed_postal_code")) unless valid_postal_code? - end - - def local_residence - return if errors.any? - - unless residency_valid? - errors.add(:local_residence, false) - store_failed_attempt - Lock.increase_tries(user) - end - end - - private - - def valid_postal_code? - postal_code =~ /^280/ - end -end diff --git a/app/models/setting.rb b/app/models/setting.rb index 7fe170e33..a35d8b6c2 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -177,6 +177,7 @@ class Setting < ApplicationRecord "machine_learning.comments_summary": false, "machine_learning.related_content": false, "machine_learning.tags": false, + "postal_codes": "", "remote_census.general.endpoint": "", "remote_census.request.method_name": "", "remote_census.request.structure": "", diff --git a/app/models/verification/residence.rb b/app/models/verification/residence.rb index 9ca30b72c..539c3ef12 100644 --- a/app/models/verification/residence.rb +++ b/app/models/verification/residence.rb @@ -5,18 +5,18 @@ class Verification::Residence attr_accessor :user, :document_number, :document_type, :date_of_birth, :postal_code, :terms_of_service - before_validation :retrieve_census_data - validates :document_number, presence: true validates :document_type, presence: true validates :date_of_birth, presence: true validates :postal_code, presence: true validates :terms_of_service, acceptance: { allow_nil: false } - validates :postal_code, length: { is: 5 } validate :allowed_age validate :document_number_uniqueness + validate :local_postal_code + validate :local_residence + def initialize(attrs = {}) self.date_of_birth = parse_date("date_of_birth", attrs) attrs = remove_date("date_of_birth", attrs) @@ -66,26 +66,52 @@ class Verification::Residence end def district_code - @census_data.district_code + census_data.district_code end def gender - @census_data.gender + census_data.gender + end + + def local_postal_code + errors.add(:postal_code, I18n.t("verification.residence.new.error_not_allowed_postal_code")) unless valid_postal_code? + end + + def local_residence + return if errors.any? + + unless residency_valid? + errors.add(:local_residence, false) + store_failed_attempt + Lock.increase_tries(user) + end end private - def retrieve_census_data - @census_data = CensusCaller.new.call(document_type, document_number, date_of_birth, postal_code) + def census_data + @census_data ||= CensusCaller.new.call(document_type, document_number, date_of_birth, postal_code) end def residency_valid? - @census_data.valid? && - @census_data.postal_code == postal_code && - @census_data.date_of_birth == date_of_birth + census_data.valid? && + census_data.postal_code == postal_code && + census_data.date_of_birth == date_of_birth end def clean_document_number self.document_number = document_number.gsub(/[^a-z0-9]+/i, "").upcase if document_number.present? end + + def valid_postal_code? + return true if Setting["postal_codes"].blank? + + Setting["postal_codes"].split(",").any? do |code_or_range| + if code_or_range.include?(":") + Range.new(*code_or_range.split(":").map(&:strip)).include?(postal_code&.strip) + else + /\A#{code_or_range.strip}\Z/.match?(postal_code&.strip) + end + end + end end diff --git a/config/locales/en/settings.yml b/config/locales/en/settings.yml index 24679d5a0..fa9287be3 100644 --- a/config/locales/en/settings.yml +++ b/config/locales/en/settings.yml @@ -60,6 +60,8 @@ en: meta_keywords_description: 'Keywords , used to improve SEO' min_age_to_participate: Minimum age needed to participate min_age_to_participate_description: "Users over this age can participate in all processes where a user verified account is needed" + postal_codes: "Postal Codes" + postal_codes_description: "A comma-separated list of valid postal codes; you can also introduce ranges separated with a colon. Example: 00001:00010,00024,AB3 45FG,00031:00035 will allow postal codes between 00001 and 00010, the postal code 00024, the postal code AB3 45FG, and postal codes between 00031 and 00035. If you leave it blank, all postal codes will be valid." proposals: successful_proposal_id: Successful proposal successful_proposal_id_description: This proposal is used as a reference for a successful proposal in supports number and will be displayed in the dashboard graph. diff --git a/config/locales/en/verification.yml b/config/locales/en/verification.yml index cd0201d63..e1bdb2883 100644 --- a/config/locales/en/verification.yml +++ b/config/locales/en/verification.yml @@ -55,7 +55,7 @@ en: residence_card: Residence card spanish_id: DNI error_not_allowed_age: You don't have the required age to participate - error_not_allowed_postal_code: In order to be verified, you must be registered. + error_not_allowed_postal_code: Citizens from this postal code cannot participate error_verifying_census: The Census was unable to verify your information. Please confirm that your census details are correct by calling to City Council or visit one Citizen Support Office. form_errors: prevented the verification of your residence postal_code_note: To verify your account you must be registered diff --git a/config/locales/es/settings.yml b/config/locales/es/settings.yml index 820aa25f8..146213632 100644 --- a/config/locales/es/settings.yml +++ b/config/locales/es/settings.yml @@ -60,6 +60,8 @@ es: meta_keywords_description: 'Palabras clave , utilizadas para mejorar el SEO' min_age_to_participate: Edad mínima para participar min_age_to_participate_description: "Los usuarios mayores de esta edad podrán participar en todos los procesos donde se necesite una cuenta verificada" + postal_codes: "Códigos Postales" + postal_codes_description: "Una lista de códigos postales válidos separados por comas; también puedes usar rangos utilizando \":\". Ejemplo: 00001:00010,00024,AB3 45FG,00031:00035 permitirá códigos postales entre 00001 y 00010, el 00024, el AB3 45FG, y códigos postales entre 00031 y 00035. Si dejas esta opción en blanco, cualquier código postal será válido." proposals: successful_proposal_id: Propuesta exitosa successful_proposal_id_description: Esta propuesta se utiliza como referencia de una propuesta exitosa en número de apoyos y se mostrará en el gráfico del panel de control diff --git a/config/locales/es/verification.yml b/config/locales/es/verification.yml index 55123724d..c3191438b 100644 --- a/config/locales/es/verification.yml +++ b/config/locales/es/verification.yml @@ -55,7 +55,7 @@ es: residence_card: Tarjeta de residencia spanish_id: DNI error_not_allowed_age: No tienes la edad mínima para participar - error_not_allowed_postal_code: Para verificarte debes estar empadronado. + error_not_allowed_postal_code: Los ciudadanos residentes en este código postal no pueden participar error_verifying_census: El Padrón no pudo verificar tu información. Por favor, confirma que tus datos de empadronamiento sean correctos llamando al Ayuntamiento o visitando una Oficina de Atención al Ciudadano. form_errors: evitaron verificar tu residencia postal_code_note: Para verificar tus datos debes estar empadronado diff --git a/spec/models/custom/verification/residence_spec.rb b/spec/models/custom/verification/residence_spec.rb deleted file mode 100644 index 493e60b91..000000000 --- a/spec/models/custom/verification/residence_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require "rails_helper" - -describe Verification::Residence do - let(:residence) { build(:verification_residence, document_number: "12345678Z") } - - describe "verification" do - describe "postal code" do - it "is valid with postal codes starting with 280" do - residence.postal_code = "28012" - residence.valid? - expect(residence.errors[:postal_code]).to be_empty - - residence.postal_code = "28023" - residence.valid? - expect(residence.errors[:postal_code]).to be_empty - end - - it "is not valid with postal codes not starting with 280" do - residence.postal_code = "12345" - residence.valid? - expect(residence.errors[:postal_code].size).to eq(1) - - residence.postal_code = "13280" - residence.valid? - expect(residence.errors[:postal_code]).to eq ["In order to be verified, you must be registered."] - end - end - end -end diff --git a/spec/models/verification/residence_spec.rb b/spec/models/verification/residence_spec.rb index f34becd1f..e9733c7d7 100644 --- a/spec/models/verification/residence_spec.rb +++ b/spec/models/verification/residence_spec.rb @@ -46,6 +46,174 @@ describe Verification::Residence do residence.terms_of_service = nil expect(residence).not_to be_valid end + + describe "postal code" do + before do + Setting["postal_codes"] = "28001:28100,28200,28303-455" + + census_data = double(valid?: true, district_code: "", gender: "") + allow(census_data).to receive(:postal_code) { residence.postal_code } + allow(census_data).to receive(:date_of_birth) { residence.date_of_birth } + allow(residence).to receive(:census_data).and_return(census_data) + end + + it "is not valid when it's nil" do + residence.postal_code = nil + + expect(residence).not_to be_valid + end + + it "is valid with postal codes included in settings" do + residence.postal_code = "28012" + expect(residence).to be_valid + + residence.postal_code = "28001" + expect(residence).to be_valid + + residence.postal_code = "28100" + expect(residence).to be_valid + + residence.postal_code = "28200" + expect(residence).to be_valid + + residence.postal_code = "28303-455" + expect(residence).to be_valid + end + + it "uses string ranges and not integer ranges" do + Setting["postal_codes"] = "0000-9999" + + residence.postal_code = "02004" + + expect(residence).not_to be_valid + end + + it "accepts postal codes of any length" do + Setting["postal_codes"] = "AB1 3NE,815C,38000" + + residence.postal_code = "AB1 3NE" + expect(residence).to be_valid + + residence.postal_code = "815C" + expect(residence).to be_valid + + residence.postal_code = "38000" + expect(residence).to be_valid + + residence.postal_code = "815" + expect(residence).not_to be_valid + end + + it "does not ignore spaces inside the postal code" do + Setting["postal_codes"] = "00001,000 05,00011" + + residence.postal_code = "000 05" + expect(residence).to be_valid + + residence.postal_code = "00005" + expect(residence).not_to be_valid + end + + it "ignores trailing spaces in both the setting and the postal codes" do + Setting["postal_codes"] = " 00001,00002: 00005, 00011 " + + residence.postal_code = " 00003 " + + expect(residence).to be_valid + + residence.postal_code = "00011 " + + expect(residence).to be_valid + end + + it "allows regular expressions" do + Setting["postal_codes"] = "007,[A-Za-z]{2}-[0-9]{3},86" + + residence.postal_code = "007" + expect(residence).to be_valid + + residence.postal_code = "86" + expect(residence).to be_valid + + residence.postal_code = "AB-123" + expect(residence).to be_valid + + residence.postal_code = "zz-789" + expect(residence).to be_valid + + residence.postal_code = "006" + expect(residence).not_to be_valid + + residence.postal_code = "87" + expect(residence).not_to be_valid + + residence.postal_code = "AB-12" + expect(residence).not_to be_valid + + residence.postal_code = "AB-1234" + expect(residence).not_to be_valid + + residence.postal_code = "A-123" + expect(residence).not_to be_valid + + residence.postal_code = "ABC-123" + expect(residence).not_to be_valid + + residence.postal_code = "ABC-12" + expect(residence).not_to be_valid + + residence.postal_code = "AB-A12" + expect(residence).not_to be_valid + + residence.postal_code = "12A-12" + expect(residence).not_to be_valid + + residence.postal_code = "123-12" + expect(residence).not_to be_valid + + residence.postal_code = "ABC-A1" + expect(residence).not_to be_valid + + residence.postal_code = "AB-123\n123" + expect(residence).not_to be_valid + end + + it "is not valid with postal codes not included in settings" do + residence.postal_code = "12345" + expect(residence).not_to be_valid + + residence.postal_code = "28000" + expect(residence).not_to be_valid + + residence.postal_code = "28303-454" + expect(residence).not_to be_valid + + residence.postal_code = "28303" + expect(residence).not_to be_valid + + residence.postal_code = "28101" + expect(residence).not_to be_valid + expect(residence.errors.count).to eq 1 + expect(residence.errors[:postal_code]).to eq ["Citizens from this postal code cannot participate"] + end + + it "allows any postal code when the setting is blank" do + Setting["postal_codes"] = nil + residence.postal_code = "randomthing" + + expect(residence).to be_valid + + Setting["postal_codes"] = "" + residence.postal_code = "ABC123" + + expect(residence).to be_valid + + Setting["postal_codes"] = " " + residence.postal_code = "555-5" + + expect(residence).to be_valid + end + end end describe "new" do diff --git a/spec/system/verification/residence_spec.rb b/spec/system/verification/residence_spec.rb index 7b72e5523..285cd9d71 100644 --- a/spec/system/verification/residence_spec.rb +++ b/spec/system/verification/residence_spec.rb @@ -91,6 +91,7 @@ describe "Residence" do end scenario "Error on postal code not in census" do + Setting["postal_codes"] = "00001:99999" user = create(:user) login_as(user) @@ -102,12 +103,12 @@ describe "Residence" do select "1997", from: "residence_date_of_birth_1i" select "January", from: "residence_date_of_birth_2i" select "1", from: "residence_date_of_birth_3i" - fill_in "residence_postal_code", with: "12345" + fill_in "residence_postal_code", with: "00000" check "residence_terms_of_service" click_button "Verify residence" - expect(page).to have_content "In order to be verified, you must be registered" + expect(page).to have_content "Citizens from this postal code cannot participate" end scenario "Error on census" do