feat(procedure.validation): extract validation context: types_de_champ_public_editor, types_de_champ_private_editor and publication [combining both contextes]. validate conditions, headers_sections, regexp on type_de_champ_private too. dry validation
This commit is contained in:
parent
f508921d2f
commit
ef3ca9839b
37 changed files with 398 additions and 221 deletions
|
@ -7,9 +7,6 @@ class Procedure::Card::ChampsComponent < ApplicationComponent
|
||||||
private
|
private
|
||||||
|
|
||||||
def error_messages
|
def error_messages
|
||||||
[
|
@procedure.errors.messages_for(:draft_types_de_champ_public).to_sentence
|
||||||
@procedure.errors.messages_for(:draft_types_de_champ_public),
|
|
||||||
@procedure.errors.messages_for(:draft_revision)
|
|
||||||
].flatten.to_sentence
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
48
app/components/procedure/errors_summary.rb
Normal file
48
app/components/procedure/errors_summary.rb
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
class Procedure::ErrorsSummary < ApplicationComponent
|
||||||
|
def initialize(procedure:, validation_context:)
|
||||||
|
@procedure = procedure
|
||||||
|
@validation_context = validation_context
|
||||||
|
end
|
||||||
|
|
||||||
|
def title
|
||||||
|
case @validation_context
|
||||||
|
when :types_de_champ_private_editor
|
||||||
|
"Les annotations privées contiennent des erreurs"
|
||||||
|
when :types_de_champ_public_editor
|
||||||
|
"Les champs formulaire contiennent des erreurs"
|
||||||
|
when :publication
|
||||||
|
if @procedure.publiee?
|
||||||
|
"Des problèmes empêchent la publication des modifications"
|
||||||
|
else
|
||||||
|
"Des problèmes empêchent la publication de la démarche"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def invalid?
|
||||||
|
@procedure.validate(@validation_context)
|
||||||
|
@procedure.errors.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def error_messages
|
||||||
|
@procedure.errors.map do |error|
|
||||||
|
[error, error_correction_page(error)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def error_correction_page(error)
|
||||||
|
case error.attribute
|
||||||
|
when :draft_types_de_champ_public
|
||||||
|
tdc = error.options[:type_de_champ]
|
||||||
|
champs_admin_procedure_path(@procedure, anchor: dom_id(tdc.stable_self, :editor_error))
|
||||||
|
when :draft_types_de_champ_private
|
||||||
|
tdc = error.options[:type_de_champ]
|
||||||
|
annotations_admin_procedure_path(@procedure, anchor: dom_id(tdc.stable_self, :editor_error))
|
||||||
|
when :attestation_template
|
||||||
|
edit_admin_procedure_attestation_template_path(@procedure)
|
||||||
|
when :initiated_mail, :received_mail, :closed_mail, :refused_mail, :without_continuation_mail, :re_instructed_mail
|
||||||
|
klass = "Mails::#{error.attribute.to_s.classify}".constantize
|
||||||
|
edit_admin_procedure_mail_template_path(@procedure, klass.const_get(:SLUG))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
#errors-summary
|
||||||
|
- if invalid?
|
||||||
|
= render Dsfr::AlertComponent.new(state: :error, title: , extra_class_names: 'fr-mb-2w') do |c|
|
||||||
|
- c.with_body do
|
||||||
|
- error_messages.each do |(error, path)|
|
||||||
|
%p.mt-2
|
||||||
|
= error.full_message
|
||||||
|
- if path.present?
|
||||||
|
= "(#{link_to 'corriger', path, class: 'fr-link'})"
|
|
@ -1,39 +0,0 @@
|
||||||
class Procedure::PublicationWarningComponent < ApplicationComponent
|
|
||||||
def initialize(procedure:)
|
|
||||||
@procedure = procedure
|
|
||||||
end
|
|
||||||
|
|
||||||
def title
|
|
||||||
return "Des problèmes empêchent la publication des modifications" if @procedure.publiee?
|
|
||||||
|
|
||||||
"Des problèmes empêchent la publication de la démarche"
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def render?
|
|
||||||
@procedure.validate(:publication)
|
|
||||||
@procedure.errors.delete(:path)
|
|
||||||
@procedure.errors.any?
|
|
||||||
end
|
|
||||||
|
|
||||||
def error_messages
|
|
||||||
@procedure.errors
|
|
||||||
.to_hash(full_messages: true)
|
|
||||||
.map do |attribute, messages|
|
|
||||||
[messages, error_correction_page(attribute)]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def error_correction_page(attribute)
|
|
||||||
case attribute
|
|
||||||
when :draft_revision
|
|
||||||
champs_admin_procedure_path(@procedure)
|
|
||||||
when :attestation_template
|
|
||||||
edit_admin_procedure_attestation_template_path(@procedure)
|
|
||||||
when :initiated_mail, :received_mail, :closed_mail, :refused_mail, :without_continuation_mail, :re_instructed_mail
|
|
||||||
klass = "Mails::#{attribute.to_s.classify}".constantize
|
|
||||||
edit_admin_procedure_mail_template_path(@procedure, klass.const_get(:SLUG))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,7 +0,0 @@
|
||||||
= render Dsfr::AlertComponent.new(state: :warning, title:) do |c|
|
|
||||||
- c.with_body do
|
|
||||||
- error_messages.each do |(messages, path)|
|
|
||||||
%p.mt-2
|
|
||||||
= messages.to_sentence
|
|
||||||
- if path.present?
|
|
||||||
= "(#{link_to 'corriger', path, class: 'fr-link'})"
|
|
|
@ -1,5 +1,5 @@
|
||||||
%li.type-de-champ.flex.column.justify-start.fr-mb-5v{ html_options }
|
%li.type-de-champ.flex.column.justify-start.fr-mb-5v{ html_options }
|
||||||
.type-de-champ-container
|
.type-de-champ-container{ id: dom_id(type_de_champ.stable_self, :editor_error) }
|
||||||
- if @errors.present?
|
- if @errors.present?
|
||||||
.types-de-champ-errors
|
.types-de-champ-errors
|
||||||
= @errors
|
= @errors
|
||||||
|
|
|
@ -17,4 +17,12 @@ class TypesDeChampEditor::EditorComponent < ApplicationComponent
|
||||||
@revision.revision_types_de_champ_public
|
@revision.revision_types_de_champ_public
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validation_context
|
||||||
|
if annotations?
|
||||||
|
:types_de_champ_private_editor
|
||||||
|
else
|
||||||
|
:types_de_champ_public_editor
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.fr-pb-12w{ 'data-turbo': 'true', id: dom_id(@revision, :types_de_champ_editor) }
|
.fr-pb-12w{ 'data-turbo': 'true', id: dom_id(@revision, :types_de_champ_editor) }
|
||||||
.types-de-champ-editor.editor-root
|
.types-de-champ-editor.editor-root
|
||||||
= render TypesDeChampEditor::ErrorsSummary.new(revision: @revision)
|
= render Procedure::ErrorsSummary.new(procedure: @revision.procedure, validation_context:)
|
||||||
= render TypesDeChampEditor::BlockComponent.new(block: @revision, coordinates: coordinates)
|
= render TypesDeChampEditor::BlockComponent.new(block: @revision, coordinates: coordinates)
|
||||||
#empty-coordinates{ hidden: coordinates.present? }
|
#empty-coordinates{ hidden: coordinates.present? }
|
||||||
= render TypesDeChampEditor::AddChampButtonComponent.new(revision: @revision, is_annotation: annotations?)
|
= render TypesDeChampEditor::AddChampButtonComponent.new(revision: @revision, is_annotation: annotations?)
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
class TypesDeChampEditor::ErrorsSummary < ApplicationComponent
|
|
||||||
def initialize(revision:)
|
|
||||||
@revision = revision
|
|
||||||
end
|
|
||||||
|
|
||||||
def invalid?
|
|
||||||
@revision.invalid?
|
|
||||||
end
|
|
||||||
|
|
||||||
def condition_errors?
|
|
||||||
@revision.errors.include?(:condition)
|
|
||||||
end
|
|
||||||
|
|
||||||
def header_section_errors?
|
|
||||||
@revision.errors.include?(:header_section)
|
|
||||||
end
|
|
||||||
|
|
||||||
def expression_reguliere_errors?
|
|
||||||
@revision.errors.include?(:expression_reguliere)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def errors_for(key)
|
|
||||||
@revision.errors.filter { _1.attribute == key }
|
|
||||||
end
|
|
||||||
|
|
||||||
def error_message_for(key)
|
|
||||||
errors_for(key)
|
|
||||||
.map { |error| error.options[:type_de_champ] }
|
|
||||||
.map { |tdc| tag.li(tdc_anchor(tdc, key)) }
|
|
||||||
.then { |lis| tag.ul(lis.reduce(&:+)) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def tdc_anchor(tdc, key)
|
|
||||||
tag.a(tdc.libelle, href: champs_admin_procedure_path(@revision.procedure_id, anchor: dom_id(tdc.stable_self, key)), data: { turbo: false })
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,12 +0,0 @@
|
||||||
fr:
|
|
||||||
fix_conditional:
|
|
||||||
one: 'La logique conditionnelle du champ suivant est invalide, veuillez la corriger :'
|
|
||||||
other: 'La logique conditionnelle des champs suivants sont invalides, veuillez les corriger :'
|
|
||||||
|
|
||||||
fix_header_section:
|
|
||||||
one: 'Le titre de section suivant est invalide, veuillez le corriger :'
|
|
||||||
other: 'Les titres de section suivants sont invalides, veuillez les corriger :'
|
|
||||||
|
|
||||||
fix_expressions_regulieres:
|
|
||||||
one: "L'expression régulière suivante est invalide, veuillez la corriger :"
|
|
||||||
other: 'Les expressions régulières suivantes sont invalides, veuillez les corriger :'
|
|
|
@ -1,15 +0,0 @@
|
||||||
#errors-summary
|
|
||||||
- if invalid?
|
|
||||||
= render Dsfr::AlertComponent.new(state: :warning, title: "Le formulaire contient des erreurs", extra_class_names: 'fr-mb-2w') do |c|
|
|
||||||
- c.with_body do
|
|
||||||
- if condition_errors?
|
|
||||||
%p= t('.fix_conditional', count: errors_for(:condition).size)
|
|
||||||
= error_message_for(:condition)
|
|
||||||
|
|
||||||
- if header_section_errors?
|
|
||||||
%p= t('.fix_header_section', count: errors_for(:header_section).size)
|
|
||||||
= error_message_for(:header_section)
|
|
||||||
|
|
||||||
- if expression_reguliere_errors?
|
|
||||||
%p= t('.fix_expressions_regulieres', count: errors_for(:expression_reguliere).size)
|
|
||||||
= error_message_for(:expression_reguliere)
|
|
|
@ -31,7 +31,7 @@ class TypesDeChampEditor::HeaderSectionComponent < ApplicationComponent
|
||||||
end
|
end
|
||||||
|
|
||||||
def errors?
|
def errors?
|
||||||
!errors.empty?
|
errors.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_html_list(messages)
|
def to_html_list(messages)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
%div{ id: dom_id(@tdc.stable_self, :header_section) }
|
%div{ id: dom_id(@tdc.stable_self, :header_section) }
|
||||||
- if errors?
|
- if errors?
|
||||||
.errors-summary= to_html_list(errors)
|
.errors-summary= errors
|
||||||
= @form.label :header_section_level, "Niveau du titre", for: dom_id(@tdc, :header_section_level)
|
= @form.label :header_section_level, "Niveau du titre", for: dom_id(@tdc, :header_section_level)
|
||||||
= @form.select :header_section_level, header_section_options_for_select, {}, id: dom_id(@tdc, :header_section_level), class: 'fr-select width-33'
|
= @form.select :header_section_level, header_section_options_for_select, {}, id: dom_id(@tdc, :header_section_level), class: 'fr-select width-33'
|
||||||
|
|
|
@ -259,13 +259,19 @@ class Procedure < ApplicationRecord
|
||||||
validates :lien_dpo, url: { no_local: true, allow_blank: true, accept_email: true }
|
validates :lien_dpo, url: { no_local: true, allow_blank: true, accept_email: true }
|
||||||
|
|
||||||
validates :draft_types_de_champ_public,
|
validates :draft_types_de_champ_public,
|
||||||
|
'types_de_champ/condition': true,
|
||||||
|
'types_de_champ/expression_reguliere': true,
|
||||||
|
'types_de_champ/header_section_consistency': true,
|
||||||
'types_de_champ/no_empty_block': true,
|
'types_de_champ/no_empty_block': true,
|
||||||
'types_de_champ/no_empty_drop_down': true,
|
'types_de_champ/no_empty_drop_down': true,
|
||||||
on: :publication
|
on: [:types_de_champ_public_editor, :publication]
|
||||||
|
|
||||||
validates :draft_types_de_champ_private,
|
validates :draft_types_de_champ_private,
|
||||||
|
'types_de_champ/condition': true,
|
||||||
|
'types_de_champ/header_section_consistency': true,
|
||||||
'types_de_champ/no_empty_block': true,
|
'types_de_champ/no_empty_block': true,
|
||||||
'types_de_champ/no_empty_drop_down': true,
|
'types_de_champ/no_empty_drop_down': true,
|
||||||
on: :publication
|
on: [:types_de_champ_private_editor, :publication]
|
||||||
|
|
||||||
validate :check_juridique, on: [:create, :publication]
|
validate :check_juridique, on: [:create, :publication]
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,6 @@ class ProcedureRevision < ApplicationRecord
|
||||||
|
|
||||||
scope :ordered, -> { order(:created_at) }
|
scope :ordered, -> { order(:created_at) }
|
||||||
|
|
||||||
validate :conditions_are_valid?
|
|
||||||
validate :header_sections_are_valid?
|
|
||||||
validate :expressions_regulieres_are_valid?
|
|
||||||
|
|
||||||
delegate :path, to: :procedure, prefix: true
|
delegate :path, to: :procedure, prefix: true
|
||||||
|
|
||||||
def build_champs_public
|
def build_champs_public
|
||||||
|
@ -453,48 +449,4 @@ class ProcedureRevision < ApplicationRecord
|
||||||
coordinate.update!(type_de_champ: cloned_type_de_champ)
|
coordinate.update!(type_de_champ: cloned_type_de_champ)
|
||||||
cloned_type_de_champ
|
cloned_type_de_champ
|
||||||
end
|
end
|
||||||
|
|
||||||
def conditions_are_valid?
|
|
||||||
public_tdcs = types_de_champ_public.to_a
|
|
||||||
.flat_map { _1.repetition? ? children_of(_1) : _1 }
|
|
||||||
|
|
||||||
public_tdcs
|
|
||||||
.map.with_index
|
|
||||||
.filter_map { |tdc, i| tdc.condition? ? [tdc, i] : nil }
|
|
||||||
.map do |tdc, i|
|
|
||||||
[tdc, tdc.condition.errors(public_tdcs.take(i))]
|
|
||||||
end
|
|
||||||
.filter { |_tdc, errors| errors.present? }
|
|
||||||
.each { |tdc, message| errors.add(:condition, message, type_de_champ: tdc) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def header_sections_are_valid?
|
|
||||||
public_tdcs = types_de_champ_public.to_a
|
|
||||||
|
|
||||||
root_tdcs_errors = errors_for_header_sections_order(public_tdcs)
|
|
||||||
repetition_tdcs_errors = public_tdcs
|
|
||||||
.filter_map { _1.repetition? ? children_of(_1) : nil }
|
|
||||||
.map { errors_for_header_sections_order(_1) }
|
|
||||||
|
|
||||||
repetition_tdcs_errors + root_tdcs_errors
|
|
||||||
end
|
|
||||||
|
|
||||||
def expressions_regulieres_are_valid?
|
|
||||||
types_de_champ_public.to_a
|
|
||||||
.flat_map { _1.repetition? ? children_of(_1) : _1 }
|
|
||||||
.each do |tdc|
|
|
||||||
if tdc.expression_reguliere? && tdc.invalid_regexp?
|
|
||||||
errors.add(:expression_reguliere, type_de_champ: tdc)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def errors_for_header_sections_order(tdcs)
|
|
||||||
tdcs
|
|
||||||
.map.with_index
|
|
||||||
.filter_map { |tdc, i| tdc.header_section? ? [tdc, i] : nil }
|
|
||||||
.map { |tdc, i| [tdc, tdc.check_coherent_header_level(tdcs.take(i))] }
|
|
||||||
.filter { |_tdc, errors| errors.present? }
|
|
||||||
.each { |tdc, message| errors.add(:header_section, message, type_de_champ: tdc) }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -505,15 +505,15 @@ class TypeDeChamp < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_coherent_header_level(upper_tdcs)
|
def check_coherent_header_level(upper_tdcs)
|
||||||
errs = []
|
|
||||||
previous_level = previous_section_level(upper_tdcs)
|
previous_level = previous_section_level(upper_tdcs)
|
||||||
|
|
||||||
current_level = header_section_level_value.to_i
|
current_level = header_section_level_value.to_i
|
||||||
|
|
||||||
difference = current_level - previous_level
|
difference = current_level - previous_level
|
||||||
if current_level > previous_level && difference != 1
|
if current_level > previous_level && difference != 1
|
||||||
errs << I18n.t('activerecord.errors.type_de_champ.attributes.header_section_level.gap_error', level: current_level - previous_level - 1)
|
I18n.t('activerecord.errors.type_de_champ.attributes.header_section_level.gap_error', level: current_level - previous_level - 1)
|
||||||
|
else
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
errs
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_section_level(revision)
|
def current_section_level(revision)
|
||||||
|
|
21
app/validators/types_de_champ/condition_validator.rb
Normal file
21
app/validators/types_de_champ/condition_validator.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
class TypesDeChamp::ConditionValidator < ActiveModel::EachValidator
|
||||||
|
def validate_each(procedure, attribute, types_de_champ)
|
||||||
|
public_tdcs = types_de_champ.to_a
|
||||||
|
.flat_map { _1.repetition? ? procedure.draft_revision.children_of(_1) : _1 }
|
||||||
|
|
||||||
|
public_tdcs
|
||||||
|
.map.with_index
|
||||||
|
.filter_map { |tdc, i| tdc.condition? ? [tdc, i] : nil }
|
||||||
|
.map do |tdc, i|
|
||||||
|
[tdc, tdc.condition.errors(public_tdcs.take(i))]
|
||||||
|
end
|
||||||
|
.filter { |_tdc, errors| errors.present? }
|
||||||
|
.each do |tdc, _error_hash|
|
||||||
|
procedure.errors.add(
|
||||||
|
attribute,
|
||||||
|
procedure.errors.generate_message(attribute, :invalid_condition, { value: tdc.libelle }),
|
||||||
|
type_de_champ: tdc
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
class TypesDeChamp::ExpressionReguliereValidator < ActiveModel::EachValidator
|
||||||
|
def validate_each(procedure, attribute, types_de_champ)
|
||||||
|
types_de_champ.to_a
|
||||||
|
.flat_map { _1.repetition? ? procedure.draft_revision.children_of(_1) : _1 }
|
||||||
|
.each do |tdc|
|
||||||
|
if tdc.expression_reguliere? && tdc.invalid_regexp?
|
||||||
|
procedure.errors.add(:expression_reguliere, type_de_champ: tdc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
class TypesDeChamp::HeaderSectionConsistencyValidator < ActiveModel::EachValidator
|
||||||
|
def validate_each(procedure, attribute, types_de_champ)
|
||||||
|
public_tdcs = types_de_champ.to_a
|
||||||
|
|
||||||
|
root_tdcs_errors = errors_for_header_sections_order(procedure, attribute, public_tdcs)
|
||||||
|
repetition_tdcs_errors = public_tdcs
|
||||||
|
.filter_map { _1.repetition? ? procedure.draft_revision.children_of(_1) : nil }
|
||||||
|
.map { errors_for_header_sections_order(procedure, attribute, _1) }
|
||||||
|
|
||||||
|
repetition_tdcs_errors + root_tdcs_errors
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def errors_for_header_sections_order(procedure, attribute, types_de_champ)
|
||||||
|
types_de_champ
|
||||||
|
.map.with_index
|
||||||
|
.filter_map { |tdc, i| tdc.header_section? ? [tdc, i] : nil }
|
||||||
|
.map { |tdc, i| [tdc, tdc.check_coherent_header_level(types_de_champ.take(i))] }
|
||||||
|
.filter { |_tdc, errors| errors.present? }
|
||||||
|
.each do |tdc, message|
|
||||||
|
procedure.errors.add(
|
||||||
|
attribute,
|
||||||
|
procedure.errors.generate_message(attribute, :inconsistent_header_section, { value: tdc.libelle, custom_message: message }),
|
||||||
|
type_de_champ: tdc
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,7 +11,8 @@ class TypesDeChamp::NoEmptyBlockValidator < ActiveModel::EachValidator
|
||||||
if procedure.draft_revision.children_of(parent).empty?
|
if procedure.draft_revision.children_of(parent).empty?
|
||||||
procedure.errors.add(
|
procedure.errors.add(
|
||||||
attribute,
|
attribute,
|
||||||
procedure.errors.generate_message(attribute, :empty_repetition, { value: parent.libelle })
|
procedure.errors.generate_message(attribute, :empty_repetition, { value: parent.libelle }),
|
||||||
|
type_de_champ: parent
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,7 +11,8 @@ class TypesDeChamp::NoEmptyDropDownValidator < ActiveModel::EachValidator
|
||||||
if drop_down.drop_down_list_enabled_non_empty_options.empty?
|
if drop_down.drop_down_list_enabled_non_empty_options.empty?
|
||||||
procedure.errors.add(
|
procedure.errors.add(
|
||||||
attribute,
|
attribute,
|
||||||
procedure.errors.generate_message(attribute, :empty_drop_down, { value: drop_down.libelle })
|
procedure.errors.generate_message(attribute, :empty_drop_down, { value: drop_down.libelle }),
|
||||||
|
type_de_champ: drop_down
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
['Configuration des champs']],
|
['Configuration des champs']],
|
||||||
preview: @procedure.draft_revision.valid? })
|
preview: @procedure.draft_revision.valid? })
|
||||||
|
|
||||||
= turbo_stream.replace 'errors-summary', render(TypesDeChampEditor::ErrorsSummary.new(revision: @procedure.draft_revision))
|
= turbo_stream.replace 'errors-summary', render(Procedure::ErrorsSummary.new(procedure: @procedure, validation_context: @tdc.public? ? :types_de_champ_public_editor : :types_de_champ_private_editor))
|
||||||
|
|
||||||
- rendered = render @condition_component
|
- rendered = render @condition_component
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
url: admin_procedure_publish_path(procedure_id: procedure.id),
|
url: admin_procedure_publish_path(procedure_id: procedure.id),
|
||||||
method: :put,
|
method: :put,
|
||||||
html: { class: 'form' } do |f|
|
html: { class: 'form' } do |f|
|
||||||
= render Procedure::PublicationWarningComponent.new(procedure: procedure)
|
= render Procedure::ErrorsSummary.new(procedure: @procedure, validation_context: :publication)
|
||||||
.mt-2
|
.mt-2
|
||||||
- if procedure.draft_changed?
|
- if procedure.draft_changed?
|
||||||
%p.mb-2= t('.draft_changed_procedure_alert')
|
%p.mb-2= t('.draft_changed_procedure_alert')
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
.fr-grid-row
|
.fr-grid-row
|
||||||
= render partial: 'champs_summary'
|
= render partial: 'champs_summary'
|
||||||
.fr-col
|
.fr-col
|
||||||
= render TypesDeChampEditor::EditorComponent.new(revision: @procedure.draft_revision)
|
= render TypesDeChampEditor::EditorComponent.new(revision: @procedure.draft_revision, is_annotation: false)
|
||||||
|
|
||||||
.padded-fixed-footer
|
.padded-fixed-footer
|
||||||
.fixed-footer
|
.fixed-footer
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
.fr-container.procedure-admin-container
|
.fr-container.procedure-admin-container
|
||||||
%ul.fr-btns-group.fr-btns-group--inline-sm.fr-btns-group--icon-left
|
%ul.fr-btns-group.fr-btns-group--inline-sm.fr-btns-group--icon-left
|
||||||
- if @procedure.draft_revision.valid?
|
- if @procedure.validate(:publication)
|
||||||
- if !@procedure.brouillon?
|
- if !@procedure.brouillon?
|
||||||
= link_to 'Télécharger', admin_procedure_archives_path(@procedure), class: 'fr-btn fr-btn--tertiary fr-btn--icon-left fr-icon-download-line', id: "archive-procedure"
|
= link_to 'Télécharger', admin_procedure_archives_path(@procedure), class: 'fr-btn fr-btn--tertiary fr-btn--icon-left fr-icon-download-line', id: "archive-procedure"
|
||||||
|
|
||||||
|
@ -27,15 +27,11 @@
|
||||||
= link_to 'Clore', admin_procedure_close_path(procedure_id: @procedure.id), class: 'fr-btn fr-btn--tertiary fr-btn--icon-left fr-icon-calendar-close-fill', id: "close-procedure-link"
|
= link_to 'Clore', admin_procedure_close_path(procedure_id: @procedure.id), class: 'fr-btn fr-btn--tertiary fr-btn--icon-left fr-icon-calendar-close-fill', id: "close-procedure-link"
|
||||||
|
|
||||||
.fr-container
|
.fr-container
|
||||||
= render TypesDeChampEditor::ErrorsSummary.new(revision: @procedure.draft_revision)
|
|
||||||
|
|
||||||
- if @procedure.draft_changed?
|
- if @procedure.draft_changed?
|
||||||
.fr-container
|
|
||||||
= render Dsfr::CalloutComponent.new(title: t(:has_changes, scope: [:administrateurs, :revision_changes]), icon: "fr-fi-information-line") do |c|
|
= render Dsfr::CalloutComponent.new(title: t(:has_changes, scope: [:administrateurs, :revision_changes]), icon: "fr-fi-information-line") do |c|
|
||||||
- c.with_body do
|
- c.with_body do
|
||||||
= render Procedure::RevisionChangesComponent.new changes: @procedure.revision_changes, previous_revision: @procedure.published_revision
|
= render Procedure::RevisionChangesComponent.new changes: @procedure.revision_changes, previous_revision: @procedure.published_revision
|
||||||
|
= render Procedure::ErrorsSummary.new(procedure: @procedure, validation_context: :publication)
|
||||||
= render Procedure::PublicationWarningComponent.new(procedure: @procedure)
|
|
||||||
|
|
||||||
- c.with_bottom do
|
- c.with_bottom do
|
||||||
%ul.fr-mt-2w.fr-btns-group.fr-btns-group--inline
|
%ul.fr-mt-2w.fr-btns-group.fr-btns-group--inline
|
||||||
|
@ -44,6 +40,9 @@
|
||||||
- else
|
- else
|
||||||
%li= button_to 'Publier les modifications', admin_procedure_publication_path(@procedure), class: 'fr-btn', id: 'publish-procedure-link', data: { disable_with: "Publication..." }, disabled: !@procedure.draft_revision.valid? || @procedure.errors.present?, method: :get
|
%li= button_to 'Publier les modifications', admin_procedure_publication_path(@procedure), class: 'fr-btn', id: 'publish-procedure-link', data: { disable_with: "Publication..." }, disabled: !@procedure.draft_revision.valid? || @procedure.errors.present?, method: :get
|
||||||
%li= button_to "Réinitialiser les modifications", admin_procedure_reset_draft_path(@procedure), class: 'fr-btn fr-btn--secondary fr-mr-2w', data: { confirm: 'Êtes-vous sûr de vouloir réinitialiser les modifications ?' }, method: :put
|
%li= button_to "Réinitialiser les modifications", admin_procedure_reset_draft_path(@procedure), class: 'fr-btn fr-btn--secondary fr-mr-2w', data: { confirm: 'Êtes-vous sûr de vouloir réinitialiser les modifications ?' }, method: :put
|
||||||
|
- else
|
||||||
|
= render Procedure::ErrorsSummary.new(procedure: @procedure, validation_context: :publication)
|
||||||
|
|
||||||
|
|
||||||
- if !@procedure.procedure_expires_when_termine_enabled?
|
- if !@procedure.procedure_expires_when_termine_enabled?
|
||||||
= render partial: 'administrateurs/procedures/suggest_expires_when_termine', locals: { procedure: @procedure }
|
= render partial: 'administrateurs/procedures/suggest_expires_when_termine', locals: { procedure: @procedure }
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
locals: { steps: [['Démarches', admin_procedures_path],
|
locals: { steps: [['Démarches', admin_procedures_path],
|
||||||
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
||||||
['Configuration des champs']],
|
['Configuration des champs']],
|
||||||
preview: @procedure.draft_revision.valid? })
|
preview: @procedure.validate(@coordinate&.private? ? :types_de_champ_private_editor : :types_de_champ_public_editor) })
|
||||||
|
|
||||||
= turbo_stream.replace 'errors-summary', render(TypesDeChampEditor::ErrorsSummary.new(revision: @procedure.draft_revision))
|
= turbo_stream.replace 'errors-summary', render(Procedure::ErrorsSummary.new(procedure: @procedure, validation_context: @coordinate&.private? ? :types_de_champ_private_editor : :types_de_champ_public_editor))
|
||||||
|
|
||||||
= turbo_stream.replace 'summary', render(partial: 'administrateurs/procedures/champs_summary')
|
= turbo_stream.replace 'summary', render(partial: 'administrateurs/procedures/champs_summary')
|
||||||
|
|
||||||
|
|
|
@ -739,8 +739,6 @@ fr:
|
||||||
evil_regexp: L'expression régulière que vous avez entrée est potentiellement dangereuse et pourrait entraîner des problèmes de performance
|
evil_regexp: L'expression régulière que vous avez entrée est potentiellement dangereuse et pourrait entraîner des problèmes de performance
|
||||||
mismatch_regexp: L'exemple doit correspondre à l'expression régulière fournie
|
mismatch_regexp: L'exemple doit correspondre à l'expression régulière fournie
|
||||||
syntax_error_regexp: La syntaxe de l'expression régulière n'est pas valide
|
syntax_error_regexp: La syntaxe de l'expression régulière n'est pas valide
|
||||||
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 n’est maintenant plus en brouillon."
|
# procedure_not_draft: "Cette démarche n’est maintenant plus en brouillon."
|
||||||
cadastres_empty:
|
cadastres_empty:
|
||||||
one: "Aucune parcelle cadastrale sur la zone sélectionnée"
|
one: "Aucune parcelle cadastrale sur la zone sélectionnée"
|
||||||
|
|
|
@ -72,8 +72,30 @@ en:
|
||||||
invalid: 'invalid format'
|
invalid: 'invalid format'
|
||||||
draft_types_de_champ_public:
|
draft_types_de_champ_public:
|
||||||
format: 'Public field %{message}'
|
format: 'Public field %{message}'
|
||||||
|
invalid_condition: "« %{value} » have an invalid logic"
|
||||||
|
empty_repetition: '« %{value} » requires at least one field'
|
||||||
|
empty_drop_down: '« %{value} » requires at least one option'
|
||||||
|
inconsistent_header_section: "« %{value} » %{custom_message}"
|
||||||
draft_types_de_champ_private:
|
draft_types_de_champ_private:
|
||||||
format: 'Private field %{message}'
|
format: 'Private field %{message}'
|
||||||
|
invalid_condition: "« %{value} » have an invalid logic"
|
||||||
|
empty_repetition: '« %{value} » requires at least one field'
|
||||||
|
empty_drop_down: '« %{value} » requires at least one option'
|
||||||
|
inconsistent_header_section: "« %{value} » %{custom_message}"
|
||||||
|
attestation_template:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
initiated_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
received_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
closed_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
refused_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
without_continuation_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
re_instructed_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
lien_dpo:
|
lien_dpo:
|
||||||
invalid_uri_or_email: "Fill in with an email or a link"
|
invalid_uri_or_email: "Fill in with an email or a link"
|
||||||
sva_svr:
|
sva_svr:
|
||||||
|
|
|
@ -78,8 +78,30 @@ fr:
|
||||||
invalid: 'n’a pas le bon format'
|
invalid: 'n’a pas le bon format'
|
||||||
draft_types_de_champ_public:
|
draft_types_de_champ_public:
|
||||||
format: 'Le champ %{message}'
|
format: 'Le champ %{message}'
|
||||||
|
invalid_condition: "« %{value} » a une logique conditionnelle invalide"
|
||||||
|
empty_repetition: '« %{value} » doit comporter au moins un champ répétable'
|
||||||
|
empty_drop_down: '« %{value} » doit comporter au moins un choix sélectionnable'
|
||||||
|
inconsistent_header_section: "« %{value} » %{custom_message}"
|
||||||
draft_types_de_champ_private:
|
draft_types_de_champ_private:
|
||||||
format: 'L’annotation privée %{message}'
|
format: 'L’annotation privée %{message}'
|
||||||
|
invalid_condition: "« %{value} » a une logique conditionnelle invalide"
|
||||||
|
empty_repetition: '« %{value} » doit comporter au moins un champ répétable'
|
||||||
|
empty_drop_down: '« %{value} » doit comporter au moins un choix sélectionnable'
|
||||||
|
inconsistent_header_section: "« %{value} » %{custom_message}"
|
||||||
|
attestation_template:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
initiated_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
received_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
closed_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
refused_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
without_continuation_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
|
re_instructed_mail:
|
||||||
|
format: "%{attribute} %{message}"
|
||||||
lien_dpo:
|
lien_dpo:
|
||||||
invalid_uri_or_email: "Veuillez saisir un mail ou un lien"
|
invalid_uri_or_email: "Veuillez saisir un mail ou un lien"
|
||||||
auto_archive_on:
|
auto_archive_on:
|
||||||
|
|
|
@ -61,4 +61,4 @@ fr:
|
||||||
type_de_champ:
|
type_de_champ:
|
||||||
attributes:
|
attributes:
|
||||||
header_section_level:
|
header_section_level:
|
||||||
gap_error: "Un titre de section avec le niveau %{level} est manquant."
|
gap_error: "devrait être précédé d'un titre de niveau %{level}"
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
describe Procedure::Card::AnnotationsComponent, type: :component do
|
||||||
|
describe 'render' do
|
||||||
|
let(:procedure) { create(:procedure, id: 1, types_de_champ_private:, types_de_champ_public:) }
|
||||||
|
let(:types_de_champ_private) { [] }
|
||||||
|
let(:types_de_champ_public) { [] }
|
||||||
|
before { procedure.validate(:publication) }
|
||||||
|
subject { render_inline(described_class.new(procedure: procedure)) }
|
||||||
|
|
||||||
|
context 'when no errors' do
|
||||||
|
it 'does not render' do
|
||||||
|
expect(subject).to have_selector('.fr-badge--info', text: 'À configurer')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when errors on types_de_champs_public' do
|
||||||
|
let(:types_de_champ_public) { [{ type: :drop_down_list, options: [] }] }
|
||||||
|
it 'does not render' do
|
||||||
|
expect(subject).to have_selector('.fr-badge--info', text: 'À configurer')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when errors on types_de_champs_private' do
|
||||||
|
let(:types_de_champ_private) { [{ type: :drop_down_list, options: [] }] }
|
||||||
|
|
||||||
|
it 'render the template' do
|
||||||
|
expect(subject).to have_selector('.fr-badge--error', text: 'À modifier')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
30
spec/components/procedures/card/champs_component_spec.rb
Normal file
30
spec/components/procedures/card/champs_component_spec.rb
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
describe Procedure::Card::ChampsComponent, type: :component do
|
||||||
|
describe 'render' do
|
||||||
|
let(:procedure) { create(:procedure, id: 1, types_de_champ_private:, types_de_champ_public:) }
|
||||||
|
let(:types_de_champ_private) { [] }
|
||||||
|
let(:types_de_champ_public) { [] }
|
||||||
|
before { procedure.validate(:publication) }
|
||||||
|
subject { render_inline(described_class.new(procedure: procedure)) }
|
||||||
|
|
||||||
|
context 'when no errors' do
|
||||||
|
it 'does not render' do
|
||||||
|
expect(subject).to have_selector('.fr-badge--warning', text: 'À faire')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when errors on types_de_champs_public' do
|
||||||
|
let(:types_de_champ_public) { [{ type: :drop_down_list, options: [] }] }
|
||||||
|
it 'does not render' do
|
||||||
|
expect(subject).to have_selector('.fr-badge--error', text: 'À modifier')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when errors on types_de_champs_private' do
|
||||||
|
let(:types_de_champ_private) { [{ type: :drop_down_list, options: [] }] }
|
||||||
|
|
||||||
|
it 'render the template' do
|
||||||
|
expect(subject).to have_selector('.fr-badge--warning', text: 'À faire')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
80
spec/components/procedures/errors_summary_spec.rb
Normal file
80
spec/components/procedures/errors_summary_spec.rb
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
describe Procedure::ErrorsSummary, type: :component do
|
||||||
|
subject { render_inline(described_class.new(procedure:, validation_context:)) }
|
||||||
|
|
||||||
|
describe 'validations context' do
|
||||||
|
let(:procedure) { create(:procedure, types_de_champ_private:, types_de_champ_public:) }
|
||||||
|
let(:types_de_champ_private) { [{ type: :drop_down_list, options: [], libelle: 'private' }] }
|
||||||
|
let(:types_de_champ_public) { [{ type: :drop_down_list, options: [], libelle: 'public' }] }
|
||||||
|
|
||||||
|
before { subject }
|
||||||
|
|
||||||
|
context 'when :publication' do
|
||||||
|
let(:validation_context) { :publication }
|
||||||
|
|
||||||
|
it 'shows errors for public and private tdc' do
|
||||||
|
expect(page).to have_text("Le champ « public » doit comporter au moins un choix sélectionnable")
|
||||||
|
expect(page).to have_text("L’annotation privée « private » doit comporter au moins un choix sélectionnable")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when :types_de_champ_public_editor' do
|
||||||
|
let(:validation_context) { :types_de_champ_public_editor }
|
||||||
|
|
||||||
|
it 'shows errors for public only tdc' do
|
||||||
|
expect(page).to have_text("Le champ « public » doit comporter au moins un choix sélectionnable")
|
||||||
|
expect(page).not_to have_text("L’annotation privée « private » doit comporter au moins un choix sélectionnable")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when :types_de_champ_private_editor' do
|
||||||
|
let(:validation_context) { :types_de_champ_private_editor }
|
||||||
|
|
||||||
|
it 'shows errors for private only tdc' do
|
||||||
|
expect(page).not_to have_text("Le champ « public » doit comporter au moins un choix sélectionnable")
|
||||||
|
expect(page).to have_text("L’annotation privée « private » doit comporter au moins un choix sélectionnable")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'render all kind of champs errors' do
|
||||||
|
include Logic
|
||||||
|
|
||||||
|
let(:procedure) do
|
||||||
|
create(:procedure, id: 1, types_de_champ_public: [
|
||||||
|
{ libelle: 'repetition requires children', type: :repetition, children: [] },
|
||||||
|
{ libelle: 'drop down list requires options', type: :drop_down_list, options: [] },
|
||||||
|
{ libelle: 'invalid condition', type: :text, condition: ds_eq(constant(true), constant(1)) },
|
||||||
|
{ libelle: 'header sections must have consistent order', type: :header_section, level: 2 }
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:validation_context) { :types_de_champ_public_editor }
|
||||||
|
|
||||||
|
before { subject }
|
||||||
|
|
||||||
|
it 'renders all errors on champ' do
|
||||||
|
expect(page).to have_text("Le champ « drop down list requires options » doit comporter au moins un choix sélectionnable")
|
||||||
|
expect(page).to have_text("Le champ « repetition requires children » doit comporter au moins un champ répétable")
|
||||||
|
expect(page).to have_text("Le champ « invalid condition » a une logique conditionnelle invalide")
|
||||||
|
expect(page).to have_text("Le champ « header sections must have consistent order » devrait être précédé d'un titre de niveau 1")
|
||||||
|
# TODO, test attestation_template, initiated_mail, :received_mail, :closed_mail, :refused_mail, :without_continuation_mail, :re_instructed_mail
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'render error for other kind of associated objects' do
|
||||||
|
let(:validation_context) { :publication }
|
||||||
|
let(:procedure) { create(:procedure, attestation_template:, initiated_mail:) }
|
||||||
|
let(:attestation_template) { build(:attestation_template) }
|
||||||
|
let(:initiated_mail) { build(:initiated_mail) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
[:attestation_template, :initiated_mail].map { procedure.send(_1).update_column(:body, '--invalidtag--') }
|
||||||
|
subject
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'render error nicely' do
|
||||||
|
expect(page).to have_text("Le modèle d’attestation n'est pas valide")
|
||||||
|
expect(page).to have_text("L’email de notification de passage de dossier en instruction n'est pas valide")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
describe TypesDeChampEditor::EditorComponent, type: :component do
|
||||||
|
let(:revision) { procedure.draft_revision }
|
||||||
|
let(:procedure) { create(:procedure, id: 1, types_de_champ_private:, types_de_champ_public:) }
|
||||||
|
|
||||||
|
let(:types_de_champ_private) { [{ type: :drop_down_list, options: [], libelle: 'private' }] }
|
||||||
|
let(:types_de_champ_public) { [{ type: :drop_down_list, options: [], libelle: 'public' }] }
|
||||||
|
|
||||||
|
describe 'render' do
|
||||||
|
subject { render_inline(described_class.new(revision:, is_annotation:)) }
|
||||||
|
context 'types_de_champ_public' do
|
||||||
|
let(:is_annotation) { false }
|
||||||
|
it 'does not render private champs errors' do
|
||||||
|
expect(subject).not_to have_text("« private » doit comporter au moins un choix sélectionnable")
|
||||||
|
expect(subject).to have_text("« public » doit comporter au moins un choix sélectionnable")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'types_de_champ_private' do
|
||||||
|
let(:is_annotation) { true }
|
||||||
|
it 'does not render public champs errors' do
|
||||||
|
expect(subject).to have_text("« private » doit comporter au moins un choix sélectionnable")
|
||||||
|
expect(subject).not_to have_text("« public » doit comporter au moins un choix sélectionnable")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -828,23 +828,22 @@ describe ProcedureRevision do
|
||||||
describe 'conditions_are_valid' do
|
describe 'conditions_are_valid' do
|
||||||
include Logic
|
include Logic
|
||||||
|
|
||||||
|
let(:procedure) { create(:procedure, types_de_champ_public:) }
|
||||||
|
let(:types_de_champ_public) do
|
||||||
|
[
|
||||||
|
{ type: :integer_number, libelle: 'l1' },
|
||||||
|
{ type: :integer_number, libelle: 'l2' }
|
||||||
|
]
|
||||||
|
end
|
||||||
def first_champ = procedure.draft_revision.types_de_champ_public.first
|
def first_champ = procedure.draft_revision.types_de_champ_public.first
|
||||||
|
|
||||||
def second_champ = procedure.draft_revision.types_de_champ_public.second
|
def second_champ = procedure.draft_revision.types_de_champ_public.second
|
||||||
|
|
||||||
let(:procedure) do
|
|
||||||
create(:procedure).tap do |p|
|
|
||||||
p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'l1')
|
|
||||||
p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'l2')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:draft_revision) { procedure.draft_revision }
|
let(:draft_revision) { procedure.draft_revision }
|
||||||
let(:condition) { nil }
|
let(:condition) { nil }
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
draft_revision.save
|
procedure.validate(:publication)
|
||||||
draft_revision.errors
|
procedure.errors
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a champ has a valid condition (type)' do
|
context 'when a champ has a valid condition (type)' do
|
||||||
|
@ -865,7 +864,7 @@ describe ProcedureRevision do
|
||||||
before { second_champ.update(condition: condition) }
|
before { second_champ.update(condition: condition) }
|
||||||
let(:condition) { ds_eq(constant(true), constant(1)) }
|
let(:condition) { ds_eq(constant(true), constant(1)) }
|
||||||
|
|
||||||
it { expect(subject.first.attribute).to eq(:condition) }
|
it { expect(subject.first.attribute).to eq(:draft_types_de_champ_public) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a champ has an invalid condition: needed tdc is down in the forms' do
|
context 'when a champ has an invalid condition: needed tdc is down in the forms' do
|
||||||
|
@ -876,7 +875,7 @@ describe ProcedureRevision do
|
||||||
first_champ.update(condition: need_second_champ)
|
first_champ.update(condition: need_second_champ)
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect(subject.first.attribute).to eq(:condition) }
|
it { expect(subject.first.attribute).to eq(:draft_types_de_champ_public) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a repetition' do
|
context 'with a repetition' do
|
||||||
|
@ -904,7 +903,7 @@ describe ProcedureRevision do
|
||||||
context 'when a champ belongs to a repetition' do
|
context 'when a champ belongs to a repetition' do
|
||||||
let(:condition) { ds_eq(champ_value(-1), constant(1)) }
|
let(:condition) { ds_eq(champ_value(-1), constant(1)) }
|
||||||
|
|
||||||
it { expect(subject.first.attribute).to eq(:condition) }
|
it { expect(subject.first.attribute).to eq(:draft_types_de_champ_public) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -918,8 +917,8 @@ describe ProcedureRevision do
|
||||||
let(:draft_revision) { procedure.draft_revision }
|
let(:draft_revision) { procedure.draft_revision }
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
draft_revision.save
|
procedure.validate(:publication)
|
||||||
draft_revision.errors
|
procedure.errors
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'find error' do
|
it 'find error' do
|
||||||
|
@ -936,8 +935,8 @@ describe ProcedureRevision do
|
||||||
let(:draft_revision) { procedure.draft_revision }
|
let(:draft_revision) { procedure.draft_revision }
|
||||||
|
|
||||||
subject do
|
subject do
|
||||||
draft_revision.save
|
procedure.validate(:publication)
|
||||||
draft_revision.errors
|
procedure.errors
|
||||||
end
|
end
|
||||||
|
|
||||||
context "When no regexp and no example" do
|
context "When no regexp and no example" do
|
||||||
|
|
|
@ -44,13 +44,10 @@ describe 'Publishing a procedure', js: true do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a procedure isn’t published yet' do
|
context 'when a procedure isn’t published yet' do
|
||||||
before do
|
|
||||||
visit admin_procedures_path(statut: "brouillons")
|
|
||||||
click_on procedure.libelle
|
|
||||||
find('#publish-procedure-link').click
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario 'an admin can publish it' do
|
scenario 'an admin can publish it' do
|
||||||
|
visit admin_procedure_path(procedure)
|
||||||
|
find('#publish-procedure-link').click
|
||||||
|
|
||||||
expect(find_field('procedure_path').value).to eq procedure.path
|
expect(find_field('procedure_path').value).to eq procedure.path
|
||||||
fill_in 'lien_site_web', with: 'http://some.website'
|
fill_in 'lien_site_web', with: 'http://some.website'
|
||||||
within('form') { click_on 'Publier' }
|
within('form') { click_on 'Publier' }
|
||||||
|
@ -72,10 +69,13 @@ describe 'Publishing a procedure', js: true do
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'an error message prevents the publication' do
|
scenario 'an error message prevents the publication' do
|
||||||
expect(page).to have_content('Des problèmes empêchent la publication de la démarche')
|
visit admin_procedure_path(procedure)
|
||||||
expect(page).to have_content("Le champ « Enfants » doit comporter au moins un champ répétable")
|
|
||||||
expect(page).to have_content("L’annotation privée « Civilité » doit comporter au moins un choix sélectionnable")
|
|
||||||
|
|
||||||
|
expect(page).to have_content('Des problèmes empêchent la publication de la démarche')
|
||||||
|
expect(page).to have_content("« Enfants » doit comporter au moins un champ répétable")
|
||||||
|
expect(page).to have_content("« Civilité » doit comporter au moins un choix sélectionnable")
|
||||||
|
|
||||||
|
visit admin_procedure_publication_path(procedure)
|
||||||
expect(find_field('procedure_path').value).to eq procedure.path
|
expect(find_field('procedure_path').value).to eq procedure.path
|
||||||
fill_in 'lien_site_web', with: 'http://some.website'
|
fill_in 'lien_site_web', with: 'http://some.website'
|
||||||
|
|
||||||
|
@ -85,8 +85,9 @@ describe 'Publishing a procedure', js: true do
|
||||||
|
|
||||||
context 'when the procedure has the same path as another procedure from another admin ' do
|
context 'when the procedure has the same path as another procedure from another admin ' do
|
||||||
scenario 'an error message prevents the publication' do
|
scenario 'an error message prevents the publication' do
|
||||||
expect(find_field('procedure_path').value).to eq procedure.path
|
visit admin_procedure_publication_path(procedure)
|
||||||
fill_in 'procedure_path', with: other_procedure.path
|
fill_in 'procedure_path', with: other_procedure.path
|
||||||
|
|
||||||
expect(page).to have_content 'vous devez la modifier afin de pouvoir publier votre démarche'
|
expect(page).to have_content 'vous devez la modifier afin de pouvoir publier votre démarche'
|
||||||
|
|
||||||
fill_in 'lien_site_web', with: 'http://some.website'
|
fill_in 'lien_site_web', with: 'http://some.website'
|
||||||
|
|
|
@ -228,9 +228,7 @@ describe 'As an administrateur I can edit types de champ', js: true do
|
||||||
click_on 'Supprimer'
|
click_on 'Supprimer'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
expect(page).to have_content("devrait être précédé d'un titre de niveau 1")
|
||||||
expect(page).to have_content("Le formulaire contient des erreurs")
|
|
||||||
expect(page).to have_content("Le titre de section suivant est invalide, veuillez le corriger :")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue