demarches-normaliennes/app/components/attachment/edit_component.rb
2022-12-05 10:47:10 +01:00

150 lines
3.8 KiB
Ruby

# Display a widget for uploading, editing and deleting a file attachment
class Attachment::EditComponent < ApplicationComponent
attr_reader :template, :form, :attachment
delegate :persisted?, to: :attachment, allow_nil: true
def initialize(form:, attached_file:, attachment: nil, user_can_destroy: false, direct_upload: true, id: nil, index: 0)
@form = form
@attached_file = attached_file
@attachment = if attachment
attachment
elsif attached_file.respond_to?(:attachment)
attached_file.attachment
else
# multiple attachments: attachment kwarg is expected, unless adding a new attachment
end
@user_can_destroy = user_can_destroy
@direct_upload = direct_upload
@id = id
@index = index
end
def max_file_size
file_size_validator.options[:less_than]
end
def user_can_destroy?
@user_can_destroy
end
def attachment_path
helpers.attachment_path attachment.id, { signed_id: attachment.blob.signed_id }
end
def attachment_id
@attachment_id ||= (attachment&.id || SecureRandom.uuid)
end
def attachment_input_class
"attachment-input-#{attachment_id}"
end
def champ
@form.object.is_a?(Champ) ? @form.object : nil
end
def file_field_options
track_issue_with_missing_validators if missing_validators?
{
class: "attachment-input #{attachment_input_class} #{'hidden' if persisted?}",
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 auto_attach_url
helpers.auto_attach_url(form.object, replace_attachment_id: persisted? ? attachment_id : nil)
end
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 file_field_name
@attached_file.name
end
def remove_button_options
{
role: 'button',
class: 'button small danger',
data: { turbo_method: :delete }
}
end
def retry_button_options
{
type: 'button',
class: 'button attachment-error-retry',
data: { input_target: ".#{attachment_input_class}", action: 'autosave#onClickRetryButton' }
}
end
def replace_button_options
{
type: 'button',
class: 'button small',
data: { toggle_target: ".#{attachment_input_class}" }
}
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]
if list.include?("application/octet-stream")
list.push(".acidcsa")
end
list.join(', ')
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