Merge pull request #9871 from mfo/US/add-pj-to-explication

ETQ administrateur, je peux ajouter une notice explicative a un champs explication
This commit is contained in:
mfo 2023-12-19 10:44:03 +00:00 committed by GitHub
commit e75c4456e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 112 additions and 26 deletions

View file

@ -1,2 +1,4 @@
class EditableChamp::ExplicationComponent < EditableChamp::EditableChampBaseComponent
delegate :type_de_champ, to: :@champ
delegate :notice_explicative, to: :type_de_champ
end

View file

@ -8,3 +8,5 @@
%button{ type: "button", "aria-controls": dom_id(@champ, :explanation), "aria-expanded": "false", href: dom_id(@champ, :explanation), class: "fr-btn ft-btn--sm fr-btn--secondary" } Lire plus
.fr-collapse{ id: dom_id(@champ, :explanation) }
= render SimpleFormatComponent.new(@champ.collapsible_explanation_text, allow_a: true)
- if notice_explicative.attached?
= render Dsfr::DownloadComponent.new(attachment: notice_explicative, virus_not_analyzed: !notice_explicative.virus_scanner.started?, new_tab: true)

View file

@ -24,6 +24,7 @@ fr:
update_drop_down_secondary_description: La description secondaire du champ « %{label} » a été modifiée. La nouvelle description est « %{to} ».
update_type_champ: Le type du champ « %{label} » a été modifié. Il est maintenant de type « %{to} ».
update_piece_justificative_template: Le modèle de pièce justificative du champ « %{label} » a été modifié.
update_notice_explicative: La notice explicative du champ « %{label} » a été modifiée.
update_drop_down_options: "Les options de sélection du champ « %{label} » ont été modifiées :"
update_drop_down_options_alert: "Le champ « %{label} » est utilisé pour le routage des dossiers. Veuillez mettre à jour la configuration des groupes d'instructeurs après avoir publié les modifications."
enable_mandatory: Le champ « %{label} » est maintenant obligatoire.
@ -59,6 +60,7 @@ fr:
update_drop_down_secondary_description: La description secondaire de lannotation « %{label} » a été modifiée. La nouvelle description est « %{to} ».
update_type_champ: Le type de lannotation privée « %{label} » a été modifié. Elle est maintenant de type « %{to} ».
update_piece_justificative_template: Le modèle de pièce justificative de lannotation privée « %{label} » a été modifié.
update_notice_explicative: La notice explicative lannotation privée « %{label} » a été modifiée.
update_drop_down_options: "Les options de sélection de lannotation privée « %{label} » ont été modifiées :"
update_carte_layers: "Les référentiels cartographiques de lannotation privée « %{label} » ont été modifiés :"
enable_drop_down_other: Lannotation privée « %{label} » comporte maintenant un choix « Autre ».

View file

@ -59,6 +59,9 @@
- when :piece_justificative_template
- list.with_item do
= t(".#{prefix}.update_piece_justificative_template", label: change.label)
- when :notice_explicative
- list.with_item do
= t(".#{prefix}.update_notice_explicative", label: change.label)
- when :drop_down_options
- added = change.to.sort - change.from.sort
- removed = change.from.sort - change.to.sort

View file

@ -82,6 +82,14 @@ class TypesDeChampEditor::ChampComponent < ApplicationComponent
}
end
def notice_explicative_options
{
attached_file: type_de_champ.notice_explicative,
auto_attach_url: helpers.auto_attach_url(type_de_champ),
view_as: :download
}
end
EXCLUDE_FROM_BLOCK = [
TypeDeChamp.type_champs.fetch(:carte),
TypeDeChamp.type_champs.fetch(:dossier_link),

View file

@ -41,34 +41,46 @@
%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
.cell.fr-mt-1w
= form.label :expression_reguliere, for: dom_id(type_de_champ, :expression_reguliere) do
= t('.expression_reguliere.labels.regex')
.type-de-champ-expression-reguliere
= form.text_field :expression_reguliere, class: "fr-input small-margin small", id: dom_id(type_de_champ, :expression_reguliere)
.cell.mt-1
.cell.fr-mt-1w
= 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
.cell.fr-mt-1w
= 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
.cell.fr-mt-1w
= form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description)
= form.text_area :description, class: 'fr-input small-margin small width-100', rows: 3, id: dom_id(type_de_champ, :description)
- if type_de_champ.header_section?
.cell.mt-1
.cell.fr-mt-1w
= render TypesDeChampEditor::HeaderSectionComponent.new(form: form, tdc: type_de_champ, upper_tdcs: @upper_coordinates.map(&:type_de_champ))
- if type_de_champ.explication?
.cell.fr-mt-1w
= form.label :collapsible_explanation_enabled, for: dom_id(type_de_champ, :collapsible_explanation_enabled) do
Afficher un texte complementaire affichable au clic
= form.check_box :collapsible_explanation_enabled, class: "small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_enabled)
- if form.object.collapsible_explanation_enabled?
= form.label :collapsible_explanation_text, for: dom_id(type_de_champ, :collapsible_explanation_text) do
= "Texte à afficher quand l'utiliser a choisi de l'afficher"
= form.text_area :collapsible_explanation_text, class: "fr-input small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_text)
.cell.fr-mt-1w
= form.label :notice_explicative, "Notice explicative", for: dom_id(type_de_champ, :notice_explicative)
= render Attachment::EditComponent.new(**notice_explicative_options)
.flex.justify-start.mt-1
.flex.justify-start.fr-mt-1w
- if type_de_champ.drop_down_list?
.flex.column.justify-start.width-33
.cell
@ -85,7 +97,7 @@
.cell
= form.label :drop_down_secondary_libelle, "Libellé du champ secondaire", class: 'flex-grow', for: dom_id(type_de_champ, :drop_down_secondary_libelle)
= form.text_field :drop_down_secondary_libelle, class: 'fr-input small-margin small width-100', id: dom_id(type_de_champ, :drop_down_secondary_libelle)
.cell.mt-1
.cell.fr-mt-1w
= form.label :drop_down_secondary_description, "Description du champ secondaire (optionnel)", for: dom_id(type_de_champ, :drop_down_secondary_description)
= form.text_area :drop_down_secondary_description, class: 'fr-input small-margin small width-100', rows: 3, id: dom_id(type_de_champ, :drop_down_secondary_description)
- if type_de_champ.piece_justificative?
@ -99,6 +111,7 @@
Dans le cadre de la RGPD, le titre didentité sera supprimé lors de lacceptation, du refus ou du classement sans suite du dossier. Aussi, pour des raisons de sécurités, un filigrane est automatiquement ajouté aux images.
- elsif procedure.piece_justificative_multiple?
%p Les usagers pourront envoyer plusieurs fichiers si nécessaire.
- if type_de_champ.carte?
- type_de_champ.editable_options.each do |slice|
.cell
@ -108,15 +121,6 @@
= form.label name, for: dom_id(type_de_champ, "layer_#{name}") do
= form.check_box name, checked: checked, class: 'small-margin small', id: dom_id(type_de_champ, "layer_#{name}")
= t(".layers.#{name}")
- if type_de_champ.explication?
.cell.width-66
= form.label :collapsible_explanation_enabled, for: dom_id(type_de_champ, :collapsible_explanation_enabled) do
Afficher un texte complementaire affichable au clic
= form.check_box :collapsible_explanation_enabled, class: "small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_enabled)
- if form.object.collapsible_explanation_enabled?
= form.label :collapsible_explanation_text, for: dom_id(type_de_champ, :collapsible_explanation_text) do
= "Texte à afficher quand l'utiliser a choisi de l'afficher"
= form.text_area :collapsible_explanation_text, class: "fr-input small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_text)
- if type_de_champ.textarea?
.cell
= form.label :character_limit, for: dom_id(type_de_champ, :character_limit) do

View file

@ -44,6 +44,19 @@ module Administrateurs
end
end
def notice_explicative
type_de_champ = draft.find_and_ensure_exclusive_use(params[:stable_id])
if type_de_champ.notice_explicative.attach(params[:blob_signed_id])
@coordinate = draft.coordinate_for(type_de_champ)
@morphed = [champ_component_from(@coordinate)]
render :create
else
render json: { errors: @champ.errors.full_messages }, status: 422
end
end
def move
draft.move_type_de_champ(params[:stable_id], params[:position].to_i)
end

View file

@ -10,8 +10,10 @@ module ChampHelper
def auto_attach_url(object, params = {})
if object.is_a?(Champ)
champs_attach_piece_justificative_url(object.id, params)
elsif object.is_a?(TypeDeChamp)
elsif object.is_a?(TypeDeChamp) && object.piece_justificative?
piece_justificative_template_admin_procedure_type_de_champ_url(stable_id: object.stable_id, procedure_id: object.procedure.id, **params)
elsif object.is_a?(TypeDeChamp) && object.explication?
notice_explicative_admin_procedure_type_de_champ_url(stable_id: object.stable_id, procedure_id: object.procedure.id, **params)
end
end
end

View file

@ -363,11 +363,18 @@ class ProcedureRevision < ApplicationRecord
to_type_de_champ.carte_optional_layers)
end
elsif to_type_de_champ.piece_justificative?
if from_type_de_champ.piece_justificative_template_checksum != to_type_de_champ.piece_justificative_template_checksum
if from_type_de_champ.checksum_for_attachment(:piece_justificative_template) != to_type_de_champ.checksum_for_attachment(:piece_justificative_template)
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:piece_justificative_template,
from_type_de_champ.piece_justificative_template_filename,
to_type_de_champ.piece_justificative_template_filename)
from_type_de_champ.filename_for_attachement(:piece_justificative_template),
to_type_de_champ.filename_for_attachement(:piece_justificative_template))
end
elsif to_type_de_champ.explication?
if from_type_de_champ.checksum_for_attachment(:notice_explicative) != to_type_de_champ.checksum_for_attachment(:notice_explicative)
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:notice_explicative,
from_type_de_champ.filename_for_attachement(:notice_explicative),
to_type_de_champ.filename_for_attachement(:notice_explicative))
end
elsif to_type_de_champ.textarea?
if from_type_de_champ.character_limit != to_type_de_champ.character_limit

View file

@ -193,6 +193,21 @@ class TypeDeChamp < ApplicationRecord
validates :piece_justificative_template, size: { less_than: FILE_MAX_SIZE }
validates :piece_justificative_template, content_type: AUTHORIZED_CONTENT_TYPES
has_one_attached :notice_explicative
validates :notice_explicative, content_type: [
"application/msword",
"application/pdf",
"application/vnd.ms-powerpoint",
"application/vnd.oasis.opendocument.presentation",
"application/vnd.oasis.opendocument.text",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"image/jpeg",
"image/jpg",
"image/png",
"text/plain"
], size: { less_than: 20.megabytes }
validates :libelle, presence: true, allow_blank: false, allow_nil: false
validates :type_champ, presence: true, allow_blank: false, allow_nil: false
validates :character_limit, numericality: {
@ -446,15 +461,17 @@ class TypeDeChamp < ApplicationRecord
"TypesDeChamp::#{type_champ.classify}TypeDeChamp"
end
def piece_justificative_template_filename
if piece_justificative_template.attached?
piece_justificative_template.filename
def filename_for_attachement(attachment_sym)
attachment = send(attachment_sym)
if attachment.attached?
attachment.filename
end
end
def piece_justificative_template_checksum
if piece_justificative_template.attached?
piece_justificative_template.checksum
def checksum_for_attachment(attachment_sym)
attachment = send(attachment_sym)
if attachment.attached?
attachment.checksum
end
end

View file

@ -625,6 +625,7 @@ Rails.application.routes.draw do
patch :move_up
patch :move_down
put :piece_justificative_template
put :notice_explicative
end
end

View file

@ -50,5 +50,14 @@ describe TypesDeChampEditor::ChampComponent, type: :component do
end
end
end
describe 'tdc explication' do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :explication }]) }
let(:coordinate) { procedure.draft_revision.revision_types_de_champ_public.first }
it 'includes an uploader for notice_explicative' do
expect(page).to have_css('label', text: 'Notice explicative')
expect(page).to have_css('input[type=file]')
end
end
end
end

View file

@ -188,4 +188,20 @@ describe Administrateurs::TypesDeChampController, type: :controller do
end
end
end
describe '#notice_explicative' do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :explication }]) }
let(:coordinate) { procedure.draft_revision.types_de_champ.first }
let(:file) { Tempfile.new }
let(:blob) { ActiveStorage::Blob.create_before_direct_upload!(filename: File.basename(file.path), byte_size: file.size, checksum: Digest::SHA256.file(file.path), content_type: 'text/plain') }
context 'when sending a valid blob' do
it 'attaches the blob and responds with 200' do
expect { put :notice_explicative, format: :turbo_stream, params: { stable_id: coordinate.stable_id, procedure_id: procedure.id, blob_signed_id: blob.signed_id } }
.to change { coordinate.reload.notice_explicative.attached? }
.from(false).to(true)
expect(response).to have_http_status(:success)
end
end
end
end