From b8ff0ba4a28790c0c5999a1a57cf0426d0b5a3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Carceles?= Date: Thu, 15 Dec 2022 10:58:17 +0100 Subject: [PATCH] feat(demarche): sign up when prefilling a dossier (#8247) * store prefill params in session Instead of using query params on /dossier/new, we assume the user comes from /commencer/:path, which is the new prefill link. There, we store the prefill params in session, and use them to prefill the dossier when creating it, in /dossiers/new. * spec: cover the case * review: serialize with json instead of yaml * review: rename method * review: store only query params * review: comment why we dont override already stored params --- .../concerns/query_params_store_concern.rb | 17 +++++ app/controllers/users/commencer_controller.rb | 4 ++ app/controllers/users/dossiers_controller.rb | 3 +- app/models/prefill_params.rb | 1 - .../query_params_store_concern_spec.rb | 66 +++++++++++++++++++ .../users/commencer_controller_spec.rb | 10 +++ .../users/dossiers_controller_spec.rb | 6 +- spec/models/prefill_params_spec.rb | 2 +- spec/system/users/dossier_prefill_spec.rb | 62 +++++++++-------- 9 files changed, 141 insertions(+), 30 deletions(-) create mode 100644 app/controllers/concerns/query_params_store_concern.rb create mode 100644 spec/controllers/concerns/query_params_store_concern_spec.rb diff --git a/app/controllers/concerns/query_params_store_concern.rb b/app/controllers/concerns/query_params_store_concern.rb new file mode 100644 index 000000000..31c8828ee --- /dev/null +++ b/app/controllers/concerns/query_params_store_concern.rb @@ -0,0 +1,17 @@ +module QueryParamsStoreConcern + extend ActiveSupport::Concern + + def store_query_params + # Don't override already stored params, because we could do goings and comings with authentication, and + # lost previously stored params + return if session[:stored_params].present? || request.query_parameters.empty? + + session[:stored_params] = request.query_parameters.to_json + end + + def retrieve_and_delete_stored_query_params + return {} if session[:stored_params].blank? + + JSON.parse(session.delete(:stored_params)) + end +end diff --git a/app/controllers/users/commencer_controller.rb b/app/controllers/users/commencer_controller.rb index 8754f24bb..c336738da 100644 --- a/app/controllers/users/commencer_controller.rb +++ b/app/controllers/users/commencer_controller.rb @@ -1,11 +1,15 @@ module Users class CommencerController < ApplicationController + include QueryParamsStoreConcern + layout 'procedure_context' def commencer @procedure = retrieve_procedure return procedure_not_found if @procedure.blank? || @procedure.brouillon? + store_query_params + @revision = @procedure.published_revision render 'commencer/show' end diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 6aa397d38..6b1d7bb85 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -1,6 +1,7 @@ module Users class DossiersController < UserController include DossierHelper + include QueryParamsStoreConcern layout 'procedure_context', only: [:identite, :update_identite, :siret, :update_siret] @@ -304,7 +305,7 @@ module Users ) dossier.build_default_individual dossier.save! - dossier.prefill!(PrefillParams.new(dossier, params).to_a) + dossier.prefill!(PrefillParams.new(dossier, retrieve_and_delete_stored_query_params).to_a) if dossier.procedure.for_individual redirect_to identite_dossier_path(dossier) diff --git a/app/models/prefill_params.rb b/app/models/prefill_params.rb index 05970e277..8e94828c8 100644 --- a/app/models/prefill_params.rb +++ b/app/models/prefill_params.rb @@ -12,7 +12,6 @@ class PrefillParams def build_prefill_values value_by_stable_id = @params - .to_unsafe_hash .map { |prefixed_typed_id, value| [stable_id_from_typed_id(prefixed_typed_id), value] } .filter { |stable_id, value| stable_id.present? && value.present? } .to_h diff --git a/spec/controllers/concerns/query_params_store_concern_spec.rb b/spec/controllers/concerns/query_params_store_concern_spec.rb new file mode 100644 index 000000000..c2e228944 --- /dev/null +++ b/spec/controllers/concerns/query_params_store_concern_spec.rb @@ -0,0 +1,66 @@ +RSpec.describe QueryParamsStoreConcern, type: :controller do + class TestController < ActionController::Base + include QueryParamsStoreConcern + end + + controller TestController do + end + + before { allow_any_instance_of(ActionDispatch::Request).to receive(:query_parameters).and_return(params) } + + describe '#store_query_params' do + subject(:store_query_params) { controller.store_query_params } + + context 'when params are already stored' do + let(:params) { { param1: "param1" } } + + it "does nothing" do + session[:stored_params] = "there is alread something in there" + + expect { store_query_params }.not_to change { session[:stored_params] } + end + end + + context 'when params are empty' do + let(:params) { {} } + + it "does nothing" do + expect { store_query_params }.not_to change { session[:stored_params] } + end + end + + context 'when the store is empty and we have params' do + let(:params) { { param1: "param1", param2: "param2" } } + + it "stores the query params" do + expect { store_query_params }.to change { session[:stored_params] }.from(nil).to(params.to_json) + end + end + end + + describe '#retrieve_and_delete_stored_query_params' do + subject(:retrieve_and_delete_stored_query_params) { controller.retrieve_and_delete_stored_query_params } + + context 'when there are no stored params' do + let(:params) { {} } + + it 'returns an empty hash' do + expect(retrieve_and_delete_stored_query_params).to be_empty + end + end + + context 'when params are stored' do + let(:params) { { param1: "param1", param2: "param2" } } + + before { controller.store_query_params } + + it 'deletes the stored params' do + expect { retrieve_and_delete_stored_query_params }.to change { session[:stored_params] }.to(nil) + end + + it 'returns the stored params' do + expect(retrieve_and_delete_stored_query_params).to match(params.with_indifferent_access) + end + end + end +end diff --git a/spec/controllers/users/commencer_controller_spec.rb b/spec/controllers/users/commencer_controller_spec.rb index 953d2fceb..d64094521 100644 --- a/spec/controllers/users/commencer_controller_spec.rb +++ b/spec/controllers/users/commencer_controller_spec.rb @@ -15,6 +15,16 @@ describe Users::CommencerController, type: :controller do expect(assigns(:procedure)).to eq published_procedure expect(assigns(:revision)).to eq published_procedure.published_revision end + + context 'when there are query params' do + subject { get :commencer, params: { path: path, any_param: "any param" } } + + it "stores the parameters in session" do + subject + + expect(session[:stored_params]).to be_present + end + end end context 'when the path is for a draft procedure' do diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index 478792f2d..fe653757a 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -1067,7 +1067,7 @@ describe Users::DossiersController, type: :controller do it { is_expected.to redirect_to dossiers_path } end - context 'when prefill values are given' do + context 'when prefill values have been stored in session before' do let!(:type_de_champ_1) { create(:type_de_champ_text, procedure: procedure) } let(:value_1) { "any value" } @@ -1082,6 +1082,10 @@ describe Users::DossiersController, type: :controller do } } + before { session[:stored_params] = params.to_json } + + it { expect { subject }.to change { session[:stored_params] }.to(nil) } + it { expect { subject }.to change { Dossier.count }.by(1) } it "prefills the dossier's champs with the given values" do diff --git a/spec/models/prefill_params_spec.rb b/spec/models/prefill_params_spec.rb index 271d5f756..4f3e145a0 100644 --- a/spec/models/prefill_params_spec.rb +++ b/spec/models/prefill_params_spec.rb @@ -3,7 +3,7 @@ RSpec.describe PrefillParams do let(:procedure) { create(:procedure, :published) } let(:dossier) { create(:dossier, :brouillon, procedure: procedure) } - subject(:prefill_params_array) { described_class.new(dossier, ActionController::Parameters.new(params)).to_a } + subject(:prefill_params_array) { described_class.new(dossier, params).to_a } context "when the stable ids match the TypeDeChamp of the corresponding procedure" do let!(:type_de_champ_1) { create(:type_de_champ_text, procedure: procedure) } diff --git a/spec/system/users/dossier_prefill_spec.rb b/spec/system/users/dossier_prefill_spec.rb index 0d9657daf..386feeba5 100644 --- a/spec/system/users/dossier_prefill_spec.rb +++ b/spec/system/users/dossier_prefill_spec.rb @@ -1,4 +1,5 @@ describe 'Prefilling a dossier:' do + let(:password) { 'my-s3cure-p4ssword' } let(:siret) { '41816609600051' } let(:procedure) { create(:procedure, :published, opendata: true) } @@ -13,20 +14,16 @@ describe 'Prefilling a dossier:' do stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}/) .to_return(status: 200, body: File.read('spec/fixtures/files/api_entreprise/etablissements.json')) - visit new_dossier_path( - procedure_id: procedure.id, + visit commencer_path( + path: procedure.path, "champ_#{type_de_champ_text.to_typed_id}" => text_value, "champ_#{type_de_champ_phone.to_typed_id}" => phone_value ) end - context 'when the user already exists' do - let(:password) { 'my-s3cure-p4ssword' } - let!(:user) { create(:user, password: password) } - - scenario "the user has got a prefilled dossier after signing in" do - expect(page).to have_content("Connectez-vous") - sign_in_with user.email, password + shared_examples "the user has got a prefilled dossier" do + scenario "the user has got a prefilled dossier" do + click_on "Commencer la démarche" expect(page).to have_current_path siret_dossier_path(procedure.dossiers.last) fill_in 'Numéro SIRET', with: siret @@ -43,28 +40,41 @@ describe 'Prefilling a dossier:' do end end - context 'when this is a new user' do - before do - allow_any_instance_of(FranceConnectParticulierClient).to receive(:authorization_uri).and_return(france_connect_particulier_callback_path(code: "c0d3")) - allow(FranceConnectService).to receive(:retrieve_user_informations_particulier).and_return(build(:france_connect_information)) + context 'when the user signs in with email and password' do + it_behaves_like "the user has got a prefilled dossier" do + let!(:user) { create(:user, password: password) } + + before do + click_on "J’ai déjà un compte" + sign_in_with user.email, password + end end + end - scenario "the user has got a prefilled dossier after signing up" do - expect(page).to have_content("Connectez-vous") - page.find('.fr-connect').click + context 'when the user signs up with email and password' do + it_behaves_like "the user has got a prefilled dossier" do + let(:user_email) { generate :user_email } - expect(page).to have_current_path siret_dossier_path(procedure.dossiers.last) - fill_in 'Numéro SIRET', with: siret - click_on 'Valider' + before do + click_on "Créer un compte #{APPLICATION_NAME}" - expect(page).to have_current_path(etablissement_dossier_path(dossier)) - expect(page).to have_content('OCTO TECHNOLOGY') - click_on 'Continuer avec ces informations' + sign_up_with user_email, password + expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}" - expect(page).to have_current_path(brouillon_dossier_path(dossier)) - expect(page).to have_field(type_de_champ_text.libelle, with: text_value) - expect(page).to have_field(type_de_champ_phone.libelle, with: phone_value) - expect(page).to have_css('.field_with_errors', text: type_de_champ_phone.libelle) + click_confirmation_link_for user_email + expect(page).to have_content('Votre compte a bien été confirmé.') + end + end + end + + context 'when the user signs up with FranceConnect' do + it_behaves_like "the user has got a prefilled dossier" do + before do + allow_any_instance_of(FranceConnectParticulierClient).to receive(:authorization_uri).and_return(france_connect_particulier_callback_path(code: "c0d3")) + allow(FranceConnectService).to receive(:retrieve_user_informations_particulier).and_return(build(:france_connect_information)) + + page.find('.fr-connect').click + end end end end