2022-05-11 08:57:25 +02:00
# Display a widget for uploading, editing and deleting a file attachment
class Attachment :: EditComponent < ApplicationComponent
2022-10-25 14:14:24 +02:00
attr_reader :template , :form , :attachment
delegate :persisted? , to : :attachment , allow_nil : true
2022-10-29 16:08:59 +02:00
def initialize ( form : , attached_file : , user_can_destroy : false , direct_upload : true , id : nil , index : 0 , ** kwargs )
2022-05-11 08:57:25 +02:00
@form = form
@attached_file = attached_file
2022-10-25 14:14:24 +02:00
2022-10-29 16:08:59 +02:00
@attachment = if kwargs . key? ( :attachment )
kwargs [ :attachment ]
2022-10-25 14:14:24 +02:00
elsif attached_file . respond_to? ( :attachment )
attached_file . attachment
else
2022-10-29 16:08:59 +02:00
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. "
2022-10-25 14:14:24 +02:00
end
2022-05-11 08:57:25 +02:00
@user_can_destroy = user_can_destroy
@direct_upload = direct_upload
2022-06-16 14:56:53 +02:00
@id = id
2022-10-25 14:14:24 +02:00
@index = index
2022-05-11 08:57:25 +02:00
end
2022-06-16 15:51:45 +02:00
def max_file_size
file_size_validator . options [ :less_than ]
2022-05-11 08:57:25 +02:00
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
2022-10-25 14:14:24 +02:00
@attachment_id || = ( attachment & . id || SecureRandom . uuid )
2022-05-11 08:57:25 +02:00
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
2022-07-05 16:31:53 +02:00
track_issue_with_missing_validators if missing_validators?
2022-05-11 08:57:25 +02:00
{
class : " attachment-input #{ attachment_input_class } #{ 'hidden' if persisted? } " ,
direct_upload : @direct_upload ,
2022-06-16 15:51:45 +02:00
id : input_id ( @id ) ,
2022-05-11 08:57:25 +02:00
aria : { describedby : champ & . describedby_id } ,
2022-06-16 15:51:45 +02:00
data : {
2022-10-25 14:14:24 +02:00
auto_attach_url :
} . merge ( has_file_size_validator? ? { max_file_size : } : { } )
2022-09-09 15:54:13 +02:00
} . merge ( has_content_type_validator? ? { accept : accept_content_type } : { } )
2022-05-11 08:57:25 +02:00
end
2022-10-25 14:14:24 +02:00
def auto_attach_url
2022-10-29 13:35:22 +02:00
helpers . auto_attach_url ( form . object )
2022-10-25 14:14:24 +02:00
end
2022-06-16 15:51:45 +02:00
def input_id ( given_id )
2022-10-25 14:14:24 +02:00
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
2022-06-16 15:51:45 +02:00
end
2022-05-11 08:57:25 +02:00
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
2022-06-16 15:51:45 +02:00
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
2022-07-05 16:31:53 +02:00
2022-09-09 15:54:13 +02:00
def accept_content_type
list = content_type_validator . options [ :in ]
if list . include? ( " application/octet-stream " )
list . push ( " .acidcsa " )
end
list . join ( ', ' )
end
2022-07-05 16:31:53 +02:00
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
2022-05-11 08:57:25 +02:00
end