Merge pull request #6840 from betagouv/fix-champs-validation-for-private-champs

Administrateur : sépare la validation des champs publics et des annotations privées
This commit is contained in:
Pierre de La Morinerie 2022-02-01 12:41:23 +01:00 committed by GitHub
commit 70cbdcacc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 64 additions and 38 deletions

View file

@ -245,9 +245,13 @@ class Procedure < ApplicationRecord
validates :description, presence: true, allow_blank: false, allow_nil: false
validates :administrateurs, presence: true
validates :lien_site_web, presence: true, if: :publiee?
validates :draft_revision,
'revisions/no_empty_repetition': true,
'revisions/no_empty_drop_down': true,
validates :draft_types_de_champ,
'types_de_champ/no_empty_repetition': true,
'types_de_champ/no_empty_drop_down': true,
if: :validate_for_publication?
validates :draft_types_de_champ_private,
'types_de_champ/no_empty_repetition': true,
'types_de_champ/no_empty_drop_down': true,
if: :validate_for_publication?
validate :check_juridique
validates :path, presence: true, format: { with: /\A[a-z0-9_\-]{3,200}\z/ }, uniqueness: { scope: [:path, :closed_at, :hidden_at, :unpublished_at], case_sensitive: false }

View file

@ -1,10 +1,6 @@
class Revisions::NoEmptyDropDownValidator < ActiveModel::EachValidator
def validate_each(procedure, attribute, revision)
return if revision.nil?
tdcs = revision.types_de_champ + revision.types_de_champ_private
drop_downs = tdcs.filter(&:drop_down_list?)
drop_downs.each do |drop_down|
class TypesDeChamp::NoEmptyDropDownValidator < ActiveModel::EachValidator
def validate_each(procedure, attribute, types_de_champ)
types_de_champ.filter(&:drop_down_list?).each do |drop_down|
validate_drop_down_not_empty(procedure, attribute, drop_down)
end
end

View file

@ -1,10 +1,6 @@
class Revisions::NoEmptyRepetitionValidator < ActiveModel::EachValidator
def validate_each(procedure, attribute, revision)
return if revision.nil?
revision_tdcs = revision.types_de_champ + revision.types_de_champ_private
repetitions = revision_tdcs.filter(&:repetition?)
repetitions.each do |repetition|
class TypesDeChamp::NoEmptyRepetitionValidator < ActiveModel::EachValidator
def validate_each(procedure, attribute, types_de_champ)
types_de_champ.filter(&:repetition?).each do |repetition|
validate_repetition_not_empty(procedure, attribute, repetition)
end
end

View file

@ -53,7 +53,7 @@
- if !@procedure.locked? || @procedure.feature_enabled?(:procedure_revisions)
- @procedure.validate(:publication)
- error_messages = @procedure.errors.messages_for(:draft_revision).to_sentence
- error_messages = @procedure.errors.messages_for(:draft_types_de_champ).to_sentence
= link_to champs_admin_procedure_path(@procedure), class: 'card-admin', title: error_messages do
- if @procedure.draft_types_de_champ.count == 0
@ -171,11 +171,18 @@
%p.button Modifier
- if !@procedure.locked? || @procedure.feature_enabled?(:procedure_revisions)
= link_to annotations_admin_procedure_path(@procedure), class: 'card-admin' do
- @procedure.validate(:publication)
- error_messages = @procedure.errors.messages_for(:draft_types_de_champ_private).to_sentence
= link_to annotations_admin_procedure_path(@procedure), class: 'card-admin', title: error_messages do
- if @procedure.draft_types_de_champ_private.present?
%div
%span.icon.accept
%p.card-admin-status-accept Validé
- elsif error_messages.present?
%div
%span.icon.refuse
%p.card-admin-status-error À modifier
- else
%div
%span.icon.clock

View file

@ -328,8 +328,8 @@ fr:
connexion: "Erreur lors de la connexion à France Connect."
forbidden_html: "Seul-e-s les usagers peuvent se connecter via France Connect. En tant quinstructeur ou administrateur, nous vous invitons à <a href='%{reset_link}'>réininitialiser votre mot de passe</a>."
procedure_archived: "Cette démarche en ligne a été close, il nest plus possible de déposer de dossier."
empty_repetition: 'Le bloc répétable « %{value} » doit comporter au moins un champ'
empty_drop_down: 'La liste de choix « %{value} » doit comporter au moins un choix sélectionnable'
empty_repetition: '« %{value} » doit comporter au moins un champ répétable'
empty_drop_down: '« %{value} » doit comporter au moins un choix sélectionnable'
# procedure_not_draft: "Cette démarche nest maintenant plus en brouillon."
cadastres_empty:
one: "Aucune parcelle cadastrale sur la zone sélectionnée"

View file

@ -23,5 +23,7 @@ fr:
attributes:
api_particulier_token:
invalid: 'na pas le bon format'
draft_revision:
format: '%{message}'
draft_types_de_champ:
format: 'Le champ %{message}'
draft_types_de_champ_private:
format: 'Lannotation privée %{message}'

View file

@ -299,20 +299,20 @@ describe Procedure do
it_behaves_like 'duree de conservation'
end
describe 'draft_revision' do
describe 'draft_types_de_champ validations' do
let(:repetition) { build(:type_de_champ_repetition, libelle: 'Enfants') }
let(:text_field) { build(:type_de_champ_text) }
let(:invalid_repetition_error_message) { 'Le bloc répétable « Enfants » doit comporter au moins un champ' }
let(:invalid_repetition_error_message) { 'Le champ « Enfants » doit comporter au moins un champ répétable' }
let(:drop_down) { build(:type_de_champ_drop_down_list, :without_selectable_values, libelle: 'Civilité') }
let(:invalid_drop_down_error_message) { 'La liste de choix « Civilité » doit comporter au moins un choix sélectionnable' }
let(:invalid_drop_down_error_message) { 'Le champ « Civilité » doit comporter au moins un choix sélectionnable' }
let(:procedure) { create(:procedure, types_de_champ: [repetition, drop_down]) }
context 'on a draft procedure' do
it 'doesnt validate the draft revision' do
it 'doesnt validate the types de champs' do
procedure.validate
expect(procedure.errors[:draft_revision]).not_to be_present
expect(procedure.errors[:draft_types_de_champ]).not_to be_present
end
end
@ -321,35 +321,52 @@ describe Procedure do
it 'validates that no repetition type de champ is empty' do
procedure.validate
expect(procedure.errors.full_messages_for(:draft_revision)).to include(invalid_repetition_error_message)
expect(procedure.errors.full_messages_for(:draft_types_de_champ)).to include(invalid_repetition_error_message)
text_field.revision = repetition.revision
text_field.order_place = repetition.types_de_champ.size
procedure.draft_revision.types_de_champ.find(&:repetition?).types_de_champ << text_field
procedure.draft_types_de_champ.find(&:repetition?).types_de_champ << text_field
procedure.validate
expect(procedure.errors.full_messages_for(:draft_revision)).not_to include(invalid_repetition_error_message)
expect(procedure.errors.full_messages_for(:draft_types_de_champ)).not_to include(invalid_repetition_error_message)
end
it 'validates that no drop-down type de champ is empty' do
procedure.validate
expect(procedure.errors.full_messages_for(:draft_revision)).to include(invalid_drop_down_error_message)
expect(procedure.errors.full_messages_for(:draft_types_de_champ)).to include(invalid_drop_down_error_message)
drop_down.update!(drop_down_list_value: "--title--\r\nsome value")
procedure.reload.validate
expect(procedure.errors.full_messages_for(:draft_revision)).not_to include(invalid_drop_down_error_message)
expect(procedure.errors.full_messages_for(:draft_types_de_champ)).not_to include(invalid_drop_down_error_message)
end
end
context 'when validating for publication' do
it 'validates that no repetition type de champ is empty' do
procedure.validate(:publication)
expect(procedure.errors.full_messages_for(:draft_revision)).to include(invalid_repetition_error_message)
expect(procedure.errors.full_messages_for(:draft_types_de_champ)).to include(invalid_repetition_error_message)
end
it 'validates that no drop-down type de champ is empty' do
procedure.validate(:publication)
expect(procedure.errors.full_messages_for(:draft_revision)).to include(invalid_drop_down_error_message)
expect(procedure.errors.full_messages_for(:draft_types_de_champ)).to include(invalid_drop_down_error_message)
end
end
context 'when the champ is private' do
let(:procedure) { create(:procedure, types_de_champ_private: [repetition, drop_down]) }
let(:invalid_repetition_error_message) { 'Lannotation privée « Enfants » doit comporter au moins un champ répétable' }
let(:invalid_drop_down_error_message) { 'Lannotation privée « Civilité » doit comporter au moins un choix sélectionnable' }
it 'validates that no repetition type de champ is empty' do
procedure.validate(:publication)
expect(procedure.errors.full_messages_for(:draft_types_de_champ_private)).to include(invalid_repetition_error_message)
end
it 'validates that no drop-down type de champ is empty' do
procedure.validate(:publication)
expect(procedure.errors.full_messages_for(:draft_types_de_champ_private)).to include(invalid_drop_down_error_message)
end
end
end

View file

@ -47,19 +47,23 @@ describe 'Publishing a procedure', js: true do
end
context 'when the procedure has invalid champs' do
let(:empty_repetition) { build(:type_de_champ_repetition, types_de_champ: []) }
let(:empty_repetition) { build(:type_de_champ_repetition, types_de_champ: [], libelle: 'Enfants') }
let(:empty_drop_down) { build(:type_de_champ_drop_down_list, :without_selectable_values, libelle: 'Civilité') }
let!(:procedure) do
create(:procedure,
:with_path,
:with_service,
instructeurs: instructeurs,
administrateur: administrateur,
types_de_champ: [empty_repetition])
types_de_champ: [empty_repetition],
types_de_champ_private: [empty_drop_down])
end
scenario 'an error message prevents the publication' do
expect(page).to have_content('Des problèmes empêchent la publication de la démarche')
expect(page).to have_content("Le bloc répétable « #{empty_repetition.libelle} » doit comporter au moins un champ")
expect(page).to have_content("Le champ « Enfants » doit comporter au moins un champ répétable")
expect(page).to have_content("Lannotation privée « Civilité » doit comporter au moins un choix sélectionnable")
expect(find_field('procedure_path').value).to eq procedure.path
fill_in 'lien_site_web', with: 'http://some.website'