Skip to content

Commit

Permalink
refactor: validateur custom pour les numéros ANTS
Browse files Browse the repository at this point in the history
  • Loading branch information
adipasquale committed Nov 20, 2024
1 parent 519cbad commit 94aec7d
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 74 deletions.
12 changes: 2 additions & 10 deletions app/form_models/admin/user_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,9 @@ class Admin::UserForm

validate :validate_duplicates

delegate :ignore_benign_errors, :ignore_benign_errors=, :add_benign_error, :benign_errors, :not_benign_errors, :errors_are_all_benign?, to: :user
delegate :ants_pre_demande_number, :ignore_benign_errors, :ignore_benign_errors=, :add_benign_error, :benign_errors, :not_benign_errors, :errors_are_all_benign?, to: :user
validate :warn_duplicates
validate do
if @user.ants_pre_demande_number.present?
ValidateAntsPreDemandeNumber.perform(
user: @user,
ants_pre_demande_number: @user.ants_pre_demande_number,
ignore_benign_errors: ignore_benign_errors
)
end
end
validates_with AntsPreDemandeNumberValidation, if: -> { @user.ants_pre_demande_number.present? }

delegate :errors, to: :user

Expand Down
14 changes: 5 additions & 9 deletions app/form_models/beneficiaire_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,7 @@ class BeneficiaireForm
validates_presence_of :first_name, :last_name
validate :warn_no_contact_information
validate :validate_phone_number
validate do
if Motif.find_by(id: motif_id)&.requires_ants_predemande_number?
ValidateAntsPreDemandeNumber.perform(
user: self,
ants_pre_demande_number: ants_pre_demande_number,
ignore_benign_errors: ignore_benign_errors
)
end
end
validates_with AntsPreDemandeNumberValidation, if: :requires_ants_predemande_number?

def warn_no_contact_information
return if ignore_benign_errors
Expand All @@ -39,4 +31,8 @@ def validate_phone_number
errors.add(:phone_number, :invalid) if PhoneNumberValidation.parsed_number(phone_number).blank?
errors.add(:phone_number, "ne permet pas de recevoir des SMS") unless PhoneNumberValidation.number_is_mobile?(phone_number)
end

def requires_ants_predemande_number?
Motif.find_by(id: motif_id)&.requires_ants_predemande_number?
end
end
23 changes: 11 additions & 12 deletions app/form_models/user_rdv_wizard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,28 @@ class Step1 < Base
delegate :errors, to: :user

validate :phone_number_present_for_motif_by_phone
validate do
if rdv.requires_ants_predemande_number?
ValidateAntsPreDemandeNumber.perform(
user: @user,
ants_pre_demande_number: @user_attributes[:ants_pre_demande_number],
ignore_benign_errors: @user_attributes[:ignore_benign_errors]
)
end
end

def phone_number_present_for_motif_by_phone
errors.add(:phone_number, :missing_for_phone_motif) if rdv.motif.phone? && @user_attributes[:phone_number].blank?
errors.add(:phone_number, :missing_for_phone_motif) if rdv.motif.phone? && user.phone_number.blank?
end

def initialize(user, attributes)
super
@user_attributes = @attributes[:user]&.with_indifferent_access
@user&.assign_attributes(@attributes.fetch(:user, {}))
end

def save
# we make sure the email can be updated only if it is blank
@user.skip_reconfirmation! if @user.email_was.blank?
valid? && @user.update(@user_attributes)

# dans la vue on appelle form_for(user) plutôt que form_for(user_rdv_wizard) les erreurs doivent donc être
# définies sur le user et on ne peut pas simplement appeler `validates_with AntsPreDemandeNumberValidation`
# dans ce form model
if rdv.requires_ants_predemande_number?
@user.singleton_class.validates_with(AntsPreDemandeNumberValidation)
end

valid? && @user.save
end
end

Expand Down
40 changes: 0 additions & 40 deletions app/services/validate_ants_pre_demande_number.rb

This file was deleted.

43 changes: 43 additions & 0 deletions app/validators/ants_pre_demande_number_validation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Cette validation ne peut être utilisée que si le record (ou le form model)
# a un attribut ants_pre_demande_number et inclut le module BenignErrors
#
# Cette validation fait des requêtes HTTP externes à l’API de l’ANTS
#
# cf /docs/interconnexions/ants.md

class AntsPreDemandeNumberValidation < ActiveModel::Validator
def validate(record)
ants_pre_demande_number = record.ants_pre_demande_number.upcase

unless ants_pre_demande_number.match?(/\A[A-Z0-9]{10}\z/)
record.errors.add(:ants_pre_demande_number, "doit comporter 10 chiffres et lettres")
return
end

application_hash = AntsApi.status(ants_pre_demande_number:, timeout: 4)

status = application_hash["status"]

if status == "validated"
if application_hash["appointments"].any?
appointment = OpenStruct.new(application_hash["appointments"].first)
record.add_benign_error(warning_message(appointment)) unless record.ignore_benign_errors
end
else
record.errors.add(:ants_pre_demande_number, AntsApi::ERROR_STATUSES.fetch(status))
end
rescue AntsApi::ApiRequestError, Typhoeus::Errors::TimeoutError => e
# Si l'API de l'ANTS est fiable, donc si elle renvoie une erreur ou un timeout,
# on préfère bloquer la réservation et logguer l'erreur.
record.errors.add(:ants_pre_demande_number, "n'a pas pu être validé à cause d'une erreur inattendue. Merci de réessayer dans 30 secondes.")
Sentry.capture_exception(e)
end

def warning_message(appointment)
I18n.t(
"activerecord.warnings.models.user.ants_pre_demande_number_already_used_html",
management_url: appointment.management_url,
meeting_point: appointment.meeting_point
).html_safe
end
end
6 changes: 3 additions & 3 deletions spec/form_models/user_rdv_wizard_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
expect(form.errors.first.attribute).to eq(:ants_pre_demande_number)
expect(form.errors.first.message).to eq("doit comporter 10 chiffres et lettres")
# le message affiché est en fait celui sur le user
expect(form.user.errors.first.full_message).to eq("Numéro de pré-demande ANTS doit comporter 10 chiffres et lettres")
expect(form.errors.first.full_message).to eq("Numéro de pré-demande ANTS doit comporter 10 chiffres et lettres")
end
end

Expand Down Expand Up @@ -147,7 +147,7 @@
expect(res).to be false
expect(form.errors.count).to eq(1)
expect(form.errors.first.attribute).to eq(:ants_pre_demande_number)
expect(form.user.errors.first.full_message).to eq("Numéro de pré-demande ANTS n'est pas reconnu par l'ANTS")
expect(form.errors.first.full_message).to eq("Numéro de pré-demande ANTS n'est pas reconnu par l'ANTS")
end
end

Expand Down Expand Up @@ -252,7 +252,7 @@
expect(res).to be false
expect(form.errors.count).to eq(1)
expect(form.errors.first.attribute).to eq(:ants_pre_demande_number)
expect(form.user.errors.first.full_message).to eq("Numéro de pré-demande ANTS n'a pas pu être validé à cause d'une erreur inattendue. Merci de réessayer dans 30 secondes.")
expect(form.errors.first.full_message).to eq("Numéro de pré-demande ANTS n'a pas pu être validé à cause d'une erreur inattendue. Merci de réessayer dans 30 secondes.")
end
end
end
Expand Down

0 comments on commit 94aec7d

Please sign in to comment.