demarches-normaliennes/app/components/attachment/edit_component.rb

217 lines
5.6 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Display a widget for uploading, editing and deleting a file attachment
class Attachment::EditComponent < ApplicationComponent
attr_reader :champ
attr_reader :attachment
attr_reader :as_multiple
alias as_multiple? as_multiple
EXTENSIONS_ORDER = ['jpeg', 'png', 'pdf', 'zip'].freeze
def initialize(champ: nil, auto_attach_url: nil, attached_file:, direct_upload: true, id: nil, index: 0, as_multiple: false, **kwargs)
@champ = champ
@auto_attach_url = auto_attach_url
@attached_file = attached_file
# attachment passed by kwarg because we don't want a default (nil) value.
@attachment = if kwargs.key?(:attachment)
kwargs.delete(:attachment)
elsif attached_file.respond_to?(:attachment)
attached_file.attachment
else
fail ArgumentError, "You must pass an `attachment` kwarg when not using as single attachment like in #{attached_file.name}. Set it to nil for a new attachment."
end
fail ArgumentError, "Unknown kwarg #{kwargs.keys.join(', ')}" unless kwargs.empty?
@direct_upload = direct_upload
@id = id
@index = index
@as_multiple = as_multiple
end
def object_name
@object.class.name.underscore
end
def first?
@index.zero?
end
def max_file_size
return if file_size_validator.nil?
file_size_validator.options[:less_than]
end
def attachment_id
@attachment_id ||= (attachment&.id || SecureRandom.uuid)
end
def attachment_path(**args)
helpers.attachment_path attachment.id, args.merge(signed_id: attachment.blob.signed_id)
end
def destroy_attachment_path
attachment_path(champ_id: champ&.id)
end
def attachment_input_class
"attachment-input-#{attachment_id}"
end
def file_field_options
track_issue_with_missing_validators if missing_validators?
{
class: "fr-upload attachment-input #{attachment_input_class} #{persisted? ? 'hidden' : ''}",
direct_upload: @direct_upload,
id: input_id(@id),
aria: { describedby: champ&.describedby_id },
data: {
auto_attach_url:
}.merge(has_file_size_validator? ? { max_file_size: } : {})
}.merge(has_content_type_validator? ? { accept: accept_content_type } : {})
end
def in_progress?
return false if attachment.nil?
return true if attachment.virus_scanner.pending?
return true if attachment.watermark_pending?
false
end
def progress_bar_label
case
when attachment.virus_scanner.pending?
"Analyse antivirus en cours…"
when attachment.watermark_pending?
"Traitement en cours…"
end
end
def poll_controller_options
{
controller: 'turbo-poll',
turbo_poll_url_value: poll_url
}
end
def poll_url
if champ.present?
auto_attach_url
else
attachment_path(user_can_edit: true, auto_attach_url: @auto_attach_url)
end
end
def file_field_name
@attached_file.name
end
def remove_button_options
{
role: 'button',
data: { turbo: "true", turbo_method: :delete }
}
end
def retry_button_options
{
type: 'button',
class: 'fr-btn fr-btn--sm fr-btn--tertiary fr-mt-1w fr-icon-refresh-line fr-btn--icon-left attachment-error-retry',
data: { input_target: ".#{attachment_input_class}", action: 'autosave#onClickRetryButton' }
}
end
def persisted?
!!attachment&.persisted?
end
def error?
attachment.virus_scanner_error?
end
def error_message
case
when attachment.virus_scanner.infected?
"Virus détecté, merci denvoyer un autre fichier."
when attachment.virus_scanner.corrupt?
"Le fichier est corrompu, merci denvoyer un autre fichier."
end
end
private
def input_id(given_id)
return given_id if given_id.present?
if champ.present?
# Single or first attachment input must match label "for" attribute. Others must remain unique.
return champ.input_id if @index.zero?
return "#{champ.input_id}_#{attachment_id}"
end
file_field_name
end
def auto_attach_url
return @auto_attach_url if @auto_attach_url.present?
return helpers.auto_attach_url(@champ) if @champ.present?
fail ArgumentError, "You must pass `auto_attach_url` when not using attachment for a Champ"
end
def file_size_validator
@attached_file.record
._validators[file_field_name.to_sym]
.find { |validator| validator.class == ActiveStorageValidations::SizeValidator }
end
def content_type_validator
@attached_file.record
._validators[file_field_name.to_sym]
.find { |validator| validator.class == ActiveStorageValidations::ContentTypeValidator }
end
def accept_content_type
list = content_type_validator.options[:in].dup
list << ".acidcsa" if list.include?("application/octet-stream")
list.join(', ')
end
def allowed_formats
return nil unless champ&.titre_identite?
@allowed_formats ||= begin
content_type_validator.options[:in].filter_map do |content_type|
MiniMime.lookup_by_content_type(content_type)&.extension
end.uniq.sort_by { EXTENSIONS_ORDER.index(_1) || 999 }
end
end
def has_content_type_validator?
!content_type_validator.nil?
end
def has_file_size_validator?
!file_size_validator.nil?
end
def missing_validators?
return true if !has_file_size_validator?
return true if !has_content_type_validator?
return false
end
def track_issue_with_missing_validators
Sentry.capture_message(
"Strange case of missing validator",
extra: {
champ: champ,
file_field_name: file_field_name,
attachment_id: attachment_id
}
)
end
end