Merge pull request #10579 from demarches-simplifiees/instructeur-invitation-include-typo-suggestion-ldu

ETQ admin et instructeur, lorsque je gère ma liste d'instructeurs sur une démarche, je suis guidé pour eviter les typos
This commit is contained in:
Lisa Durand 2024-07-10 14:48:49 +00:00 committed by GitHub
commit 72f840e393
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 76 additions and 43 deletions

View file

@ -10,16 +10,10 @@ module Administrateurs
def create
emails = params['emails'].presence || []
emails = emails.map { EmailSanitizer.sanitize(_1) }
@maybe_typos, no_suggestions = emails
.map { |email| [email, EmailChecker.check(email:)[:suggestions]&.first] }
.partition { _1[1].present? }
emails = check_if_typo(emails)
errors = Array.wrap(generate_emails_suggestions_message(@maybe_typos))
emails = no_suggestions.map(&:first)
emails << EmailSanitizer.sanitize(params['final_email']) if params['final_email'].present?
valid_users, invalid_users = emails
.map { |email| User.create_or_promote_to_expert(email, SecureRandom.hex) }
.partition(&:valid?)
@ -78,14 +72,5 @@ module Administrateurs
def expert_procedure_params
params.require(:experts_procedure).permit(:allow_decision_access)
end
def generate_emails_suggestions_message(suggestions)
return if suggestions.empty?
typo_list = suggestions.map(&:first).join(', ')
verification_link = view_context.link_to("vérifier lorthographe", "#maybe_typos_errors")
"Attention, nous pensons avoir identifié une faute de frappe dans les invitations : #{typo_list}. Veuillez #{verification_link} des invitations."
end
end
end

View file

@ -1,6 +1,7 @@
module Administrateurs
class GroupeInstructeursController < AdministrateurController
include ActiveSupport::NumberHelper
include EmailSanitizableConcern
include Logic
include UninterlacePngConcern
include GroupeInstructeursSignatureConcern
@ -218,19 +219,22 @@ module Administrateurs
end
def add_instructeur
emails = params[:emails].presence || []
emails = emails.map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) }
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?
flash[:alert] = t('.wrong_address',
errors += [
t('.wrong_address',
count: invalid_emails.size,
emails: invalid_emails.join(', '))
]
end
if instructeurs.present?
flash[:notice] = if procedure.routing_enabled?
flash.now[:notice] = if procedure.routing_enabled?
t('.assignment',
count: instructeurs.size,
emails: instructeurs.map(&:email).join(', '),
@ -250,10 +254,18 @@ module Administrateurs
end
end
flash.now[:alert] = errors.join(". ") if !errors.empty?
@procedure = procedure
@instructeurs = paginated_instructeurs
@available_instructeur_emails = available_instructeur_emails
if procedure.routing_enabled?
redirect_to admin_procedure_groupe_instructeur_path(procedure, groupe_instructeur)
@groupe_instructeur = groupe_instructeur
render :show
else
redirect_to admin_procedure_groupe_instructeurs_path(procedure)
@groupes_instructeurs = paginated_groupe_instructeurs
render :index
end
end

View file

@ -1,5 +1,6 @@
module Instructeurs
class GroupeInstructeursController < InstructeurController
include EmailSanitizableConcern
include UninterlacePngConcern
include GroupeInstructeursSignatureConcern
@ -19,16 +20,29 @@ module Instructeurs
end
def add_instructeur
instructeur = Instructeur.by_email(instructeur_email) ||
create_instructeur(instructeur_email)
email = instructeur_email.present? ? [instructeur_email] : []
email = check_if_typo(email)&.first
errors = Array.wrap(generate_emails_suggestions_message(@maybe_typos))
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] = "Ladresse email « #{instructeur_email} » nest pas valide."
flash[:alert] = "Ladresse email « #{email} » nest pas valide."
elsif groupe_instructeur.instructeurs.include?(instructeur)
flash[:alert] = "Linstructeur « #{instructeur_email} » est déjà dans le groupe."
flash[:alert] = "Linstructeur « #{email} » est déjà dans le groupe."
else
groupe_instructeur.add(instructeur)
flash[:notice] = "Linstructeur « #{instructeur_email} » a été affecté au groupe."
flash[:notice] = "Linstructeur « #{email} » a été affecté au groupe."
if instructeur.user.email_verified_at
GroupeInstructeurMailer
@ -100,7 +114,7 @@ module Instructeurs
end
def instructeur_email
params[:instructeur][:email].strip.downcase
params.dig('instructeur', 'email')&.strip&.downcase
end
def instructeur_id

View file

@ -8,6 +8,26 @@ module EmailSanitizableConcern
end
end
def generate_emails_suggestions_message(suggestions)
return if suggestions.empty?
typo_list = suggestions.map(&:first).join(', ')
verification_link = view_context.link_to("vérifier lorthographe", "#maybe_typos_errors")
"Attention, nous pensons avoir identifié une faute de frappe dans les invitations : #{typo_list}. Veuillez #{verification_link} des invitations."
end
def check_if_typo(emails)
emails = emails.map { EmailSanitizer.sanitize(_1) }
@maybe_typos, no_suggestions = emails
.map { |email| [email, EmailChecker.check(email:)[:suggestions]&.first] }
.partition { _1[1].present? }
emails = no_suggestions.map(&:first)
emails << EmailSanitizer.sanitize(params['final_email']) if params['final_email'].present?
emails
end
class EmailSanitizer
def self.sanitize(value)
value.gsub(/[[:space:]]/, ' ').strip.downcase

View file

@ -1,5 +1,6 @@
.card
= render Procedure::InvitationWithTypoComponent.new(maybe_typos: @maybe_typos, url: add_instructeur_admin_procedure_groupe_instructeur_path(@procedure, groupe_instructeur.id), title: "Avant d'ajouter l'email, veuillez confirmer" )
.card-title Affectation des instructeurs
= form_for :instructeur, url: { action: :add_instructeur, id: groupe_instructeur.id }, html: { class: 'form' } do |f|
.instructeur-wrapper

View file

@ -21,6 +21,7 @@
Démarche « #{@procedure.libelle} »
.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

View file

@ -341,7 +341,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
context 'when all emails are valid' do
let(:emails) { ['test@b.gouv.fr', 'test2@b.gouv.fr'] }
it do
expect(subject).to redirect_to admin_procedure_groupe_instructeurs_path(procedure_non_routee)
expect(subject).to render_template(:index)
expect(subject.request.flash[:alert]).to be_nil
expect(subject.request.flash[:notice]).to be_present
end
@ -350,7 +350,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
context 'when there is at least one bad email' do
let(:emails) { ['badmail', 'instructeur2@gmail.com'] }
it do
expect(subject).to redirect_to admin_procedure_groupe_instructeurs_path(procedure_non_routee)
expect(subject).to render_template(:index)
expect(subject.request.flash[:alert]).to be_present
expect(subject.request.flash[:notice]).to be_present
end
@ -360,7 +360,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
let(:instructeur) { create(:instructeur) }
before { procedure_non_routee.groupe_instructeurs.first.add_instructeurs(emails: [instructeur.user.email]) }
let(:emails) { [instructeur.email] }
it { expect(subject).to redirect_to admin_procedure_groupe_instructeurs_path(procedure_non_routee) }
it { expect(subject).to render_template(:index) }
end
context 'when signed in admin comes from manager' do
@ -385,7 +385,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
context 'of news instructeurs' do
let!(:user_email_verified) { create(:user, :with_email_verified) }
let!(:instructeur_email_verified) { create(:instructeur, user: user_email_verified) }
let(:new_instructeur_emails) { ['new_i1@mail.com', 'new_i2@mail.com', instructeur_email_verified.email] }
let(:new_instructeur_emails) { ['new_i1@gmail.com', 'new_i2@gmail.com', instructeur_email_verified.email] }
before do
allow(GroupeInstructeurMailer).to receive(:notify_added_instructeurs)
@ -398,7 +398,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
it 'validates changes and responses' do
expect(gi_1_2.instructeurs.pluck(:email)).to include(*new_instructeur_emails)
expect(flash.notice).to be_present
expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2))
expect(response).to render_template(:show)
expect(procedure.routing_enabled?).to be_truthy
expect(GroupeInstructeurMailer).to have_received(:notify_added_instructeurs).with(
gi_1_2,
@ -409,13 +409,13 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
it "calls InstructeurMailer with the right params" do
expect(InstructeurMailer).to have_received(:confirm_and_notify_added_instructeur).with(
User.find_by(email: 'new_i1@mail.com').instructeur,
User.find_by(email: 'new_i1@gmail.com').instructeur,
gi_1_2,
admin.email
)
expect(InstructeurMailer).to have_received(:confirm_and_notify_added_instructeur).with(
User.find_by(email: 'new_i2@mail.com').instructeur,
User.find_by(email: 'new_i2@gmail.com').instructeur,
gi_1_2,
admin.email
)
@ -425,7 +425,7 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
context 'of an instructeur already in the group' do
let(:new_instructeur_emails) { [instructeur.email] }
before { do_request }
it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) }
it { expect(response).to render_template(:show) }
end
context 'of badly formed email' do
@ -433,14 +433,14 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
before { do_request }
it do
expect(flash.alert).to be_present
expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2))
expect(response).to render_template(:show)
end
end
context 'of an empty string' do
let(:new_instructeur_emails) { [''] }
before { do_request }
it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) }
it { expect(response).to render_template(:show) }
end
context 'when connected as an administrateur from manager' do

View file

@ -86,7 +86,7 @@ describe Instructeurs::GroupeInstructeursController, type: :controller do
end
context 'of a new instructeur' do
let(:new_instructeur_email) { 'new_instructeur@mail.com' }
let(:new_instructeur_email) { 'new_instructeur@gmail.com' }
before { subject }
it "works" do