From 1c96e0b0fff225aeef35b364dcdf3b13f5090d22 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 14 Aug 2019 18:19:01 -0300 Subject: [PATCH] =?UTF-8?q?ver=20art=C3=ADculos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cada metadato tiene su plantilla de solo lectura para generar una tabla de metadatos dinámica :D --- Gemfile.lock | 6 +- app/controllers/application_controller.rb | 23 +--- app/controllers/posts_controller.rb | 8 +- app/helpers/application_helper.rb | 15 ++- app/models/post_relation.rb | 6 + app/models/site.rb | 7 +- app/services/post_service.rb | 24 +++- app/views/posts/attribute_ro/_array.haml | 8 ++ app/views/posts/attribute_ro/_content.haml | 3 + .../posts/attribute_ro/_document_date.haml | 3 + app/views/posts/attribute_ro/_image.haml | 6 + app/views/posts/attribute_ro/_string.haml | 3 + app/views/posts/show.haml | 110 +++++------------- config/locales/en.yml | 4 +- config/locales/es.yml | 3 + test/controllers/posts_controller_test.rb | 10 +- test/models/post_test.rb | 1 - test/models/site_test.rb | 2 - 18 files changed, 116 insertions(+), 126 deletions(-) create mode 100644 app/views/posts/attribute_ro/_array.haml create mode 100644 app/views/posts/attribute_ro/_content.haml create mode 100644 app/views/posts/attribute_ro/_document_date.haml create mode 100644 app/views/posts/attribute_ro/_image.haml create mode 100644 app/views/posts/attribute_ro/_string.haml diff --git a/Gemfile.lock b/Gemfile.lock index 660119e3..dbb8a16c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -141,7 +141,7 @@ GEM activerecord (>= 4.0.0) globalid (0.4.2) activesupport (>= 4.2.0) - haml (5.0.4) + haml (5.1.2) temple (>= 0.8.0) tilt haml-lint (0.999.999) @@ -277,7 +277,7 @@ GEM rake (>= 0.8.7) thor (>= 0.19.0, < 2.0) rainbow (3.0.0) - rake (12.3.2) + rake (12.3.3) rb-fsevent (0.10.3) rb-inotify (0.10.0) ffi (~> 1.0) @@ -306,7 +306,7 @@ GEM actionpack (>= 5.0) railties (>= 5.0) rouge (3.3.0) - rubocop (0.72.0) + rubocop (0.74.0) jaro_winkler (~> 1.5.1) parallel (~> 1.10) parser (>= 2.6) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b7e9338f..340944a6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -40,29 +40,8 @@ class ApplicationController < ActionController::Base site end - def find_post(site) - id = params[:post_id] || params[:id] - lang = find_lang(site) - posts = site.posts_for(lang) - - posts.find do |p| - p.id == id - end - end - - def find_lang(site) - params.fetch(:lang, site.default_lang) - end - - def find_template(site) - id = params[:template_id] || params[:template] || params.dig(:post, :layout) - site.templates.find do |t| - t.id == id - end - end - def set_locale - I18n.locale = current_usuarie.lang + I18n.locale = current_usuarie.lang if current_usuarie end protected diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 71dce5a1..f36a06f1 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -8,8 +8,6 @@ class PostsController < ApplicationController def index authorize Post @site = find_site - # TODO: por qué no lo está leyendo @site.posts? - @site.read @category = session[:category] = params.dig(:category) # TODO: Aplicar policy_scope @posts = @site.posts(lang: I18n.locale) @@ -26,8 +24,7 @@ class PostsController < ApplicationController def show @site = find_site - @lang = find_lang(@site) - @post = find_post(@site) + @post = @site.posts.find params[:id] authorize @post end @@ -54,8 +51,7 @@ class PostsController < ApplicationController def edit @site = find_site - @lang = find_lang(@site) - @post = find_post(@site) + @post = @site.posts.find params[:id] authorize @post end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index db667923..15ac00f8 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -27,8 +27,21 @@ module ApplicationHelper end end + # Devuelve todas las etiquetas HTML que queremos mantener + def all_html_tags + %w[h1 h2 h3 h4 h5 h6 p a ul ol li table tr td th tbody thead + tfoot em strong sup blockquote cite pre section article] + end + def sanitize_markdown(text, options = {}) - sanitize(CommonMarker.render_html(text), options) + options.merge!(attributes: %w[id href alt class]) + + document = CommonMarker + .render_doc(text, + %i[FOOTNOTES SMART], + %i[table strikethrough autolink]) + + sanitize(document.to_html, options) end def invalid?(model, field) diff --git a/app/models/post_relation.rb b/app/models/post_relation.rb index fe122d6c..dec79d39 100644 --- a/app/models/post_relation.rb +++ b/app/models/post_relation.rb @@ -25,6 +25,12 @@ class PostRelation < Array post end + def find(id) + super() do |p| + p.id == id + end + end + # Intenta guardar todos y devuelve true si pudo def save_all map(&:save).all? diff --git a/app/models/site.rb b/app/models/site.rb index ac95651c..e81ffcd5 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -108,6 +108,9 @@ class Site < ApplicationRecord # Lee el sitio y todos los artículos def read + # No hacer nada si ya se leyó antes + return unless @jekyll.layouts.empty? + @jekyll.read end @@ -115,7 +118,7 @@ class Site < ApplicationRecord # # XXX: Leer directamente sin pasar por Jekyll def data - read if @jekyll.data.empty? + read @jekyll.data end @@ -123,7 +126,7 @@ class Site < ApplicationRecord # Traer las colecciones. Todos los artículos van a estar dentro de # colecciones. def collections - read if @jekyll.collections.empty? + read @jekyll.collections end diff --git a/app/services/post_service.rb b/app/services/post_service.rb index 6d2a1fce..884ca493 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -12,11 +12,18 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do # TODO: No podemos pasar los post_params a build aun porque para # saber los parámetros tenemos que haber instanciado el post # primero. - post.update_attributes(post_params) && - site.repository.commit(file: post.path.absolute, - usuarie: usuarie, - message: I18n.t('post_service.created', - title: post.title.value)) + post.update_attributes(post_params) && commit(action: :created) + + # Devolver el post aunque no se haya salvado para poder rescatar los + # errores + post + end + + def update + # TODO: No podemos pasar los post_params a build aun porque para + # saber los parámetros tenemos que haber instanciado el post + # primero. + post.update_attributes(post_params) && commit(action: :updated) # Devolver el post aunque no se haya salvado para poder rescatar los # errores @@ -25,6 +32,13 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do private + def commit(action:) + site.repository.commit(file: post.path.absolute, + usuarie: usuarie, + message: I18n.t("post_service.#{action}", + title: post.title.value)) + end + # Solo permitir cambiar estos atributos de cada articulo def post_params params.require(:post).permit(post.params) diff --git a/app/views/posts/attribute_ro/_array.haml b/app/views/posts/attribute_ro/_array.haml new file mode 100644 index 00000000..10b08508 --- /dev/null +++ b/app/views/posts/attribute_ro/_array.haml @@ -0,0 +1,8 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td + - if metadata.value.respond_to? :each + - metadata.value.each do |v| + %span.badge.badge-primary= v + - else + %span.badge.badge-primary= metadata.value diff --git a/app/views/posts/attribute_ro/_content.haml b/app/views/posts/attribute_ro/_content.haml new file mode 100644 index 00000000..27e599d4 --- /dev/null +++ b/app/views/posts/attribute_ro/_content.haml @@ -0,0 +1,3 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td= sanitize_markdown metadata.value, tags: tags diff --git a/app/views/posts/attribute_ro/_document_date.haml b/app/views/posts/attribute_ro/_document_date.haml new file mode 100644 index 00000000..dc94def2 --- /dev/null +++ b/app/views/posts/attribute_ro/_document_date.haml @@ -0,0 +1,3 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td= l metadata.value.to_date diff --git a/app/views/posts/attribute_ro/_image.haml b/app/views/posts/attribute_ro/_image.haml new file mode 100644 index 00000000..a50d441a --- /dev/null +++ b/app/views/posts/attribute_ro/_image.haml @@ -0,0 +1,6 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, :path, post: post) + %td + %figure + = image_tag metadata.value['path'], alt: metadata.value['description'] + %figcaption= metadata.value['description'] diff --git a/app/views/posts/attribute_ro/_string.haml b/app/views/posts/attribute_ro/_string.haml new file mode 100644 index 00000000..31dd8f0d --- /dev/null +++ b/app/views/posts/attribute_ro/_string.haml @@ -0,0 +1,3 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td= metadata.value diff --git a/app/views/posts/show.haml b/app/views/posts/show.haml index fccf15e6..bbd668d4 100644 --- a/app/views/posts/show.haml +++ b/app/views/posts/show.haml @@ -1,91 +1,39 @@ -- tags = %w[h1 h2 h3 h4 h5 h6 p a ul ol li table tr td th tbody thead tfoot em strong sup blockquote cite pre] - .row .col = render 'layouts/breadcrumb', crumbs: [link_to(t('sites.index'), sites_path), @site.name, - link_to(t('posts.index'), - site_posts_path(@site)), - @post.title] + link_to(t('posts.index'), site_posts_path(@site)), + @post.title.value] .row .col - %h1{ class: @post.get_front_matter(:dir) }= @post.title + %article.content + = link_to t('posts.edit'), + edit_site_post_path(@site, @post.id), + class: 'btn btn-info btn-block' - %p - - translations = @post.translations.map do |translation| - - link_to translation.title, - site_post_path(@site, translation, lang: translation.lang) - = raw translations.join(' / ') - -.row - .col - = link_to t('posts.edit'), - edit_site_post_path(@site, @post, lang: @lang), - class: 'btn btn-info' - -.row - .col - .content{ class: @post.get_front_matter(:dir) } - = sanitize_markdown @post.content, - tags: tags - - -# - Representar los datos en una tabla: - Texto: tal cual en una celda - Array: píldoras - Array de Hashes: Tabla - Hash: Tabla - TODO DRY - %table.table.table-condensed.table-striped.table-responsive - %tbody - - @post.front_matter.each do |key, data| + %table.table.table-condensed.table-striped.table-responsive + %thead %tr - %th= t("posts.#{key}") - %td - - if data.is_a? Array - -# Un Array de Hashes - - if data.all? { |a| a.is_a? Hash } - %table - %thead - %tr - - !data.empty? && data.first.keys.each do |k| - %th= k.humanize - %tbody - - data.each do |r| - %tr - - r.each do |_, v| - %td - - if v.is_a? Array - - v.each do |s| - %span.badge.badge-secondary= s - - else - = v - - else - - data.each do |d| - %span.badge.badge-secondary= d - - elsif data.is_a? Hash - %table - %thead - %tr - - data.keys.each do |k| - %th= k.humanize - %tbody - %tr - - data.each do |_, v| - %td= v - - elsif data.respond_to? :content - -# Contenido del artículo - = sanitize_markdown data.content, tags: tags - - elsif data.respond_to? :strftime - -# Fecha - = data.strftime('%F') - - else - -# Texto - - if @post.image? key - %img.img-fluid{ src: @site.get_url_for_sutty(data) } - - elsif @post.url? key - %a{ href: @site.get_url_for_sutty(data) }= data - - else - = data + %th.text-center{ colspan: 2 }= t('.front_matter') + %tbody + -# + TODO: Cambiar por un método que nos deje interactuar + directamente con los metadatos + - @post.attributes.each do |attr| + :ruby + metadata = @post.send(attr) + + next unless metadata.front_matter? + + = render "posts/attribute_ro/#{metadata.type}", post: @post, + attribute: attr, metadata: metadata, tags: all_html_tags + + -# Mostrar todo lo que no va en el front_matter (el contenido) + - @post.attributes.each do |attr| + + - next if @post.send(attr).front_matter? + + %section{ id: attr } + = sanitize_markdown @post.send(attr).value, tags: all_html_tags diff --git a/config/locales/en.yml b/config/locales/en.yml index ad57552b..8a72e325 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -5,6 +5,7 @@ en: update: 'Updated %{name}' post_service: created: 'Created "%{title}"' + updated: 'Updated "%{title}"' metadata: array: cant_be_empty: 'This field cannot be empty' @@ -300,6 +301,8 @@ en: en: 'English' ar: 'Arabic' posts: + show: + front_matter: Post metadata submit: save: 'Save' save_incomplete: 'Save as draft' @@ -326,7 +329,6 @@ en: edit: 'Edit' draft: revision incomplete: draft - invalid: 'This field is required!' open: 'Tip: You can add new options by typing them and pressing Enter' private: '🔒 The values of this field will remain private' select: diff --git a/config/locales/es.yml b/config/locales/es.yml index f5a2b9b5..81afbb7e 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -5,6 +5,7 @@ es: update: 'Actualizado %{name}' post_service: created: 'Creado "%{title}"' + updated: 'Modificado "%{title}"' metadata: array: cant_be_empty: 'El campo no puede estar vacío' @@ -313,6 +314,8 @@ es: en: 'inglés' ar: 'árabe' posts: + show: + front_matter: Metadatos del artículo submit: save: 'Guardar' save_incomplete: 'Guardar como borrador' diff --git a/test/controllers/posts_controller_test.rb b/test/controllers/posts_controller_test.rb index 6a095a56..755d57f8 100644 --- a/test/controllers/posts_controller_test.rb +++ b/test/controllers/posts_controller_test.rb @@ -20,7 +20,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest @site.destroy end - test 'se pueden ver' do + test 'se pueden ver todos' do get site_posts_url(@site), headers: @authorization assert_match @site.name, response.body @@ -39,7 +39,6 @@ class PostsControllerTest < ActionDispatch::IntegrationTest # TODO: implementar reload? site = Site.find(@site.id) - site.read new_post = site.posts.first assert_equal 302, response.status @@ -52,4 +51,11 @@ class PostsControllerTest < ActionDispatch::IntegrationTest assert_equal I18n.t('post_service.created', title: new_post.title.value), @site.repository.rugged.head.target.message end + + test 'se pueden ver' do + get site_post_url(@site, @post.id), headers: @authorization + + assert_equal 200, response.status + assert_match @post.title.value, response.body + end end diff --git a/test/models/post_test.rb b/test/models/post_test.rb index 7b992403..d437a30a 100644 --- a/test/models/post_test.rb +++ b/test/models/post_test.rb @@ -8,7 +8,6 @@ class PostTest < ActiveSupport::TestCase # # TODO: Cambiar a skel cuando publiquemos los códigos y privacidad @site = create :site, name: 'sutty.nl' - @site.read @post = @site.posts.sample end diff --git a/test/models/site_test.rb b/test/models/site_test.rb index 5d8a511b..817613db 100644 --- a/test/models/site_test.rb +++ b/test/models/site_test.rb @@ -61,7 +61,6 @@ class SiteTest < ActiveSupport::TestCase test 'se puede leer un sitio' do site = create :site, name: 'sutty.nl' - site.read assert site.valid? assert !site.posts.empty? @@ -89,7 +88,6 @@ class SiteTest < ActiveSupport::TestCase test 'el sitio tiene artículos en distintos idiomas' do site = create :site, name: 'sutty.nl' - site.read I18n.available_locales.each do |locale| assert site.posts(lang: locale).size.positive?