Merge pull request #8271 from colinux/pj-en-construction-replace
Replace mandatory attachments when dossier is "en construction"
This commit is contained in:
commit
495b4988d2
17 changed files with 256 additions and 31 deletions
|
@ -25,7 +25,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.attachment-multiple:not(.fr-downloads-group) {
|
.attachment-multiple:not(.fr-downloads-group),
|
||||||
|
.attachment-multiple.fr-downloads-group[data-controller=replace-attachment] {
|
||||||
ul {
|
ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding-inline-start: 0;
|
padding-inline-start: 0;
|
||||||
|
@ -42,6 +43,10 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -1rem;
|
top: -1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fr-btn {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.attachment-multiple.fr-downloads-group.destroyable {
|
.attachment-multiple.fr-downloads-group.destroyable {
|
||||||
|
|
|
@ -4,12 +4,14 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
attr_reader :attachment
|
attr_reader :attachment
|
||||||
attr_reader :user_can_destroy
|
attr_reader :user_can_destroy
|
||||||
alias user_can_destroy? user_can_destroy
|
alias user_can_destroy? user_can_destroy
|
||||||
|
attr_reader :user_can_replace
|
||||||
|
alias user_can_replace? user_can_replace
|
||||||
attr_reader :as_multiple
|
attr_reader :as_multiple
|
||||||
alias as_multiple? as_multiple
|
alias as_multiple? as_multiple
|
||||||
|
|
||||||
EXTENSIONS_ORDER = ['jpeg', 'png', 'pdf', 'zip'].freeze
|
EXTENSIONS_ORDER = ['jpeg', 'png', 'pdf', 'zip'].freeze
|
||||||
|
|
||||||
def initialize(champ: nil, auto_attach_url: nil, attached_file:, direct_upload: true, index: 0, as_multiple: false, view_as: :link, user_can_destroy: true, **kwargs)
|
def initialize(champ: nil, auto_attach_url: nil, attached_file:, direct_upload: true, index: 0, as_multiple: false, view_as: :link, user_can_destroy: true, user_can_replace: false, **kwargs)
|
||||||
@as_multiple = as_multiple
|
@as_multiple = as_multiple
|
||||||
@attached_file = attached_file
|
@attached_file = attached_file
|
||||||
@auto_attach_url = auto_attach_url
|
@auto_attach_url = auto_attach_url
|
||||||
|
@ -18,6 +20,7 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
@index = index
|
@index = index
|
||||||
@view_as = view_as
|
@view_as = view_as
|
||||||
@user_can_destroy = user_can_destroy
|
@user_can_destroy = user_can_destroy
|
||||||
|
@user_can_replace = user_can_replace
|
||||||
|
|
||||||
# attachment passed by kwarg because we don't want a default (nil) value.
|
# attachment passed by kwarg because we don't want a default (nil) value.
|
||||||
@attachment = if kwargs.key?(:attachment)
|
@attachment = if kwargs.key?(:attachment)
|
||||||
|
@ -64,13 +67,14 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
def file_field_options
|
def file_field_options
|
||||||
track_issue_with_missing_validators if missing_validators?
|
track_issue_with_missing_validators if missing_validators?
|
||||||
{
|
{
|
||||||
class: "fr-upload attachment-input #{attachment_input_class} #{persisted? ? 'hidden' : ''}",
|
class: class_names("fr-upload attachment-input": true, "#{attachment_input_class}": true, "hidden": persisted?, "fr-mt-2w": user_can_replace?),
|
||||||
direct_upload: @direct_upload,
|
direct_upload: @direct_upload,
|
||||||
id: input_id,
|
id: input_id,
|
||||||
aria: { describedby: champ&.describedby_id },
|
aria: { describedby: champ&.describedby_id },
|
||||||
data: {
|
data: {
|
||||||
auto_attach_url:
|
auto_attach_url:
|
||||||
}.merge(has_file_size_validator? ? { max_file_size: } : {})
|
}.merge(has_file_size_validator? ? { max_file_size: } : {})
|
||||||
|
.merge(user_can_replace? ? { replace_attachment_target: "input" } : {})
|
||||||
}.merge(has_content_type_validator? ? { accept: accept_content_type } : {})
|
}.merge(has_content_type_validator? ? { accept: accept_content_type } : {})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -103,6 +107,24 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def replace_button_options
|
||||||
|
{
|
||||||
|
type: 'button',
|
||||||
|
data: {
|
||||||
|
action: "click->replace-attachment#open",
|
||||||
|
auto_attach_url: auto_attach_url
|
||||||
|
}.compact
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace_controller_attributes
|
||||||
|
return {} if !persisted? || !user_can_replace? || as_multiple?
|
||||||
|
|
||||||
|
{
|
||||||
|
"data-controller": 'replace-attachment'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def retry_button_options
|
def retry_button_options
|
||||||
{
|
{
|
||||||
type: 'button',
|
type: 'button',
|
||||||
|
@ -155,7 +177,9 @@ class Attachment::EditComponent < ApplicationComponent
|
||||||
def auto_attach_url
|
def auto_attach_url
|
||||||
return @auto_attach_url if @auto_attach_url.present?
|
return @auto_attach_url if @auto_attach_url.present?
|
||||||
|
|
||||||
return helpers.auto_attach_url(@champ) if @champ.present?
|
params = { replace_attachment_id: @attachment.id } if user_can_replace? && @attachment.present?
|
||||||
|
|
||||||
|
return helpers.auto_attach_url(@champ, params) if @champ.present?
|
||||||
|
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,9 @@ en:
|
||||||
allowed_formats: "Supported formats : %{formats}"
|
allowed_formats: "Supported formats : %{formats}"
|
||||||
retry: Retry
|
retry: Retry
|
||||||
delete: Delete
|
delete: Delete
|
||||||
|
delete_file: Delete file %{filename}
|
||||||
|
replace: Replace
|
||||||
|
replace_file: Replace file %{filename}
|
||||||
errors:
|
errors:
|
||||||
uploading: "An error occurred while sending the file."
|
uploading: "An error occurred while sending the file."
|
||||||
virus_infected: "Virus detected, please send another file."
|
virus_infected: "Virus detected, please send another file."
|
||||||
|
|
|
@ -4,6 +4,9 @@ fr:
|
||||||
allowed_formats: "Formats supportés : %{formats}"
|
allowed_formats: "Formats supportés : %{formats}"
|
||||||
retry: Réessayer
|
retry: Réessayer
|
||||||
delete: Supprimer
|
delete: Supprimer
|
||||||
|
delete_file: Supprimer le fichier %{filename}
|
||||||
|
replace: Remplacer
|
||||||
|
replace_file: Remplacer le fichier %{filename}
|
||||||
errors:
|
errors:
|
||||||
uploading: "Une erreur s’est produite pendant l’envoi du fichier."
|
uploading: "Une erreur s’est produite pendant l’envoi du fichier."
|
||||||
virus_infected: "Virus détecté, merci d’envoyer un autre fichier."
|
virus_infected: "Virus détecté, merci d’envoyer un autre fichier."
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
.attachment.fr-upload-group{ { id: attachment ? dom_id(attachment, :edit) : nil, class: class_names("fr-mb-2w": !(as_multiple? && downloadable?)) }.compact }
|
.attachment.fr-upload-group{ { id: attachment ? dom_id(attachment, :edit) : nil, class: class_names("fr-mb-2w": !(as_multiple? && downloadable?)) }.compact, **replace_controller_attributes }
|
||||||
- if persisted?
|
- if persisted?
|
||||||
%div{ id: dom_id(attachment, :persisted_row) }
|
%div{ id: dom_id(attachment, :persisted_row) }
|
||||||
.flex.flex-gap-2{ class: class_names("attachment-error": attachment.virus_scanner_error?) }
|
.flex.flex-gap-2{ class: class_names("attachment-error": attachment.virus_scanner_error?) }
|
||||||
- if user_can_destroy?
|
- if user_can_destroy?
|
||||||
= link_to(t('.delete'), destroy_attachment_path, **remove_button_options, class: "fr-btn fr-btn--tertiary fr-btn--sm fr-icon-delete-line", title: "Supprimer le fichier #{attachment.filename}")
|
= link_to(t('.delete'), destroy_attachment_path, **remove_button_options, class: "fr-btn fr-btn--tertiary fr-btn--sm fr-icon-delete-line", title: t(".delete_file", filename: attachment.filename))
|
||||||
|
- elsif user_can_replace?
|
||||||
|
= button_tag t('.replace'), **replace_button_options, class: "fr-btn fr-btn--tertiary fr-btn--sm", title: t(".replace_file", filename: attachment.filename)
|
||||||
|
|
||||||
.fr-py-1v
|
|
||||||
- if downloadable?
|
- if downloadable?
|
||||||
= render Dsfr::DownloadComponent.new(attachment:)
|
= render Dsfr::DownloadComponent.new(attachment:)
|
||||||
- else
|
- else
|
||||||
|
.fr-py-1v
|
||||||
%span.attachment-filename.fr-mr-1w= link_to_if(viewable?, attachment.filename.to_s, helpers.url_for(attachment.blob), title: "Ouvrir le fichier #{attachment.filename.to_s}", **helpers.external_link_attributes)
|
%span.attachment-filename.fr-mr-1w= link_to_if(viewable?, attachment.filename.to_s, helpers.url_for(attachment.blob), title: "Ouvrir le fichier #{attachment.filename.to_s}", **helpers.external_link_attributes)
|
||||||
|
|
||||||
= render Attachment::ProgressComponent.new(attachment: attachment)
|
= render Attachment::ProgressComponent.new(attachment: attachment)
|
||||||
|
|
|
@ -12,15 +12,18 @@ class Attachment::MultipleComponent < ApplicationComponent
|
||||||
attr_reader :view_as
|
attr_reader :view_as
|
||||||
attr_reader :user_can_destroy
|
attr_reader :user_can_destroy
|
||||||
alias user_can_destroy? user_can_destroy
|
alias user_can_destroy? user_can_destroy
|
||||||
|
attr_reader :user_can_replace
|
||||||
|
alias user_can_replace? user_can_replace
|
||||||
|
|
||||||
delegate :count, :empty?, to: :attachments, prefix: true
|
delegate :count, :empty?, to: :attachments, prefix: true
|
||||||
|
|
||||||
def initialize(champ:, attached_file:, form_object_name: nil, view_as: :link, user_can_destroy: true, max: nil)
|
def initialize(champ:, attached_file:, form_object_name: nil, view_as: :link, user_can_destroy: true, user_can_replace: false, max: nil)
|
||||||
@champ = champ
|
@champ = champ
|
||||||
@attached_file = attached_file
|
@attached_file = attached_file
|
||||||
@form_object_name = form_object_name
|
@form_object_name = form_object_name
|
||||||
@view_as = view_as
|
@view_as = view_as
|
||||||
@user_can_destroy = user_can_destroy
|
@user_can_destroy = user_can_destroy
|
||||||
|
@user_can_replace = user_can_replace
|
||||||
@max = max || DEFAULT_MAX_ATTACHMENTS
|
@max = max || DEFAULT_MAX_ATTACHMENTS
|
||||||
|
|
||||||
@attachments = attached_file.attachments || []
|
@attachments = attached_file.attachments || []
|
||||||
|
@ -48,4 +51,12 @@ class Attachment::MultipleComponent < ApplicationComponent
|
||||||
|
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def replace_controller_attributes
|
||||||
|
return {} unless user_can_replace?
|
||||||
|
|
||||||
|
{
|
||||||
|
"data-controller": 'replace-attachment'
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
.fr-mb-4w.attachment-multiple{ class: class_names("fr-downloads-group": view_as == :download, "destroyable": user_can_destroy?) }
|
.fr-mb-4w.attachment-multiple{ class: class_names("fr-downloads-group": view_as == :download, "destroyable": user_can_destroy?), **replace_controller_attributes }
|
||||||
= template
|
= template
|
||||||
|
|
||||||
%ul
|
%ul
|
||||||
- each_attachment do |attachment, index|
|
- each_attachment do |attachment, index|
|
||||||
%li{ id: dom_id(attachment) }
|
%li{ id: dom_id(attachment) }
|
||||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment:, index:, as_multiple: true, view_as:, user_can_destroy:, form_object_name:)
|
= render Attachment::EditComponent.new(champ:, attached_file:, attachment:, index:, as_multiple: true, view_as:, user_can_destroy:, user_can_replace:, form_object_name:)
|
||||||
|
|
||||||
%div{ id: empty_component_id, class: class_names("hidden": !can_attach_next?) }
|
%div{ id: empty_component_id, class: class_names("hidden": !can_attach_next?) }
|
||||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment: nil, index: attachments_count, user_can_destroy:, form_object_name:)
|
= render Attachment::EditComponent.new(champ:, attached_file:, attachment: nil, index: attachments_count, user_can_destroy:, user_can_replace:, form_object_name:)
|
||||||
|
|
||||||
// single poll and refresh message for all attachments
|
// single poll and refresh message for all attachments
|
||||||
= render Attachment::PendingPollComponent.new(attachments: attachments, poll_url:, context: poll_context)
|
= render Attachment::PendingPollComponent.new(attachments: attachments, poll_url:, context: poll_context)
|
||||||
|
|
|
@ -11,6 +11,10 @@ class EditableChamp::PieceJustificativeComponent < EditableChamp::EditableChampB
|
||||||
!@champ.mandatory? || @champ.dossier.brouillon?
|
!@champ.mandatory? || @champ.dossier.brouillon?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_can_replace?
|
||||||
|
@champ.mandatory? && @champ.dossier.en_construction?
|
||||||
|
end
|
||||||
|
|
||||||
def max
|
def max
|
||||||
[true, nil].include?(@champ.procedure&.piece_justificative_multiple?) ? Attachment::MultipleComponent::DEFAULT_MAX_ATTACHMENTS : 1
|
[true, nil].include?(@champ.procedure&.piece_justificative_multiple?) ? Attachment::MultipleComponent::DEFAULT_MAX_ATTACHMENTS : 1
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
= render Attachment::MultipleComponent.new(champ: @champ, attached_file: @champ.piece_justificative_file, form_object_name: @form.object_name, view_as:, user_can_destroy: user_can_destroy?, max:) do |c|
|
= render Attachment::MultipleComponent.new(champ: @champ, attached_file: @champ.piece_justificative_file, form_object_name: @form.object_name, view_as:, user_can_destroy: user_can_destroy?, user_can_replace: user_can_replace?, max:) do |c|
|
||||||
- if @champ.type_de_champ.piece_justificative_template&.attached?
|
- if @champ.type_de_champ.piece_justificative_template&.attached?
|
||||||
- c.with_template do
|
- c.with_template do
|
||||||
= render partial: "shared/piece_justificative_template", locals: { champ: @champ }
|
= render partial: "shared/piece_justificative_template", locals: { champ: @champ }
|
||||||
|
|
|
@ -1,2 +1,9 @@
|
||||||
class EditableChamp::TitreIdentiteComponent < EditableChamp::EditableChampBaseComponent
|
class EditableChamp::TitreIdentiteComponent < EditableChamp::EditableChampBaseComponent
|
||||||
|
def user_can_destroy?
|
||||||
|
!@champ.mandatory? || @champ.dossier.brouillon?
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_can_replace?
|
||||||
|
@champ.mandatory? && @champ.dossier.en_construction?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- user_can_destroy = !@champ.mandatory? || @champ.dossier.brouillon?
|
|
||||||
|
|
||||||
- if @champ.type_de_champ.piece_justificative_template&.attached?
|
- if @champ.type_de_champ.piece_justificative_template&.attached?
|
||||||
= render partial: "shared/piece_justificative_template", locals: { champ: @champ }
|
= render partial: "shared/piece_justificative_template", locals: { champ: @champ }
|
||||||
= render Attachment::EditComponent.new(champ: @form.object, attached_file: @champ.piece_justificative_file, attachment: @champ.piece_justificative_file[0], form_object_name: @form.object_name, user_can_destroy:)
|
= render Attachment::EditComponent.new(champ: @form.object, attached_file: @champ.piece_justificative_file, attachment: @champ.piece_justificative_file[0], form_object_name: @form.object_name,
|
||||||
|
user_can_destroy: user_can_destroy?, user_can_replace: user_can_replace?)
|
||||||
|
|
|
@ -28,9 +28,22 @@ class Champs::PieceJustificativeController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def attach_piece_justificative
|
def attach_piece_justificative
|
||||||
|
save_succeed = nil
|
||||||
|
|
||||||
|
ActiveStorage::Attachment.transaction do
|
||||||
|
if params.key?(:replace_attachment_id)
|
||||||
|
@champ.piece_justificative_file.attachments.find do
|
||||||
|
_1.id == params[:replace_attachment_id].to_i
|
||||||
|
end&.destroy
|
||||||
|
end
|
||||||
|
|
||||||
@champ.piece_justificative_file.attach(params[:blob_signed_id])
|
@champ.piece_justificative_file.attach(params[:blob_signed_id])
|
||||||
|
|
||||||
save_succeed = @champ.save
|
save_succeed = @champ.save
|
||||||
|
end
|
||||||
|
|
||||||
@champ.dossier.update(last_champ_updated_at: Time.zone.now.utc) if save_succeed
|
@champ.dossier.update(last_champ_updated_at: Time.zone.now.utc) if save_succeed
|
||||||
|
|
||||||
save_succeed
|
save_succeed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,11 @@ module ChampHelper
|
||||||
simple_format(auto_linked_text, {}, sanitize: false)
|
simple_format(auto_linked_text, {}, sanitize: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def auto_attach_url(object)
|
def auto_attach_url(object, params = {})
|
||||||
if object.is_a?(Champ)
|
if object.is_a?(Champ)
|
||||||
champs_attach_piece_justificative_url(object.id)
|
champs_attach_piece_justificative_url(object.id, params)
|
||||||
elsif object.is_a?(TypeDeChamp)
|
elsif object.is_a?(TypeDeChamp)
|
||||||
piece_justificative_template_admin_procedure_type_de_champ_url(stable_id: object.stable_id, procedure_id: object.procedure.id)
|
piece_justificative_template_admin_procedure_type_de_champ_url(stable_id: object.stable_id, procedure_id: object.procedure.id, **params)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
30
app/javascript/controllers/replace_attachment_controller.ts
Normal file
30
app/javascript/controllers/replace_attachment_controller.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { ApplicationController } from './application_controller';
|
||||||
|
import { show } from '@utils';
|
||||||
|
|
||||||
|
export class ReplaceAttachmentController extends ApplicationController {
|
||||||
|
static targets = ['input'];
|
||||||
|
|
||||||
|
declare readonly inputTarget: HTMLInputElement;
|
||||||
|
|
||||||
|
open(event: Event) {
|
||||||
|
show(this.inputTarget);
|
||||||
|
this.inputTarget.click(); // opens input prompt
|
||||||
|
|
||||||
|
const target = event.currentTarget as HTMLButtonElement;
|
||||||
|
|
||||||
|
if (target.dataset.autoAttachUrl) {
|
||||||
|
// set the auto attach url specific to this button to replace the related attachment
|
||||||
|
this.inputTarget.dataset.originalAutoAttachUrl =
|
||||||
|
this.inputTarget.dataset.autoAttachUrl;
|
||||||
|
|
||||||
|
this.inputTarget.dataset.autoAttachUrl = target.dataset.autoAttachUrl;
|
||||||
|
|
||||||
|
// reset autoAttachUrl which would add an attachment
|
||||||
|
// when replace is not finalized
|
||||||
|
this.inputTarget.addEventListener('cancel', () => {
|
||||||
|
this.inputTarget.dataset.autoAttachUrl =
|
||||||
|
this.inputTarget.dataset.originalAutoAttachUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,13 +38,7 @@ RSpec.describe Attachment::MultipleComponent, type: :component do
|
||||||
|
|
||||||
context 'when there is an attachment' do
|
context 'when there is an attachment' do
|
||||||
before do
|
before do
|
||||||
attached_file.attach(
|
attach_to_champ(attached_file, champ)
|
||||||
io: StringIO.new("x" * 2),
|
|
||||||
filename: "me.jpg",
|
|
||||||
content_type: "image/jpeg",
|
|
||||||
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
|
|
||||||
)
|
|
||||||
champ.save!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders the filenames' do
|
it 'renders the filenames' do
|
||||||
|
@ -98,4 +92,26 @@ RSpec.describe Attachment::MultipleComponent, type: :component do
|
||||||
expect(subject).to have_selector('[data-controller=turbo-poll]')
|
expect(subject).to have_selector('[data-controller=turbo-poll]')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when user can replace' do
|
||||||
|
let(:kwargs) { { user_can_replace: true } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
attach_to_champ(attached_file, champ)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'setup controller' do
|
||||||
|
expect(subject).to have_selector('[data-controller=replace-attachment]').once
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def attach_to_champ(attached_file, champ)
|
||||||
|
attached_file.attach(
|
||||||
|
io: StringIO.new("x" * 2),
|
||||||
|
filename: "me.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
|
||||||
|
)
|
||||||
|
champ.save!
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,8 @@ describe Champs::PieceJustificativeController, type: :controller do
|
||||||
let(:champ) { dossier.champs_public.first }
|
let(:champ) { dossier.champs_public.first }
|
||||||
|
|
||||||
describe '#update' do
|
describe '#update' do
|
||||||
|
let(:replace_attachment_id) { nil }
|
||||||
|
|
||||||
render_views
|
render_views
|
||||||
before { sign_in user }
|
before { sign_in user }
|
||||||
|
|
||||||
|
@ -12,8 +14,9 @@ describe Champs::PieceJustificativeController, type: :controller do
|
||||||
put :update, params: {
|
put :update, params: {
|
||||||
position: '1',
|
position: '1',
|
||||||
champ_id: champ.id,
|
champ_id: champ.id,
|
||||||
blob_signed_id: file
|
blob_signed_id: file,
|
||||||
}, format: :turbo_stream
|
replace_attachment_id:
|
||||||
|
}.compact, format: :turbo_stream
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the file is valid' do
|
context 'when the file is valid' do
|
||||||
|
@ -65,6 +68,33 @@ describe Champs::PieceJustificativeController, type: :controller do
|
||||||
expect(JSON.parse(response.body)).to eq({ 'errors' => ['La pièce justificative n’est pas d’un type accepté'] })
|
expect(JSON.parse(response.body)).to eq({ 'errors' => ['La pièce justificative n’est pas d’un type accepté'] })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'replace an attachment' do
|
||||||
|
let(:file) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||||
|
before { subject }
|
||||||
|
|
||||||
|
context "attachment associated to dossier" do
|
||||||
|
let(:champ) { create(:champ, :with_piece_justificative_file, dossier:) }
|
||||||
|
let(:replace_attachment_id) { champ.piece_justificative_file.first.id }
|
||||||
|
|
||||||
|
it "replaces an existing attachment" do
|
||||||
|
champ.reload
|
||||||
|
|
||||||
|
expect(champ.piece_justificative_file.attachments.count).to eq(1)
|
||||||
|
expect(champ.piece_justificative_file.attachments.first.filename).to eq("piece_justificative_0.pdf")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "attachment not associated to dossier" do
|
||||||
|
let(:other_champ) { create(:champ, :with_piece_justificative_file) }
|
||||||
|
let(:replace_attachment_id) { other_champ.piece_justificative_file.first.id }
|
||||||
|
|
||||||
|
it "add attachment, don't replace attachment" do
|
||||||
|
expect(champ.reload.piece_justificative_file.attachments.count).to eq(1)
|
||||||
|
expect(other_champ.reload.piece_justificative_file.attachments.count).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#template' do
|
describe '#template' do
|
||||||
|
|
77
spec/system/users/en_construction_spec.rb
Normal file
77
spec/system/users/en_construction_spec.rb
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
describe "Dossier en_construction" do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:procedure) { create(:simple_procedure, :with_piece_justificative, :with_titre_identite) }
|
||||||
|
let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_populated_champs, user:, procedure:) }
|
||||||
|
|
||||||
|
let(:tdc) {
|
||||||
|
procedure.active_revision.types_de_champ_public.find { _1.type_champ == "piece_justificative" }
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:champ) {
|
||||||
|
dossier.champs_public.find { _1.type_de_champ_id == tdc.id }
|
||||||
|
}
|
||||||
|
|
||||||
|
scenario 'delete a non mandatory piece justificative', js: true do
|
||||||
|
visit_dossier(dossier)
|
||||||
|
|
||||||
|
expect(page).not_to have_button("Remplacer")
|
||||||
|
click_on "Supprimer le fichier toto.txt"
|
||||||
|
|
||||||
|
expect(page).not_to have_text("toto.txt")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a mandatory piece justificative" do
|
||||||
|
before do
|
||||||
|
tdc.update_attribute(:mandatory, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'remplace a mandatory piece justificative', js: true do
|
||||||
|
visit_dossier(dossier)
|
||||||
|
|
||||||
|
click_on "Remplacer le fichier toto.txt"
|
||||||
|
|
||||||
|
input_selector = "#attachment-multiple-empty-#{champ.id}"
|
||||||
|
expect(page).to have_selector(input_selector)
|
||||||
|
find(input_selector).attach_file(Rails.root.join('spec/fixtures/files/file.pdf'))
|
||||||
|
|
||||||
|
expect(page).to have_text("file.pdf")
|
||||||
|
expect(page).not_to have_text("toto.txt")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a mandatory titre identite" do
|
||||||
|
let(:tdc) {
|
||||||
|
procedure.active_revision.types_de_champ_public.find { _1.type_champ == "titre_identite" }
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
tdc.update_attribute(:mandatory, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'remplace a mandatory titre identite', js: true do
|
||||||
|
visit_dossier(dossier)
|
||||||
|
|
||||||
|
click_on "Remplacer le fichier toto.png"
|
||||||
|
|
||||||
|
input_selector = ".attachment-input-#{champ.piece_justificative_file.attachments.first.id}"
|
||||||
|
expect(page).to have_selector(input_selector)
|
||||||
|
find(input_selector).attach_file(Rails.root.join('spec/fixtures/files/file.pdf'))
|
||||||
|
|
||||||
|
expect(page).to have_text("file.pdf")
|
||||||
|
expect(page).not_to have_text("toto.png")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def visit_dossier(dossier)
|
||||||
|
visit modifier_dossier_path(dossier)
|
||||||
|
|
||||||
|
expect(page).to have_current_path(new_user_session_path)
|
||||||
|
fill_in 'user_email', with: user.email
|
||||||
|
fill_in 'user_password', with: user.password
|
||||||
|
click_on 'Se connecter'
|
||||||
|
|
||||||
|
expect(page).to have_current_path(modifier_dossier_path(dossier))
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue