From 5d862ae92b81dcd34f4b240e2fa3afa9b240e073 Mon Sep 17 00:00:00 2001 From: Frederic Merizen Date: Thu, 11 Oct 2018 10:45:03 +0200 Subject: [PATCH 1/4] [#1961] Add individual fields --- app/models/procedure_presentation.rb | 8 +++ spec/models/procedure_presentation_spec.rb | 78 +++++++++++++--------- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/app/models/procedure_presentation.rb b/app/models/procedure_presentation.rb index 62d45475d..23a94de3c 100644 --- a/app/models/procedure_presentation.rb +++ b/app/models/procedure_presentation.rb @@ -20,6 +20,14 @@ class ProcedurePresentation < ApplicationRecord field_hash('Demandeur', 'user', 'email') ] + if procedure.for_individual + fields.push( + field_hash("Prénom", "individual", "prenom"), + field_hash("Nom", "individual", "nom"), + field_hash("Civilité", "individual", "gender") + ) + end + if !procedure.for_individual || (procedure.for_individual && procedure.individual_with_siret) fields.push( field_hash('SIREN', 'etablissement', 'entreprise_siren'), diff --git a/spec/models/procedure_presentation_spec.rb b/spec/models/procedure_presentation_spec.rb index 18cb9a9c6..071237465 100644 --- a/spec/models/procedure_presentation_spec.rb +++ b/spec/models/procedure_presentation_spec.rb @@ -49,42 +49,56 @@ describe ProcedurePresentation do end describe "#fields" do - let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private, :types_de_champ_count => 4, :types_de_champ_private_count => 4) } - let(:tdc_1) { procedure.types_de_champ[0] } - let(:tdc_2) { procedure.types_de_champ[1] } - let(:tdc_private_1) { procedure.types_de_champ_private[0] } - let(:tdc_private_2) { procedure.types_de_champ_private[1] } - let(:expected) { - [ - { "label" => 'Créé le', "table" => 'self', "column" => 'created_at' }, - { "label" => 'Mis à jour le', "table" => 'self', "column" => 'updated_at' }, - { "label" => 'Demandeur', "table" => 'user', "column" => 'email' }, - { "label" => 'SIREN', "table" => 'etablissement', "column" => 'entreprise_siren' }, - { "label" => 'Forme juridique', "table" => 'etablissement', "column" => 'entreprise_forme_juridique' }, - { "label" => 'Nom commercial', "table" => 'etablissement', "column" => 'entreprise_nom_commercial' }, - { "label" => 'Raison sociale', "table" => 'etablissement', "column" => 'entreprise_raison_sociale' }, - { "label" => 'SIRET siège social', "table" => 'etablissement', "column" => 'entreprise_siret_siege_social' }, - { "label" => 'Date de création', "table" => 'etablissement', "column" => 'entreprise_date_creation' }, - { "label" => 'SIRET', "table" => 'etablissement', "column" => 'siret' }, - { "label" => 'Libellé NAF', "table" => 'etablissement', "column" => 'libelle_naf' }, - { "label" => 'Code postal', "table" => 'etablissement', "column" => 'code_postal' }, - { "label" => tdc_1.libelle, "table" => 'type_de_champ', "column" => tdc_1.id.to_s }, - { "label" => tdc_2.libelle, "table" => 'type_de_champ', "column" => tdc_2.id.to_s }, - { "label" => tdc_private_1.libelle, "table" => 'type_de_champ_private', "column" => tdc_private_1.id.to_s }, - { "label" => tdc_private_2.libelle, "table" => 'type_de_champ_private', "column" => tdc_private_2.id.to_s } - ] - } + context 'when the procedure can have a SIRET number' do + let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private, :types_de_champ_count => 4, :types_de_champ_private_count => 4) } + let(:tdc_1) { procedure.types_de_champ[0] } + let(:tdc_2) { procedure.types_de_champ[1] } + let(:tdc_private_1) { procedure.types_de_champ_private[0] } + let(:tdc_private_2) { procedure.types_de_champ_private[1] } + let(:expected) { + [ + { "label" => 'Créé le', "table" => 'self', "column" => 'created_at' }, + { "label" => 'Mis à jour le', "table" => 'self', "column" => 'updated_at' }, + { "label" => 'Demandeur', "table" => 'user', "column" => 'email' }, + { "label" => 'SIREN', "table" => 'etablissement', "column" => 'entreprise_siren' }, + { "label" => 'Forme juridique', "table" => 'etablissement', "column" => 'entreprise_forme_juridique' }, + { "label" => 'Nom commercial', "table" => 'etablissement', "column" => 'entreprise_nom_commercial' }, + { "label" => 'Raison sociale', "table" => 'etablissement', "column" => 'entreprise_raison_sociale' }, + { "label" => 'SIRET siège social', "table" => 'etablissement', "column" => 'entreprise_siret_siege_social' }, + { "label" => 'Date de création', "table" => 'etablissement', "column" => 'entreprise_date_creation' }, + { "label" => 'SIRET', "table" => 'etablissement', "column" => 'siret' }, + { "label" => 'Libellé NAF', "table" => 'etablissement', "column" => 'libelle_naf' }, + { "label" => 'Code postal', "table" => 'etablissement', "column" => 'code_postal' }, + { "label" => tdc_1.libelle, "table" => 'type_de_champ', "column" => tdc_1.id.to_s }, + { "label" => tdc_2.libelle, "table" => 'type_de_champ', "column" => tdc_2.id.to_s }, + { "label" => tdc_private_1.libelle, "table" => 'type_de_champ_private', "column" => tdc_private_1.id.to_s }, + { "label" => tdc_private_2.libelle, "table" => 'type_de_champ_private', "column" => tdc_private_2.id.to_s } + ] + } - before do - procedure.types_de_champ[2].update_attribute(:type_champ,TypeDeChamp.type_champs.fetch(:header_section)) - procedure.types_de_champ[3].update_attribute(:type_champ,TypeDeChamp.type_champs.fetch(:explication)) - procedure.types_de_champ_private[2].update_attribute(:type_champ,TypeDeChamp.type_champs.fetch(:header_section)) - procedure.types_de_champ_private[3].update_attribute(:type_champ,TypeDeChamp.type_champs.fetch(:explication)) + before do + procedure.types_de_champ[2].update_attribute(:type_champ,TypeDeChamp.type_champs.fetch(:header_section)) + procedure.types_de_champ[3].update_attribute(:type_champ,TypeDeChamp.type_champs.fetch(:explication)) + procedure.types_de_champ_private[2].update_attribute(:type_champ,TypeDeChamp.type_champs.fetch(:header_section)) + procedure.types_de_champ_private[3].update_attribute(:type_champ,TypeDeChamp.type_champs.fetch(:explication)) + end + + subject { create(:procedure_presentation, assign_to: create(:assign_to, procedure: procedure)) } + + it { expect(subject.fields).to eq(expected) } end - subject { create(:procedure_presentation, assign_to: create(:assign_to, procedure: procedure)) } + context 'when the procedure is for individuals' do + let(:name_field) { { "label" => "Prénom", "table" => "individual", "column" => "prenom" } } + let(:surname_field) { { "label" => "Nom", "table" => "individual", "column" => "nom" } } + let(:gender_field) { { "label" => "Civilité", "table" => "individual", "column" => "gender" } } + let(:procedure) { create(:procedure, :for_individual) } + let(:procedure_presentation) { create(:procedure_presentation, assign_to: create(:assign_to, procedure: procedure)) } - it { expect(subject.fields).to eq(expected) } + subject { procedure_presentation.fields } + + it { is_expected.to include(name_field, surname_field, gender_field) } + end end describe "#fields_for_select" do From 34da620b0fe1f1f5db41e55c8896a5f04c590036 Mon Sep 17 00:00:00 2001 From: Frederic Merizen Date: Thu, 11 Oct 2018 10:46:32 +0200 Subject: [PATCH 2/4] [#1961] get_value for individual --- app/models/procedure_presentation.rb | 6 ++---- spec/models/procedure_presentation_spec.rb | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/app/models/procedure_presentation.rb b/app/models/procedure_presentation.rb index 23a94de3c..6e1c215fc 100644 --- a/app/models/procedure_presentation.rb +++ b/app/models/procedure_presentation.rb @@ -186,10 +186,8 @@ class ProcedurePresentation < ApplicationRecord case table when 'self' dossier.send(column) - when 'user' - dossier.user.send(column) - when 'etablissement' - dossier.etablissement&.send(column) + when 'user', 'individual', 'etablissement' + dossier.send(table)&.send(column) when 'type_de_champ' dossier.champs.find { |c| c.type_de_champ_id == column.to_i }.value when 'type_de_champ_private' diff --git a/spec/models/procedure_presentation_spec.rb b/spec/models/procedure_presentation_spec.rb index 071237465..35a3c82c9 100644 --- a/spec/models/procedure_presentation_spec.rb +++ b/spec/models/procedure_presentation_spec.rb @@ -147,6 +147,29 @@ describe ProcedurePresentation do it { is_expected.to eq('bla@yopmail.com') } end + context 'for individual table' do + let(:table) { 'individual' } + let(:dossier) { create(:dossier, procedure: procedure, individual: create(:individual, nom: 'Martin', prenom: 'Jacques', gender: 'M.')) } + + context 'for prenom column' do + let(:column) { 'prenom' } + + it { is_expected.to eq('Jacques') } + end + + context 'for nom column' do + let(:column) { 'nom' } + + it { is_expected.to eq('Martin') } + end + + context 'for gender column' do + let(:column) { 'gender' } + + it { is_expected.to eq('M.') } + end + end + context 'for etablissement table' do let(:table) { 'etablissement' } let(:column) { 'code_postal' } # All other columns work the same, no extra test required From abd066c6f433d9fc7cdaa2f43158700ee6609eb5 Mon Sep 17 00:00:00 2001 From: Frederic Merizen Date: Thu, 11 Oct 2018 11:17:58 +0200 Subject: [PATCH 3/4] [#1961] filtered_ids for individual --- app/models/procedure_presentation.rb | 2 +- spec/models/procedure_presentation_spec.rb | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/models/procedure_presentation.rb b/app/models/procedure_presentation.rb index 6e1c215fc..6cd363533 100644 --- a/app/models/procedure_presentation.rb +++ b/app/models/procedure_presentation.rb @@ -129,7 +129,7 @@ class ProcedurePresentation < ApplicationRecord .includes(table) .where("#{column} ILIKE ?", "%#{filter['value']}%") end - when 'user' + when 'user', 'individual' dossiers .includes(table) .where("#{column} ILIKE ?", "%#{filter['value']}%") diff --git a/spec/models/procedure_presentation_spec.rb b/spec/models/procedure_presentation_spec.rb index 35a3c82c9..7d41674b7 100644 --- a/spec/models/procedure_presentation_spec.rb +++ b/spec/models/procedure_presentation_spec.rb @@ -382,5 +382,29 @@ describe ProcedurePresentation do it { is_expected.to contain_exactly(kept_dossier.id) } end + + context 'for individual table' do + let(:procedure) { create(:procedure, :for_individual) } + let!(:kept_dossier) { create(:dossier, procedure: procedure, individual: create(:individual, gender: 'Mme', prenom: 'Josephine', nom: 'Baker')) } + let!(:discarded_dossier) { create(:dossier, procedure: procedure, individual: create(:individual, gender: 'M', prenom: 'Jean', nom: 'Tremblay')) } + + context 'for gender column' do + let(:filter) { [{ 'table' => 'individual', 'column' => 'gender', 'value' => 'Mme' }] } + + it { is_expected.to contain_exactly(kept_dossier.id) } + end + + context 'for prenom column' do + let(:filter) { [{ 'table' => 'individual', 'column' => 'prenom', 'value' => 'Josephine' }] } + + it { is_expected.to contain_exactly(kept_dossier.id) } + end + + context 'for nom column' do + let(:filter) { [{ 'table' => 'individual', 'column' => 'nom', 'value' => 'Baker' }] } + + it { is_expected.to contain_exactly(kept_dossier.id) } + end + end end end From 3dca3c7dee96fb19bc9ce24ea817db93f9e06833 Mon Sep 17 00:00:00 2001 From: Frederic Merizen Date: Thu, 11 Oct 2018 11:28:51 +0200 Subject: [PATCH 4/4] [Fix #1961] Check that sorted_ids works for individual --- app/models/procedure_presentation.rb | 2 +- config/brakeman.ignore | 46 +++++++++++----------- spec/models/procedure_presentation_spec.rb | 28 +++++++++++++ 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/app/models/procedure_presentation.rb b/app/models/procedure_presentation.rb index 6cd363533..1e55d8c13 100644 --- a/app/models/procedure_presentation.rb +++ b/app/models/procedure_presentation.rb @@ -95,7 +95,7 @@ class ProcedurePresentation < ApplicationRecord .where("champs.type_de_champ_id = #{sort['column'].to_i}") .order("champs.value #{order}") .pluck(:id) - else + when 'user', 'individual', 'etablissement' return dossiers .includes(table) .order("#{column} #{order}") diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 3ef4730c0..cb8344d0e 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -1,25 +1,5 @@ { "ignored_warnings": [ - { - "warning_type": "SQL Injection", - "warning_code": 0, - "fingerprint": "030551e51e29561702bcb9760bdeeed15e1936d4a9537f27e5d1d13a0ebb34ef", - "check_name": "SQL", - "message": "Possible SQL injection", - "file": "app/models/procedure_presentation.rb", - "line": 130, - "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", - "code": "dossiers.includes(sort[\"table\"]).order(\"#{sanitized_column(sort)} #{sort[\"order\"]}\")", - "render_path": null, - "location": { - "type": "method", - "class": "ProcedurePresentation", - "method": "sorted_ids" - }, - "user_input": "sanitized_column(sort)", - "confidence": "Weak", - "note": "Not an injection because of `sanitized_column`" - }, { "warning_type": "SQL Injection", "warning_code": 0, @@ -27,7 +7,7 @@ "check_name": "SQL", "message": "Possible SQL injection", "file": "app/models/procedure_presentation.rb", - "line": 119, + "line": 90, "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "dossiers.order(\"#{sanitized_column(sort)} #{sort[\"order\"]}\")", "render_path": null, @@ -47,7 +27,7 @@ "check_name": "SQL", "message": "Possible SQL injection", "file": "app/models/procedure_presentation.rb", - "line": 125, + "line": 96, "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "dossiers.includes(((\"type_de_champ\" == \"type_de_champ\") ? (:champs) : (:champs_private))).where(\"champs.type_de_champ_id = #{sort[\"column\"].to_i}\").order(\"champs.value #{sort[\"order\"]}\")", "render_path": null, @@ -59,8 +39,28 @@ "user_input": "sort[\"order\"]", "confidence": "Weak", "note": "Not an injection because `sort[\"order\"]` has passed `check_allowed_sort_order`" + }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "e0e5b55126891df8fe144835ea99367ffd7a92ae6d7227a923fe79f4a79f67f4", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/models/procedure_presentation.rb", + "line": 101, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "dossiers.includes(\"user\").order(\"#{sanitized_column(sort)} #{sort[\"order\"]}\")", + "render_path": null, + "location": { + "type": "method", + "class": "ProcedurePresentation", + "method": "sorted_ids" + }, + "user_input": "sanitized_column(sort)", + "confidence": "Weak", + "note": "Not an injection because of `sanitized_column`" } ], - "updated": "2018-10-05 16:12:32 +0200", + "updated": "2018-10-11 12:09:03 +0200", "brakeman_version": "4.3.1" } diff --git a/spec/models/procedure_presentation_spec.rb b/spec/models/procedure_presentation_spec.rb index 7d41674b7..f85d9de97 100644 --- a/spec/models/procedure_presentation_spec.rb +++ b/spec/models/procedure_presentation_spec.rb @@ -286,6 +286,34 @@ describe ProcedurePresentation do it { is_expected.to eq([biere_dossier, vin_dossier].map(&:id)) } end + context 'for individual table' do + let(:table) { 'individual' } + let(:order) { 'asc' } # Desc works the same, no extra test required + + let(:procedure) { create(:procedure, :for_individual) } + + let!(:first_dossier) { create(:dossier, procedure: procedure, individual: create(:individual, gender: 'M', prenom: 'Alain', nom: 'Antonelli')) } + let!(:last_dossier) { create(:dossier, procedure: procedure, individual: create(:individual, gender: 'Mme', prenom: 'Zora', nom: 'Zemmour')) } + + context 'for gender column' do + let(:column) { 'gender' } + + it { is_expected.to eq([first_dossier, last_dossier].map(&:id)) } + end + + context 'for prenom column' do + let(:column) { 'prenom' } + + it { is_expected.to eq([first_dossier, last_dossier].map(&:id)) } + end + + context 'for nom column' do + let(:column) { 'nom' } + + it { is_expected.to eq([first_dossier, last_dossier].map(&:id)) } + end + end + context 'for other tables' do # All other columns and tables work the same so it’s ok to test only one let(:table) { 'etablissement' }