feat(administrateurs/experts_procedures#create): avoid typo on expert
list management
This commit is contained in:
parent
9cbf1d3341
commit
2bb7584246
5 changed files with 88 additions and 22 deletions
21
app/components/procedure/invitation_with_typo_component.rb
Normal file
21
app/components/procedure/invitation_with_typo_component.rb
Normal 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
|
|
@ -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'}
|
|
@ -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
|
||||||
|
|
|
@ -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|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue