2019-08-06 17:54:17 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# Define un campo de imagen
|
2019-08-22 01:09:29 +00:00
|
|
|
# TODO: Validar que sea una imagen
|
2019-08-06 17:54:17 +00:00
|
|
|
class MetadataImage < MetadataTemplate
|
|
|
|
# Una ruta vacía a la imagen con una descripción vacía
|
|
|
|
def default_value
|
2019-08-22 19:13:21 +00:00
|
|
|
{ 'path' => nil, 'description' => nil }
|
2019-08-06 17:54:17 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def empty?
|
|
|
|
value == default_value
|
|
|
|
end
|
2019-08-13 23:33:57 +00:00
|
|
|
|
2019-08-22 19:13:21 +00:00
|
|
|
def validate
|
|
|
|
super
|
|
|
|
|
|
|
|
errors << I18n.t('metadata.image.path_required') if path_missing?
|
2019-08-23 18:24:41 +00:00
|
|
|
errors << I18n.t('metadata.image.not_an_image') unless image?
|
2019-08-22 19:13:21 +00:00
|
|
|
|
|
|
|
errors.compact!
|
|
|
|
errors.empty?
|
|
|
|
end
|
|
|
|
|
|
|
|
# Determina si necesitamos la imagen pero no la tenemos
|
|
|
|
def path_missing?
|
|
|
|
required && !value['path'].blank?
|
|
|
|
end
|
|
|
|
|
|
|
|
# Determina si el archivo ya fue subido
|
|
|
|
def uploaded?
|
|
|
|
value['path'].is_a?(String)
|
|
|
|
end
|
|
|
|
|
2019-08-23 18:24:41 +00:00
|
|
|
# Determina si es una imagen antes de subirla
|
|
|
|
def image?
|
|
|
|
if value['path'].is_a? ActionDispatch::Http::UploadedFile
|
|
|
|
`file --mime-type "#{value['path'].tempfile.path}"`
|
|
|
|
.split(' ')
|
|
|
|
.last
|
|
|
|
.chomp
|
|
|
|
.starts_with? 'image/'
|
|
|
|
else
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-08-22 19:13:21 +00:00
|
|
|
# Determina si la ruta es opcional pero deja pasar si la ruta se
|
|
|
|
# especifica
|
|
|
|
def path_optional?
|
|
|
|
!required && value['path'].blank?
|
|
|
|
end
|
|
|
|
|
2019-08-22 01:09:29 +00:00
|
|
|
# Asociar la imagen subida al sitio y obtener la ruta
|
|
|
|
def save
|
2019-08-22 19:13:21 +00:00
|
|
|
return true if uploaded?
|
|
|
|
return true if path_optional?
|
2019-08-22 01:09:29 +00:00
|
|
|
return false unless hardlink.zero?
|
|
|
|
|
|
|
|
# Modificar el valor actual
|
|
|
|
value['path'] = relative_destination_path
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2019-08-13 23:33:57 +00:00
|
|
|
def to_param
|
|
|
|
{ name => %i[description path] }
|
|
|
|
end
|
2019-08-22 01:09:29 +00:00
|
|
|
|
|
|
|
# Almacena el archivo en el sitio y lo devuelve
|
|
|
|
# XXX: ActiveStorage devuelve un Array al guardar
|
|
|
|
#
|
|
|
|
# @return ActiveStorage::Attachment
|
|
|
|
def static_file
|
2019-08-22 19:13:21 +00:00
|
|
|
if uploaded?
|
2019-08-22 01:09:29 +00:00
|
|
|
blob = ActiveStorage::Blob.find_by(key: key_from_path)
|
|
|
|
@static_file ||= site.static_files.find_by(blob_id: blob.id)
|
|
|
|
else
|
|
|
|
@static_file ||= site.static_files.attach(value['path']).first
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def key_from_path
|
|
|
|
# XXX: No podemos usar self#extension porque en este punto todavía
|
|
|
|
# no sabemos el static_file
|
|
|
|
File.basename(value['path'], '.*')
|
|
|
|
end
|
|
|
|
|
|
|
|
# Hacemos un link duro para colocar el archivo dentro del repositorio
|
|
|
|
# y no duplicar el espacio que ocupan. Esto requiere que ambos
|
|
|
|
# directorios estén dentro del mismo punto de montaje.
|
|
|
|
def hardlink
|
|
|
|
FileUtils.mkdir_p File.dirname(destination_path)
|
|
|
|
FileUtils.ln uploaded_path, destination_path
|
|
|
|
end
|
|
|
|
|
|
|
|
def extension
|
|
|
|
static_file.blob.content_type.split('/').last
|
|
|
|
end
|
|
|
|
|
|
|
|
# Obtener la ruta al archivo
|
|
|
|
# https://stackoverflow.com/a/53908358
|
|
|
|
def uploaded_relative_path
|
|
|
|
ActiveStorage::Blob.service.path_for(static_file.key)
|
|
|
|
end
|
|
|
|
|
|
|
|
def uploaded_path
|
|
|
|
Rails.root.join uploaded_relative_path
|
|
|
|
end
|
|
|
|
|
|
|
|
def relative_destination_path
|
|
|
|
File.join('public', [static_file.key, extension].join('.'))
|
|
|
|
end
|
|
|
|
|
|
|
|
def destination_path
|
|
|
|
File.join(site.path, relative_destination_path)
|
|
|
|
end
|
2019-08-06 17:54:17 +00:00
|
|
|
end
|