feat(administrateurs/experts_procedures#create): avoid typo on expert

list management
This commit is contained in:
mfo 2024-06-14 11:36:58 +02:00
parent 9cbf1d3341
commit 2bb7584246
No known key found for this signature in database
GPG key ID: 7CE3E1F5B794A8EC
5 changed files with 88 additions and 22 deletions

View file

@ -0,0 +1,21 @@
class Procedure::InvitationWithTypoComponent < ApplicationComponent
def initialize(maybe_typo:, url:, params:, title:)
@maybe_typo = maybe_typo
@url = url
@params = params
@title = title
end
def render?
@maybe_typo.present?
end
def maybe_typos
email_checker = EmailChecker.new
@maybe_typo.map do |actual_email|
suggested_email = email_checker.check(email: actual_email)[:email_suggestions].first
[actual_email, suggested_email]
end
end
end

View file

@ -0,0 +1,10 @@
= render Dsfr::AlertComponent.new(title: "nous pensons avoir identifié une faute de frappe : ", state: :warning, extra_class_names: 'fr-mb-3w') do |c|
- c.with_body do
%p= @title
%ul
- maybe_typos.each do |(actual_email, suggested_email)|
%li
= "Je confirme "
= button_to "#{actual_email}", @url, method: :POST, params: @params.call(actual_email), class: 'fr-btn fr-btn--tertiary fr-btn--sm', form: {class: 'inline'}
= " ou "
= button_to "#{suggested_email}", @url, method: :POST, params: @params.call(suggested_email), class: 'fr-btn fr-btn--tertiary fr-btn--sm', form: {class: 'inline'}

View file

@ -1,25 +1,31 @@
module Administrateurs module Administrateurs
class ExpertsProceduresController < AdministrateurController class ExpertsProceduresController < AdministrateurController
include EmailSanitizableConcern
before_action :retrieve_procedure before_action :retrieve_procedure
before_action :retrieve_experts_procedure, only: [:index, :create]
before_action :retrieve_experts_emails, only: [:index, :create]
def index def index
@experts_procedure = @procedure
.experts_procedures
.where(revoked_at: nil)
.sort_by { |expert_procedure| expert_procedure.expert.email }
@experts_emails = experts_procedure_emails
end end
def create def create
emails = params['emails'].presence || [].to_json emails = params['emails'].presence || [].to_json
emails = JSON.parse(emails).map(&:strip).map(&:downcase) @maybe_typo, emails = JSON.parse(emails)
.map { EmailSanitizer.sanitize(_1) }
.partition { EmailChecker.new.check(email: _1)[:email_suggestions].present? }
errors = if !@maybe_typo.empty?
["Attention, nous pensons avoir identifié une faute de frappe dans les invitations : #{@maybe_typo.join(', ')}"]
else
[]
end
emails += [EmailSanitizer.sanitize(params['maybe_typo'])] if params['maybe_typo'].present?
valid_users, invalid_users = emails valid_users, invalid_users = emails
.map { |email| User.create_or_promote_to_expert(email, SecureRandom.hex) } .map { |email| User.create_or_promote_to_expert(email, SecureRandom.hex) }
.partition(&:valid?) .partition(&:valid?)
if invalid_users.any? if invalid_users.any?
flash[:alert] = invalid_users errors += invalid_users
.filter { |user| user.errors.present? } .filter { |user| user.errors.present? }
.map { |user| "#{user.email} : #{user.errors.full_messages_for(:email).join(', ')}" } .map { |user| "#{user.email} : #{user.errors.full_messages_for(:email).join(', ')}" }
end end
@ -37,7 +43,9 @@ module Administrateurs
value: valid_users.map(&:email).join(', '), value: valid_users.map(&:email).join(', '),
procedure: @procedure.id) procedure: @procedure.id)
end end
redirect_to admin_procedure_experts_path(@procedure)
flash[:alert] = errors.join(". ") if !errors.empty?
render :index
end end
def update def update
@ -57,8 +65,12 @@ module Administrateurs
private private
def experts_procedure_emails def retrieve_experts_procedure
@procedure.experts.map(&:email).sort @experts_procedure ||= @procedure.experts_procedures.where(revoked_at: nil).sort_by { _1.expert.email }
end
def retrieve_experts_emails
@experts_emails ||= @experts_procedure.map { _1.expert.email }
end end
def expert_procedure_params def expert_procedure_params

View file

@ -58,6 +58,7 @@
- if @procedure.experts_require_administrateur_invitation? - if @procedure.experts_require_administrateur_invitation?
.card .card
= render Procedure::InvitationWithTypoComponent.new(maybe_typo: @maybe_typo, url: admin_procedure_experts_path(@procedure), params: ->(email) { { maybe_typo: email } }, title: "Avant d'ajouter l'email à la liste d'expert prédéfinie, veuillez confirmer" )
= form_for :experts_procedure, = form_for :experts_procedure,
url: admin_procedure_experts_path(@procedure), url: admin_procedure_experts_path(@procedure),
html: { class: 'form' } do |f| html: { class: 'form' } do |f|

View file

@ -21,23 +21,45 @@ describe Administrateurs::ExpertsProceduresController, type: :controller do
describe '#create' do describe '#create' do
let(:expert) { create(:expert) } let(:expert) { create(:expert) }
let(:expert2) { create(:expert) } let(:expert2) { create(:expert) }
let(:procedure) { create :procedure, administrateur: admin, experts_require_administrateur_invitation: true }
subject do subject { post :create, params: params }
post :create, params: { before { subject }
procedure_id: procedure.id,
emails: "[\"#{expert.email}\",\"#{expert2.email}\"]" context 'when inviting multiple valid experts' do
} let(:params) { { procedure_id: procedure.id, emails: [expert.email, expert2.email].to_json } }
it 'creates experts' do
expect(procedure.experts.include?(expert)).to be_truthy
expect(procedure.experts.include?(expert2)).to be_truthy
expect(flash.notice).to be_present
expect(assigns(:maybe_typo)).to eq([])
expect(response).to have_http_status(:success)
end
end end
before do context 'when inviting expert using an email with typos' do
subject let(:params) { { procedure_id: procedure.id, emails: ['martin@oraneg.fr'].to_json } }
render_views
it 'warns' do
expect(flash.alert).to be_present
expect(assigns(:maybe_typo)).to eq(['martin@oraneg.fr'])
expect(response).to have_http_status(:success)
end
end end
context 'of multiple experts' do context 'when forcing email with typos' do
it { expect(procedure.experts.include?(expert)).to be_truthy } let(:maybe_typo) { 'martin@oraneg.fr' }
it { expect(procedure.experts.include?(expert2)).to be_truthy } let(:params) { { procedure_id: procedure.id, maybe_typo: } }
it { expect(flash.notice).to be_present }
it { expect(response).to redirect_to(admin_procedure_experts_path(procedure)) } it 'works' do
created_user = User.where(email: maybe_typo).first
expect(created_user).to be_an_instance_of(User)
expect(created_user.expert).to be_an_instance_of(Expert)
expect(procedure.experts.include?(created_user.expert)).to be_truthy
expect(flash.notice).to be_present
expect(response).to have_http_status(:success)
end
end end
end end