From 81cbda05538f8d31d06419e3b19b3cddd45539ed Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Thu, 17 Oct 2024 17:45:11 +0200 Subject: [PATCH 1/2] feat(instructeurs): can add many instructeurs --- .../groupe_instructeurs_controller.rb | 72 ++++++++++--------- .../groupe_instructeurs/show.html.haml | 15 ++-- .../instructeurs/groupe_instructeurs/fr.yml | 16 +++++ .../groupe_instructeurs_controller_spec.rb | 16 +++-- 4 files changed, 74 insertions(+), 45 deletions(-) create mode 100644 config/locales/views/instructeurs/groupe_instructeurs/fr.yml diff --git a/app/controllers/instructeurs/groupe_instructeurs_controller.rb b/app/controllers/instructeurs/groupe_instructeurs_controller.rb index f7caec975..046da2574 100644 --- a/app/controllers/instructeurs/groupe_instructeurs_controller.rb +++ b/app/controllers/instructeurs/groupe_instructeurs_controller.rb @@ -21,41 +21,51 @@ module Instructeurs end def add_instructeur - email = instructeur_email.present? ? [instructeur_email] : [] - email = check_if_typo(email)&.first + emails = params['emails'].presence || [] + emails = check_if_typo(emails) errors = Array.wrap(generate_emails_suggestions_message(@maybe_typos)) + instructeurs, invalid_emails = groupe_instructeur.add_instructeurs(emails:) + + if invalid_emails.present? + errors += [ + t('.wrong_address', + count: invalid_emails.size, + emails: invalid_emails.join(', ')) + ] + end + + if instructeurs.present? + flash[:notice] = if procedure.routing_enabled? + t('.assignment', count: instructeurs.size, + emails: instructeurs.map(&:email).join(', '), + groupe: groupe_instructeur.label) + else + "Les instructeurs ont bien été affectés à la démarche" + end + + known_instructeurs, not_verified_instructeurs = instructeurs.partition { |instructeur| instructeur.user.email_verified_at } + + not_verified_instructeurs.filter(&:should_receive_email_activation?).each do + InstructeurMailer.confirm_and_notify_added_instructeur(_1, groupe_instructeur, current_instructeur.email).deliver_later + end + + if known_instructeurs.present? + GroupeInstructeurMailer + .notify_added_instructeurs(groupe_instructeur, known_instructeurs, current_instructeur.email) + .deliver_later + end + end + + @procedure = procedure + @groupe_instructeur = groupe_instructeur + @instructeurs = paginated_instructeurs + if !errors.empty? flash.now[:alert] = errors.join(". ") if !errors.empty? - - @procedure = procedure - @groupe_instructeur = groupe_instructeur - @instructeurs = paginated_instructeurs - return render :show end - instructeur = Instructeur.by_email(email) || - create_instructeur(email) - - if instructeur.blank? - flash[:alert] = "L’adresse email « #{email} » n’est pas valide." - elsif groupe_instructeur.instructeurs.include?(instructeur) - flash[:alert] = "L’instructeur « #{email} » est déjà dans le groupe." - else - groupe_instructeur.add(instructeur) - flash[:notice] = "L’instructeur « #{email} » a été affecté au groupe." - - if instructeur.user.email_verified_at - GroupeInstructeurMailer - .notify_added_instructeurs(groupe_instructeur, [instructeur], current_user.email) - .deliver_later - elsif instructeur.should_receive_email_activation? - InstructeurMailer.confirm_and_notify_added_instructeur(instructeur, groupe_instructeur, current_user.email).deliver_later - end - # else instructeur already exists and email is not verified, so do not spam them - end - - redirect_to instructeur_groupe_path(procedure, groupe_instructeur) + render :show end def remove_instructeur @@ -115,10 +125,6 @@ module Instructeurs .order(:email) end - def instructeur_email - params.dig('instructeur', 'email')&.strip&.downcase - end - def instructeur_id params[:instructeur][:id] end diff --git a/app/views/instructeurs/groupe_instructeurs/show.html.haml b/app/views/instructeurs/groupe_instructeurs/show.html.haml index e0a42aa46..ea54dc215 100644 --- a/app/views/instructeurs/groupe_instructeurs/show.html.haml +++ b/app/views/instructeurs/groupe_instructeurs/show.html.haml @@ -22,11 +22,16 @@ .card.fr-mt-2w = render Procedure::InvitationWithTypoComponent.new(maybe_typos: @maybe_typos, url: add_instructeur_instructeur_groupe_path(@procedure, @groupe_instructeur.id), title: "Avant d'ajouter l'email, veuillez confirmer" ) - %h2.fr-h3 Gestion des instructeurs - = form_for(Instructeur.new(user: User.new), url: { action: :add_instructeur }, html: { class: 'form' }) do |f| - %h3.fr-h4 Affecter un nouvel instructeur - = render Dsfr::InputComponent.new(form: f, attribute: :email) - = f.submit 'Affecter', class: 'fr-btn fr-primary' + %h2.fr-h3= t('.title') + + = form_for :instructeur, url: { action: :add_instructeur, id: @groupe_instructeur.id }, html: { class: 'form' } do |f| + .instructeur-wrapper + %p= t('.instructeur_emails') + %p.fr-hint-text= t('.copy_paste_hint') + %react-fragment + = render ReactComponent.new 'ComboBox/MultiComboBox', id: 'instructeur_emails', name: 'emails[]', allows_custom_value: true, 'aria-label': 'Emails' + + = f.submit t('.assign'), class: 'fr-btn fr-btn--tertiary' %table.fr-table.fr-mt-2w.width-100 %thead diff --git a/config/locales/views/instructeurs/groupe_instructeurs/fr.yml b/config/locales/views/instructeurs/groupe_instructeurs/fr.yml new file mode 100644 index 000000000..a198cb320 --- /dev/null +++ b/config/locales/views/instructeurs/groupe_instructeurs/fr.yml @@ -0,0 +1,16 @@ +fr: + instructeurs: + groupe_instructeurs: + show: + title: Affecter un nouvel instructeur + instructeur_emails: Adresse électronique des instructeurs que vous souhaitez affecter à cette démarche. + copy_paste_hint: "Vous pouvez saisir les adresses individuellement, ou bien copier-coller dans le champ ci-dessous une liste d’adresses séparées par des points-virgules (exemple : adresse1@mail.com; adresse2@mail.com; adresse3@mail.com)." + assign: Affecter + wrong_adress: "L’adresse électronique saisie n’est pas valide." + add_instructeur: + wrong_address: + one: "%{emails} n’est pas une adresse email valide" + other: "%{emails} ne sont pas des adresses emails valides" + assignment: + one: "L’instructeur %{emails} a été affecté au groupe « %{groupe} »." + other: "Les instructeurs %{emails} ont été affectés au groupe « %{groupe} »." diff --git a/spec/controllers/instructeurs/groupe_instructeurs_controller_spec.rb b/spec/controllers/instructeurs/groupe_instructeurs_controller_spec.rb index 043d20071..eeff1104e 100644 --- a/spec/controllers/instructeurs/groupe_instructeurs_controller_spec.rb +++ b/spec/controllers/instructeurs/groupe_instructeurs_controller_spec.rb @@ -88,7 +88,7 @@ describe Instructeurs::GroupeInstructeursController, type: :controller do params: { procedure_id: procedure.id, id: gi_1_2.id, - instructeur: { email: new_instructeur_email } + emails: [new_instructeur_email] } end @@ -99,7 +99,7 @@ describe Instructeurs::GroupeInstructeursController, type: :controller do it "works" do expect(gi_1_2.instructeurs.map(&:email)).to include(new_instructeur_email) expect(flash.notice).to be_present - expect(response).to redirect_to(instructeur_groupe_path(procedure, gi_1_2)) + expect(response).to have_http_status(:success) expect(InstructeurMailer).to have_received(:confirm_and_notify_added_instructeur).with(instance_of(Instructeur), gi_1_2, anything) expect(GroupeInstructeurMailer).not_to have_received(:notify_added_instructeurs) end @@ -114,7 +114,7 @@ describe Instructeurs::GroupeInstructeursController, type: :controller do it "works" do expect(gi_1_2.instructeurs.map(&:email)).to include(new_instructeur_email) expect(flash.notice).to be_present - expect(response).to redirect_to(instructeur_groupe_path(procedure, gi_1_2)) + expect(response).to have_http_status(:success) expect(InstructeurMailer).not_to have_received(:confirm_and_notify_added_instructeur) expect(GroupeInstructeurMailer).to have_received(:notify_added_instructeurs) end @@ -129,7 +129,7 @@ describe Instructeurs::GroupeInstructeursController, type: :controller do it "works" do expect(gi_1_2.instructeurs.map(&:email)).to include(new_instructeur_email) expect(flash.notice).to be_present - expect(response).to redirect_to(instructeur_groupe_path(procedure, gi_1_2)) + expect(response).to have_http_status(:success) expect(InstructeurMailer).to have_received(:confirm_and_notify_added_instructeur) expect(GroupeInstructeurMailer).not_to have_received(:notify_added_instructeurs) end @@ -137,11 +137,13 @@ describe Instructeurs::GroupeInstructeursController, type: :controller do context 'of an instructeur already in the group' do let(:new_instructeur_email) { instructeur.email } - before { subject } + before do + instructeur.user.update(email_verified_at: 1.day.ago) + subject + end it "works" do - expect(flash.alert).to be_present - expect(response).to redirect_to(instructeur_groupe_path(procedure, gi_1_2)) + expect(response).to have_http_status(:success) expect(InstructeurMailer).not_to have_received(:confirm_and_notify_added_instructeur) expect(GroupeInstructeurMailer).not_to have_received(:notify_added_instructeurs) end From fa449d3e41e9790bb1b56df2b889404530c4c9e2 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Tue, 22 Oct 2024 17:33:31 +0200 Subject: [PATCH 2/2] fix(instructeurs test): avoid duplication of instructor with same email --- .../instructeurs/groupe_instructeurs_controller_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/controllers/instructeurs/groupe_instructeurs_controller_spec.rb b/spec/controllers/instructeurs/groupe_instructeurs_controller_spec.rb index eeff1104e..3ecfddda6 100644 --- a/spec/controllers/instructeurs/groupe_instructeurs_controller_spec.rb +++ b/spec/controllers/instructeurs/groupe_instructeurs_controller_spec.rb @@ -2,9 +2,9 @@ describe Instructeurs::GroupeInstructeursController, type: :controller do render_views - let(:administrateurs) { [create(:administrateur, user: instructeur.user)] } - let(:instructeur) { create(:instructeur) } - let(:procedure) { create(:procedure, :published, administrateurs:) } + let(:administrateur) { create(:administrateur) } + let(:instructeur) { administrateur.instructeur } + let(:procedure) { create(:procedure, :published, administrateurs: [administrateur]) } let!(:gi_1_1) { procedure.defaut_groupe_instructeur } let!(:gi_1_2) { create(:groupe_instructeur, label: 'groupe instructeur 2', procedure: procedure) }