5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-05-19 10:20:49 +00:00
panel/app/models/metadata_file.rb
f 5117ffbce3 fix: siempre devolver la ruta completa
closes #6984

closes #7053

closes #7807

closes #7998

closes #8262

closes #8690

closes #8887

closes #9363

closes #9376
2023-01-11 17:04:22 -03:00

175 lines
4.7 KiB
Ruby

# frozen_string_literal: true
require 'filemagic'
# Define un campo de archivo
class MetadataFile < MetadataTemplate
# Una ruta vacía a la imagen con una descripción vacía
def default_value
super || { 'path' => nil, 'description' => nil }
end
def empty?
value == default_value
end
# No hay valores sugeridos para archivos subidos.
#
# XXX: Esto ayuda a deserializar en {Site#everything_of}
def values; end
def validate
super
errors << I18n.t("metadata.#{type}.site_invalid") if site.invalid?
errors << I18n.t("metadata.#{type}.path_required") if path_missing?
errors << I18n.t("metadata.#{type}.attachment_missing") if path? && !static_file
errors.compact!
errors.empty?
end
# Determina si necesitamos la imagen pero no la tenemos
def path_missing?
required && !path?
end
# Determina si el archivo ya fue subido
def uploaded?
value['path'].is_a?(String)
end
# Asociar la imagen subida al sitio y obtener la ruta
# @return [Boolean]
def save
if value['path'].blank?
self[:value] = default_value
else
value['description'] = sanitize value['description']
value['path'] = relative_destination_path_with_filename.to_s if static_file
end
true
end
# Almacena el archivo en el sitio y lo devuelve o lo obtiene de la
# base de datos.
#
# Existen tres casos:
#
# * El archivo fue subido a través de HTTP
# * El archivo es una ruta que apunta a un archivo asociado al sitio
# * El archivo es una ruta a un archivo dentro del repositorio
#
# @todo encontrar una forma de obtener el attachment sin tener que
# recurrir al último subido.
#
# @return [ActiveStorage::Attachment,nil]
def static_file
@static_file ||=
case value['path']
when ActionDispatch::Http::UploadedFile
site.static_files.last if site.static_files.attach(value['path'])
when String
site.static_files.find_by(blob_id: blob_id) || migrate_static_file!
end
end
# Obtiene la ruta absoluta al archivo
#
# @return [Pathname]
def pathname
raise NoMethodError unless uploaded?
@pathname ||= Pathname.new(File.join(site.path, value['path']))
end
# Obtiene la key del attachment a partir de la ruta
#
# @return [String]
def key_from_path
@key_from_path ||= pathname.dirname.basename.to_s
end
def path?
value['path'].present?
end
def description?
value['description'].present?
end
private
# Obtener la ruta al archivo relativa al sitio
#
# @return [Pathname]
def destination_path
Pathname.new(static_file_path)
end
# Agrega el nombre de archivo a la ruta para tener retrocompatibilidad
#
# @return [Pathname]
def destination_path_with_filename
destination_path.realpath
# Si el archivo no llegara a existir, en lugar de hacer fallar todo,
# devolvemos la ruta original, que puede ser el archivo que no existe
# o vacía si se está subiendo uno.
rescue Errno::ENOENT => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] })
Pathname.new(File.join(site.path, value['path']))
end
# Obtener la ruta relativa al sitio.
#
# Si algo falla, devolver la ruta original para no romper el archivo.
#
# @return [String, nil]
def relative_destination_path_with_filename
destination_path_with_filename.relative_path_from(Pathname.new(site.path).realpath)
rescue ArgumentError => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] })
value['path']
end
def static_file_path
case static_file.blob.service.name
when :local
File.join(site.path, 'public', static_file.key, static_file.filename.to_s)
else
static_file.blob.service.path_for(static_file.key)
end
end
# Obtiene el id del blob asociado
#
# @return [Integer,nil]
def blob_id
@blob_id ||= ActiveStorage::Blob.where(key: key_from_path, service_name: site.name).pluck(:id).first
end
# Genera el blob para un archivo que ya se encuentra en el
# repositorio y lo agrega a la base de datos.
#
# @return [ActiveStorage::Attachment]
def migrate_static_file!
raise ArgumentError, 'El archivo no existe' unless path? && pathname.exist?
Site.transaction do
blob =
ActiveStorage::Blob.create_after_unfurling!(key: key_from_path,
io: pathname.open,
filename: pathname.basename,
service_name: site.name)
ActiveStorage::Attachment.create!(name: 'static_files', record: site, blob: blob)
end
rescue ArgumentError => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, path: value['path'] })
nil
end
end