Add new type de champ expression_reguliere with tests

This commit is contained in:
Kara Diaby 2023-09-28 13:14:29 +00:00
parent c995a06434
commit 74c240ef66
9 changed files with 87 additions and 2 deletions

View file

@ -13,3 +13,8 @@ fr:
character_limit:
unlimited: Pas de limite de caractères
limit: Limité à %{limit} caractères
expression_reguliere:
labels:
regex: Saisissez votre expression régulière, essayez-la sur https://rubular.com
valid_exemple: Exemple valide qui passe l'expression régulière
error_message: Message d'erreur à afficher à l'usager en cas de saisie invalide

View file

@ -46,6 +46,23 @@
%p
%small Nous numérotons automatiquement les titres lorsquaucun de vos titres ne commence par un chiffre.
- if type_de_champ.expression_reguliere?
.cell.mt-1
= form.label :expression_reguliere, for: dom_id(type_de_champ, :expression_reguliere) do
= t('.expression_reguliere.labels.regex')
= form.text_field :expression_reguliere, class: "fr-input small-margin small", id: dom_id(type_de_champ, :expression_reguliere)
.cell.mt-1
= form.label :expression_reguliere_exemple_text, for: dom_id(type_de_champ, :expression_reguliere_exemple_text) do
= t('.expression_reguliere.labels.valid_exemple')
= form.text_field :expression_reguliere_exemple_text, class: "fr-input small-margin small", id: dom_id(type_de_champ, :expression_reguliere_exemple_text)
- if type_de_champ.invalid_regexp?
%p.fr-message.fr-message--error
= type_de_champ.errors[:expression_reguliere_exemple_text].join(", ")
.cell.mt-1
= form.label :expression_reguliere_error_message, for: dom_id(type_de_champ, :expression_reguliere_error_message) do
= t('.expression_reguliere.labels.error_message')
= form.text_field :expression_reguliere_error_message, class: "fr-input small-margin small", id: dom_id(type_de_champ, :expression_reguliere_error_message)
- if !type_de_champ.header_section? && !type_de_champ.titre_identite?
.cell.mt-1
= form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description)

View file

@ -130,6 +130,9 @@ module Administrateurs
:collapsible_explanation_text,
:header_section_level,
:character_limit,
:expression_reguliere,
:expression_reguliere_exemple_text,
:expression_reguliere_error_message,
editable_options: [
:cadastres,
:unesco,

View file

@ -55,7 +55,8 @@ class TypeDeChamp < ApplicationRecord
dgfip: REFERENTIEL_EXTERNE,
pole_emploi: REFERENTIEL_EXTERNE,
mesri: REFERENTIEL_EXTERNE,
cojo: REFERENTIEL_EXTERNE
cojo: REFERENTIEL_EXTERNE,
expression_reguliere: STANDARD
}
enum type_champs: {
@ -95,7 +96,8 @@ class TypeDeChamp < ApplicationRecord
pole_emploi: 'pole_emploi',
mesri: 'mesri',
epci: 'epci',
cojo: 'cojo'
cojo: 'cojo',
expression_reguliere: 'expression_reguliere'
}
ROUTABLE_TYPES = [
@ -116,6 +118,9 @@ class TypeDeChamp < ApplicationRecord
:drop_down_secondary_description,
:drop_down_other,
:character_limit,
:expression_reguliere,
:expression_reguliere_exemple_text,
:expression_reguliere_error_message,
:collapsible_explanation_enabled,
:collapsible_explanation_text,
:header_section_level
@ -184,6 +189,7 @@ class TypeDeChamp < ApplicationRecord
before_validation :check_mandatory
before_validation :normalize_libelle
before_save :remove_piece_justificative_template, if: -> { type_champ_changed? }
before_validation :remove_drop_down_list, if: -> { type_champ_changed? }
before_save :remove_block, if: -> { type_champ_changed? }
@ -414,6 +420,10 @@ class TypeDeChamp < ApplicationRecord
type_champ == TypeDeChamp.type_champs.fetch(:checkbox)
end
def expression_reguliere?
type_champ == TypeDeChamp.type_champs.fetch(:expression_reguliere)
end
def public?
!private?
end
@ -604,6 +614,24 @@ class TypeDeChamp < ApplicationRecord
type_champ.in?(ROUTABLE_TYPES)
end
def invalid_regexp?
return false if expression_reguliere.blank?
return false if expression_reguliere_exemple_text.blank?
begin
if expression_reguliere_exemple_text.match?(Regexp.new(expression_reguliere, timeout: 2.0))
return false
end
rescue Regexp::TimeoutError
self.errors.add(:expression_reguliere, I18n.t('errors.messages.evil_regexp'))
end
self.errors.add(:expression_reguliere_exemple_text, I18n.t('errors.messages.mismatch_regexp'))
true
rescue RegexpError
self.errors.add(:expression_reguliere, I18n.t('errors.messages.syntax_error_regexp'))
true
end
private
DEFAULT_EMPTY = ['']

View file

@ -0,0 +1,2 @@
class TypesDeChamp::ExpressionReguliereTypeDeChamp < TypesDeChamp::TypeDeChampBase
end

View file

@ -55,6 +55,7 @@ en:
mesri: "Data from Ministère de lEnseignement Supérieur, de la Recherche et de lInnovation"
epci: "EPCI"
cojo: "Accreditation Paris 2024"
expression_reguliere: 'Regular expression'
errors:
type_de_champ:
attributes:

View file

@ -55,6 +55,7 @@ fr:
mesri: "Données du Ministère de lEnseignement Supérieur, de la Recherche et de lInnovation"
epci: "EPCI"
cojo: "Accréditation Paris 2024"
expression_reguliere: 'Expression régulière'
errors:
type_de_champ:
attributes:

View file

@ -99,6 +99,9 @@ FactoryBot.define do
type_champ { TypeDeChamp.type_champs.fetch(:linked_drop_down_list) }
drop_down_list_value { "--primary--\nsecondary\n" }
end
factory :type_de_champ_expression_reguliere do
type_champ { TypeDeChamp.type_champs.fetch(:expression_reguliere) }
end
factory :type_de_champ_pays do
type_champ { TypeDeChamp.type_champs.fetch(:pays) }
end

View file

@ -166,6 +166,31 @@ describe TypeDeChamp do
end
end
describe "validate_regexp" do
let(:tdc) { create(:type_de_champ_expression_reguliere, expression_reguliere:, expression_reguliere_exemple_text:) }
subject { tdc.invalid_regexp? }
context "expression_reguliere and bad example" do
let(:expression_reguliere_exemple_text) { "01234567" }
let(:expression_reguliere) { "[A-Z]+" }
it "should add error message" do
expect(subject).to be_truthy
expect(tdc.errors.messages[:expression_reguliere_exemple_text]).to be_present
end
end
context "Bad expression_reguliere" do
let(:expression_reguliere_exemple_text) { "0123456789" }
let(:expression_reguliere) { "(" }
it "should add error message" do
expect(subject).to be_truthy
expect(tdc.errors.messages[:expression_reguliere]).to be_present
end
end
end
describe '#drop_down_list_options' do
let(:value) do
<<~EOS