refactor(attachment): bring batch user_can_destroy, update tests
This commit is contained in:
parent
df135b080b
commit
b609c3dae4
9 changed files with 152 additions and 89 deletions
|
@ -4,12 +4,14 @@ class Attachment::EditComponent < ApplicationComponent
|
|||
attr_reader :attachment
|
||||
attr_reader :user_can_download
|
||||
alias user_can_download? user_can_download
|
||||
attr_reader :user_can_destroy
|
||||
alias user_can_destroy? user_can_destroy
|
||||
attr_reader :as_multiple
|
||||
alias as_multiple? as_multiple
|
||||
|
||||
EXTENSIONS_ORDER = ['jpeg', 'png', 'pdf', 'zip'].freeze
|
||||
|
||||
def initialize(champ: nil, auto_attach_url: nil, field_name: nil, attached_file:, direct_upload: true, index: 0, as_multiple: false, user_can_download: false, **kwargs)
|
||||
def initialize(champ: nil, auto_attach_url: nil, field_name: nil, attached_file:, direct_upload: true, index: 0, as_multiple: false, user_can_download: false, user_can_destroy: true, **kwargs)
|
||||
@as_multiple = as_multiple
|
||||
@attached_file = attached_file
|
||||
@auto_attach_url = auto_attach_url
|
||||
|
@ -17,6 +19,7 @@ class Attachment::EditComponent < ApplicationComponent
|
|||
@direct_upload = direct_upload
|
||||
@index = index
|
||||
@user_can_download = user_can_download
|
||||
@user_can_destroy = user_can_destroy
|
||||
|
||||
# attachment passed by kwarg because we don't want a default (nil) value.
|
||||
@attachment = if kwargs.key?(:attachment)
|
||||
|
@ -128,6 +131,14 @@ class Attachment::EditComponent < ApplicationComponent
|
|||
!!attachment&.persisted?
|
||||
end
|
||||
|
||||
def downloadable?
|
||||
return false unless user_can_download?
|
||||
return false if attachment.virus_scanner_error?
|
||||
return false if attachment.watermark_pending?
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def error?
|
||||
attachment.virus_scanner_error?
|
||||
end
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
- if persisted?
|
||||
%div{ id: dom_id(attachment, :persisted_row) }
|
||||
.flex.flex-gap-2{ class: class_names("attachment-error": attachment.virus_scanner_error?) }
|
||||
= link_to('Supprimer', 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}")
|
||||
- if user_can_destroy?
|
||||
= link_to('Supprimer', 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}")
|
||||
|
||||
.fr-py-1v
|
||||
= link_to_if(user_can_download?, attachment.filename.to_s, attachment.url, class: "attachment-filename", download: "") do
|
||||
%span.attachment-filename= attachment.filename.to_s
|
||||
- if in_progress?
|
||||
%p.fr-badge.fr-badge--info.fr-badge--sm.fr-badge--no-icon.fr-ml-1w
|
||||
= progress_bar_label
|
||||
.fr-py-1v
|
||||
= link_to_if(downloadable?, attachment.filename.to_s, attachment.url, class: "attachment-filename", download: "") do
|
||||
%span.attachment-filename= attachment.filename.to_s
|
||||
- if in_progress?
|
||||
%p.fr-badge.fr-badge--info.fr-badge--sm.fr-badge--no-icon.fr-ml-1w
|
||||
= progress_bar_label
|
||||
|
||||
- if error?
|
||||
%p.fr-error-text= error_message
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
- each_attachment do |attachment, index|
|
||||
%div{ id: dom_id(attachment) }
|
||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment:, index:, as_multiple: true)
|
||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment:, index:, as_multiple: true, user_can_destroy:)
|
||||
|
||||
%div{ id: empty_component_id, class: class_names("hidden": !can_attach_next?) }
|
||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment: nil, index: attachments_count)
|
||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment: nil, index: attachments_count, user_can_destroy:)
|
||||
|
||||
// single poll and refresh message for all attachments
|
||||
- if in_progress?
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
- user_can_destroy = !@champ.mandatory? || @champ.dossier.brouillon?
|
||||
= render Attachment::EditComponent.new(champ: @form.object, attached_file: @champ.piece_justificative_file, attachment: @champ.piece_justificative_file[0])
|
||||
= render Attachment::EditComponent.new(champ: @form.object, attached_file: @champ.piece_justificative_file, attachment: @champ.piece_justificative_file[0], user_can_destroy:)
|
||||
|
|
|
@ -365,6 +365,9 @@
|
|||
%h3.fr-mt-4w Existing attachment
|
||||
= render Attachment::EditComponent.new(champ:, attached_file: champ.piece_justificative_file, attachment:)
|
||||
|
||||
%h3.fr-mt-4w Existing attachment, user can not destroy
|
||||
= render Attachment::EditComponent.new(champ:, attached_file: champ.piece_justificative_file, attachment:, user_can_destroy: false)
|
||||
|
||||
%h3.fr-mt-4w Existing attachment, antivirus in progress
|
||||
- attachment.blob.metadata[:virus_scan_result] = ActiveStorage::VirusScanner::PENDING
|
||||
- attachment.created_at = Time.zone.now
|
||||
|
@ -379,6 +382,7 @@
|
|||
- attachment.blob.metadata[:virus_scan_result] = ActiveStorage::VirusScanner::INFECTED
|
||||
= render Attachment::EditComponent.new(champ:, attached_file: Champ.new.piece_justificative_file, attachment:)
|
||||
|
||||
|
||||
%h3.fr-mt-4w New attachment on TypeDeChamp
|
||||
= render Attachment::EditComponent.new(auto_attach_url: "/some-auto-attach-path", attached_file: tdc.piece_justificative_template, attachment: nil)
|
||||
|
||||
|
|
112
spec/components/attachment/edit_component_spec.rb
Normal file
112
spec/components/attachment/edit_component_spec.rb
Normal file
|
@ -0,0 +1,112 @@
|
|||
RSpec.describe Attachment::EditComponent, type: :component do
|
||||
let(:champ) { create(:champ_titre_identite, dossier: create(:dossier)) }
|
||||
let(:attached_file) { champ.piece_justificative_file }
|
||||
let(:attachment) { attached_file.attachments.first }
|
||||
let(:kwargs) { {} }
|
||||
|
||||
let(:component) do
|
||||
described_class.new(
|
||||
champ:,
|
||||
attached_file:,
|
||||
attachment:,
|
||||
**kwargs
|
||||
)
|
||||
end
|
||||
|
||||
subject { render_inline(component).to_html }
|
||||
|
||||
context 'when there is no attachment yet' do
|
||||
let(:attachment) { nil }
|
||||
|
||||
it 'renders a form field for uploading a file' do
|
||||
expect(subject).to have_selector('input[type=file]:not(.hidden)')
|
||||
end
|
||||
|
||||
it 'renders max size' do
|
||||
expect(subject).to have_content(/Taille maximale :\s+20 Mo/)
|
||||
end
|
||||
|
||||
it 'renders allowed formats' do
|
||||
expect(subject).to have_content(/Formats supportés :\s+jpeg, png/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is an attachment' do
|
||||
it 'renders the filename' do
|
||||
expect(subject).to have_content(attachment.filename.to_s)
|
||||
end
|
||||
|
||||
it 'hides the file field by default' do
|
||||
expect(subject).to have_selector('input[type=file].hidden')
|
||||
end
|
||||
|
||||
it 'shows the Delete button by default' do
|
||||
expect(subject).to have_selector('[title^="Supprimer le fichier"]')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user cannot destroy the attachment' do
|
||||
let(:kwargs) { { user_can_destroy: false } }
|
||||
|
||||
it 'hides the Delete button' do
|
||||
expect(subject).not_to have_selector("[title^='Supprimer le fichier']")
|
||||
end
|
||||
end
|
||||
|
||||
context 'within multiple attachments' do
|
||||
let(:index) { 0 }
|
||||
let(:component) do
|
||||
described_class.new(
|
||||
champ:,
|
||||
attached_file:,
|
||||
attachment: nil,
|
||||
as_multiple: true,
|
||||
index:
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not render an empty file' do # (is is rendered by MultipleComponent)
|
||||
expect(subject).not_to have_selector('input[type=file]')
|
||||
end
|
||||
|
||||
it 'renders max size for first index' do
|
||||
expect(subject).to have_content(/Taille maximale :\s+20 Mo/)
|
||||
end
|
||||
|
||||
context 'when index is not 0' do
|
||||
let(:index) { 1 }
|
||||
|
||||
it 'renders max size for first index' do
|
||||
expect(subject).not_to have_content('Taille maximale')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user can download' do
|
||||
let(:kwargs) { { user_can_download: true } }
|
||||
let(:filename) { champ.piece_justificative_file[0].filename.to_s }
|
||||
|
||||
it 'renders a link to download the file' do
|
||||
expect(subject).to have_link(filename)
|
||||
end
|
||||
|
||||
context 'when watermark is pending' do
|
||||
let(:champ) { create(:champ_titre_identite) }
|
||||
let(:kwargs) { { user_can_download: true } }
|
||||
|
||||
it 'displays the filename, but doesn’t allow to download the file' do
|
||||
expect(attachment.watermark_pending?).to be_truthy
|
||||
expect(subject).to have_text(filename)
|
||||
expect(subject).to have_link('Supprimer')
|
||||
expect(subject).to have_no_link(text: filename) # don't match "Delete" link which also include filename in title attribute
|
||||
expect(subject).to have_text('Traitement en cours')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'TODO: with a pending antivirus scan' do
|
||||
end
|
||||
|
||||
context 'TODO: with an error' do
|
||||
end
|
||||
end
|
|
@ -1,13 +1,21 @@
|
|||
describe 'shared/attachment/_show.html.haml', type: :view do
|
||||
RSpec.describe Attachment::ShowComponent, type: :component do
|
||||
let(:champ) { create(:champ_piece_justificative) }
|
||||
let(:virus_scan_result) { nil }
|
||||
|
||||
let(:attachment) {
|
||||
champ.piece_justificative_file.attachments.first
|
||||
}
|
||||
|
||||
let(:component) do
|
||||
described_class.new(attachment:)
|
||||
end
|
||||
|
||||
subject { render_inline(component).to_html }
|
||||
|
||||
before do
|
||||
champ.piece_justificative_file[0].blob.update(metadata: champ.piece_justificative_file[0].blob.metadata.merge(virus_scan_result: virus_scan_result))
|
||||
end
|
||||
|
||||
subject { render Attachment::ShowComponent.new(attachment: champ.piece_justificative_file.attachments.first) }
|
||||
|
||||
context 'when there is no anti-virus scan' do
|
||||
let(:virus_scan_result) { nil }
|
||||
|
||||
|
@ -27,17 +35,6 @@ describe 'shared/attachment/_show.html.haml', type: :view do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when watermark is pending' do
|
||||
let(:champ) { create(:champ_titre_identite) }
|
||||
|
||||
it 'displays the filename, but doesn’t allow to download the file' do
|
||||
expect(champ.piece_justificative_file.attachments[0].watermark_pending?).to be_truthy
|
||||
expect(subject).to have_text(champ.piece_justificative_file[0].filename.to_s)
|
||||
expect(subject).not_to have_link(champ.piece_justificative_file[0].filename.to_s)
|
||||
expect(subject).to have_text('Traitement en cours')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the file is scanned and safe' do
|
||||
let(:virus_scan_result) { ActiveStorage::VirusScanner::SAFE }
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
describe 'shared/attachment/_update.html.haml', type: :view do
|
||||
let(:champ) { build(:champ_titre_identite, dossier: create(:dossier)) }
|
||||
let(:attached_file) { champ.piece_justificative_file }
|
||||
let(:user_can_destroy) { false }
|
||||
let(:template) { nil }
|
||||
|
||||
subject do
|
||||
view.render Attachment::EditComponent.new(champ: champ, attached_file: attached_file, attachment: attached_file[0])
|
||||
end
|
||||
|
||||
context 'when there is no attached file' do
|
||||
before do
|
||||
champ.piece_justificative_file = nil
|
||||
end
|
||||
|
||||
it 'renders a form field for uploading a file' do
|
||||
expect(subject).to have_selector('input[type=file]:not(.hidden)')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is an attached file' do
|
||||
it 'renders a form field for uploading a file' do
|
||||
expect(subject).to have_selector('input[type=file]:not(.hidden)')
|
||||
end
|
||||
|
||||
it 'does not renders a link to the unsaved file' do
|
||||
expect(subject).not_to have_content(attached_file.attachments[0].filename.to_s)
|
||||
end
|
||||
|
||||
it 'does not render action buttons' do
|
||||
expect(subject).not_to have_link('Supprimer')
|
||||
end
|
||||
|
||||
context 'and the attachment has been saved' do
|
||||
before { champ.save! }
|
||||
|
||||
it 'renders a link to the file' do
|
||||
expect(subject).to have_content(attached_file.attachments[0].filename.to_s)
|
||||
end
|
||||
|
||||
it 'hides the form field by default' do
|
||||
expect(subject).to have_selector('input[type=file].hidden')
|
||||
end
|
||||
|
||||
it 'shows the Delete button by default' do
|
||||
is_expected.to have_link('Supprimer')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user cannot destroy the attachment' do
|
||||
subject do
|
||||
render Attachment::EditComponent.new(champ: champ,
|
||||
attached_file: attached_file,
|
||||
attachment: attached_file[0])
|
||||
end
|
||||
|
||||
it 'hides the Delete button' do
|
||||
is_expected.not_to have_link('Supprimer')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -114,7 +114,7 @@ describe 'shared/dossiers/edit.html.haml', type: :view do
|
|||
before { dossier.champs_public << champ }
|
||||
|
||||
it 'cannot delete a piece justificative' do
|
||||
expect(subject).not_to have_text('Supprimer')
|
||||
expect(subject).not_to have_selector("[title='Supprimer le fichier #{champ.piece_justificative_file.attachments[0].filename}']")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -124,7 +124,7 @@ describe 'shared/dossiers/edit.html.haml', type: :view do
|
|||
end
|
||||
|
||||
it 'can delete a piece justificative' do
|
||||
expect(subject).to have_text('Supprimer')
|
||||
expect(subject).to have_selector("[title='Supprimer le fichier #{champ.piece_justificative_file.attachments[0].filename}']")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue