diff --git a/app/models/metadata_file.rb b/app/models/metadata_file.rb new file mode 100644 index 00000000..06e69be0 --- /dev/null +++ b/app/models/metadata_file.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +# Define un campo de archivo +class MetadataFile < MetadataTemplate + # Una ruta vacía a la imagen con una descripción vacía + def default_value + { 'path' => nil, 'description' => nil } + end + + def empty? + value == default_value + end + + def validate + super + + errors << I18n.t('metadata.image.path_required') if path_missing? + + 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 + + # Determina si la ruta es opcional pero deja pasar si la ruta se + # especifica + def path_optional? + !required && value['path'].blank? + end + + # Asociar la imagen subida al sitio y obtener la ruta + def save + return true if uploaded? + return true if path_optional? + return false unless hardlink.zero? + + # Modificar el valor actual + value['path'] = relative_destination_path + + true + end + + def to_param + { name => %i[description path] } + end + + # Almacena el archivo en el sitio y lo devuelve + # + # @return ActiveStorage::Attachment + def static_file + ActiveRecord::Base.connection_pool.with_connection do + if uploaded? + blob = ActiveStorage::Blob.find_by(key: key_from_path) + @static_file ||= site.static_files.find_by(blob_id: blob.id) + elsif site.static_files.attach(value['path']) + @static_file ||= site.static_files.last + end + 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 +end diff --git a/app/models/metadata_image.rb b/app/models/metadata_image.rb index 9da909a6..50109ae8 100644 --- a/app/models/metadata_image.rb +++ b/app/models/metadata_image.rb @@ -1,37 +1,16 @@ # frozen_string_literal: true # Define un campo de imagen -# TODO: Validar que sea una imagen -class MetadataImage < MetadataTemplate - # Una ruta vacía a la imagen con una descripción vacía - def default_value - { 'path' => nil, 'description' => nil } - end - - def empty? - value == default_value - end - +class MetadataImage < MetadataFile def validate super - errors << I18n.t('metadata.image.path_required') if path_missing? errors << I18n.t('metadata.image.not_an_image') unless image? 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 - # Determina si es una imagen antes de subirla def image? if value['path'].is_a? ActionDispatch::Http::UploadedFile @@ -44,78 +23,4 @@ class MetadataImage < MetadataTemplate true end end - - # Determina si la ruta es opcional pero deja pasar si la ruta se - # especifica - def path_optional? - !required && value['path'].blank? - end - - # Asociar la imagen subida al sitio y obtener la ruta - def save - return true if uploaded? - return true if path_optional? - return false unless hardlink.zero? - - # Modificar el valor actual - value['path'] = relative_destination_path - - true - end - - def to_param - { name => %i[description path] } - end - - # Almacena el archivo en el sitio y lo devuelve - # - # @return ActiveStorage::Attachment - def static_file - ActiveRecord::Base.connection_pool.with_connection do - if uploaded? - blob = ActiveStorage::Blob.find_by(key: key_from_path) - @static_file ||= site.static_files.find_by(blob_id: blob.id) - elsif site.static_files.attach(value['path']) - @static_file ||= site.static_files.last - end - 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 end diff --git a/app/models/metadata_url.rb b/app/models/metadata_url.rb new file mode 100644 index 00000000..125d5cdb --- /dev/null +++ b/app/models/metadata_url.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +# Un campo de URL +class MetadataUrl < MetadataString; end diff --git a/app/views/posts/attribute_ro/_file.haml b/app/views/posts/attribute_ro/_file.haml new file mode 100644 index 00000000..55c086f5 --- /dev/null +++ b/app/views/posts/attribute_ro/_file.haml @@ -0,0 +1,7 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, :path, post: post) + %td + - if metadata.value['path'].present? + %figure + = link_to url_for(metadata.static_file) + %figcaption= metadata.value['description'] diff --git a/app/views/posts/attribute_ro/_order.haml b/app/views/posts/attribute_ro/_order.haml new file mode 100644 index 00000000..31dd8f0d --- /dev/null +++ b/app/views/posts/attribute_ro/_order.haml @@ -0,0 +1,3 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td= metadata.value diff --git a/app/views/posts/attribute_ro/_url.haml b/app/views/posts/attribute_ro/_url.haml new file mode 100644 index 00000000..74c240bd --- /dev/null +++ b/app/views/posts/attribute_ro/_url.haml @@ -0,0 +1,3 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td= link_to metadata.value diff --git a/app/views/posts/attributes/_file.haml b/app/views/posts/attributes/_file.haml new file mode 100644 index 00000000..cf2d67b4 --- /dev/null +++ b/app/views/posts/attributes/_file.haml @@ -0,0 +1,22 @@ +.form-group + - if metadata.uploaded? + = hidden_field_tag "post[#{attribute}][path]", metadata.value['path'] + + .custom-file + = file_field(*field_name_for('post', attribute, :path), + **field_options(attribute, metadata), + class: "custom-file-input #{invalid(post, attribute)}", + data: { preview: "#{attribute}-preview" }) + = label_tag "post_#{attribute}_path", + post_label_t(attribute, :path, post: post), class: 'custom-file-label' + = render 'posts/attribute_feedback', + post: post, attribute: [attribute, :path], metadata: metadata + +.form-group + = label_tag "post_#{attribute}_description", + post_label_t(attribute, :description, post: post) + = text_field(*field_name_for('post', attribute, :description), + value: metadata.value['description'], + **field_options(attribute, metadata)) + = render 'posts/attribute_feedback', + post: post, attribute: [attribute, :description], metadata: metadata diff --git a/app/views/posts/attributes/_order.haml b/app/views/posts/attributes/_order.haml new file mode 100644 index 00000000..0aab9802 --- /dev/null +++ b/app/views/posts/attributes/_order.haml @@ -0,0 +1 @@ +-# nada diff --git a/app/views/posts/attributes/_url.haml b/app/views/posts/attributes/_url.haml new file mode 100644 index 00000000..eff3f1d5 --- /dev/null +++ b/app/views/posts/attributes/_url.haml @@ -0,0 +1,6 @@ +.form-group + = label_tag "post_#{attribute}", post_label_t(attribute, post: post) + = url_field 'post', attribute, value: metadata.value, + **field_options(attribute, metadata) + = render 'posts/attribute_feedback', + post: post, attribute: attribute, metadata: metadata