ver artículos

cada metadato tiene su plantilla de solo lectura para generar una tabla
de metadatos dinámica :D
This commit is contained in:
f 2019-08-14 18:19:01 -03:00
parent 9469cb41e6
commit 1c96e0b0ff
No known key found for this signature in database
GPG key ID: 2AE5A13E321F953D
18 changed files with 116 additions and 126 deletions

View file

@ -141,7 +141,7 @@ GEM
activerecord (>= 4.0.0) activerecord (>= 4.0.0)
globalid (0.4.2) globalid (0.4.2)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
haml (5.0.4) haml (5.1.2)
temple (>= 0.8.0) temple (>= 0.8.0)
tilt tilt
haml-lint (0.999.999) haml-lint (0.999.999)
@ -277,7 +277,7 @@ GEM
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0) thor (>= 0.19.0, < 2.0)
rainbow (3.0.0) rainbow (3.0.0)
rake (12.3.2) rake (12.3.3)
rb-fsevent (0.10.3) rb-fsevent (0.10.3)
rb-inotify (0.10.0) rb-inotify (0.10.0)
ffi (~> 1.0) ffi (~> 1.0)
@ -306,7 +306,7 @@ GEM
actionpack (>= 5.0) actionpack (>= 5.0)
railties (>= 5.0) railties (>= 5.0)
rouge (3.3.0) rouge (3.3.0)
rubocop (0.72.0) rubocop (0.74.0)
jaro_winkler (~> 1.5.1) jaro_winkler (~> 1.5.1)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.6) parser (>= 2.6)

View file

@ -40,29 +40,8 @@ class ApplicationController < ActionController::Base
site site
end 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 def set_locale
I18n.locale = current_usuarie.lang I18n.locale = current_usuarie.lang if current_usuarie
end end
protected protected

View file

@ -8,8 +8,6 @@ class PostsController < ApplicationController
def index def index
authorize Post authorize Post
@site = find_site @site = find_site
# TODO: por qué no lo está leyendo @site.posts?
@site.read
@category = session[:category] = params.dig(:category) @category = session[:category] = params.dig(:category)
# TODO: Aplicar policy_scope # TODO: Aplicar policy_scope
@posts = @site.posts(lang: I18n.locale) @posts = @site.posts(lang: I18n.locale)
@ -26,8 +24,7 @@ class PostsController < ApplicationController
def show def show
@site = find_site @site = find_site
@lang = find_lang(@site) @post = @site.posts.find params[:id]
@post = find_post(@site)
authorize @post authorize @post
end end
@ -54,8 +51,7 @@ class PostsController < ApplicationController
def edit def edit
@site = find_site @site = find_site
@lang = find_lang(@site) @post = @site.posts.find params[:id]
@post = find_post(@site)
authorize @post authorize @post
end end

View file

@ -27,8 +27,21 @@ module ApplicationHelper
end end
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 = {}) 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 end
def invalid?(model, field) def invalid?(model, field)

View file

@ -25,6 +25,12 @@ class PostRelation < Array
post post
end end
def find(id)
super() do |p|
p.id == id
end
end
# Intenta guardar todos y devuelve true si pudo # Intenta guardar todos y devuelve true si pudo
def save_all def save_all
map(&:save).all? map(&:save).all?

View file

@ -108,6 +108,9 @@ class Site < ApplicationRecord
# Lee el sitio y todos los artículos # Lee el sitio y todos los artículos
def read def read
# No hacer nada si ya se leyó antes
return unless @jekyll.layouts.empty?
@jekyll.read @jekyll.read
end end
@ -115,7 +118,7 @@ class Site < ApplicationRecord
# #
# XXX: Leer directamente sin pasar por Jekyll # XXX: Leer directamente sin pasar por Jekyll
def data def data
read if @jekyll.data.empty? read
@jekyll.data @jekyll.data
end end
@ -123,7 +126,7 @@ class Site < ApplicationRecord
# Traer las colecciones. Todos los artículos van a estar dentro de # Traer las colecciones. Todos los artículos van a estar dentro de
# colecciones. # colecciones.
def collections def collections
read if @jekyll.collections.empty? read
@jekyll.collections @jekyll.collections
end end

View file

@ -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 # TODO: No podemos pasar los post_params a build aun porque para
# saber los parámetros tenemos que haber instanciado el post # saber los parámetros tenemos que haber instanciado el post
# primero. # primero.
post.update_attributes(post_params) && post.update_attributes(post_params) && commit(action: :created)
site.repository.commit(file: post.path.absolute,
usuarie: usuarie, # Devolver el post aunque no se haya salvado para poder rescatar los
message: I18n.t('post_service.created', # errores
title: post.title.value)) 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 # Devolver el post aunque no se haya salvado para poder rescatar los
# errores # errores
@ -25,6 +32,13 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
private 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 # Solo permitir cambiar estos atributos de cada articulo
def post_params def post_params
params.require(:post).permit(post.params) params.require(:post).permit(post.params)

View file

@ -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

View file

@ -0,0 +1,3 @@
%tr{ id: attribute }
%th= post_label_t(attribute, post: post)
%td= sanitize_markdown metadata.value, tags: tags

View file

@ -0,0 +1,3 @@
%tr{ id: attribute }
%th= post_label_t(attribute, post: post)
%td= l metadata.value.to_date

View file

@ -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']

View file

@ -0,0 +1,3 @@
%tr{ id: attribute }
%th= post_label_t(attribute, post: post)
%td= metadata.value

View file

@ -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 .row
.col .col
= render 'layouts/breadcrumb', = render 'layouts/breadcrumb',
crumbs: [link_to(t('sites.index'), sites_path), crumbs: [link_to(t('sites.index'), sites_path),
@site.name, @site.name,
link_to(t('posts.index'), link_to(t('posts.index'), site_posts_path(@site)),
site_posts_path(@site)), @post.title.value]
@post.title]
.row .row
.col .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 %table.table.table-condensed.table-striped.table-responsive
- translations = @post.translations.map do |translation| %thead
- 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|
%tr %tr
%th= t("posts.#{key}") %th.text-center{ colspan: 2 }= t('.front_matter')
%td %tbody
- if data.is_a? Array -#
-# Un Array de Hashes TODO: Cambiar por un método que nos deje interactuar
- if data.all? { |a| a.is_a? Hash } directamente con los metadatos
%table - @post.attributes.each do |attr|
%thead :ruby
%tr metadata = @post.send(attr)
- !data.empty? && data.first.keys.each do |k|
%th= k.humanize next unless metadata.front_matter?
%tbody
- data.each do |r| = render "posts/attribute_ro/#{metadata.type}", post: @post,
%tr attribute: attr, metadata: metadata, tags: all_html_tags
- r.each do |_, v|
%td -# Mostrar todo lo que no va en el front_matter (el contenido)
- if v.is_a? Array - @post.attributes.each do |attr|
- v.each do |s|
%span.badge.badge-secondary= s - next if @post.send(attr).front_matter?
- else
= v %section{ id: attr }
- else = sanitize_markdown @post.send(attr).value, tags: all_html_tags
- 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

View file

@ -5,6 +5,7 @@ en:
update: 'Updated %{name}' update: 'Updated %{name}'
post_service: post_service:
created: 'Created "%{title}"' created: 'Created "%{title}"'
updated: 'Updated "%{title}"'
metadata: metadata:
array: array:
cant_be_empty: 'This field cannot be empty' cant_be_empty: 'This field cannot be empty'
@ -300,6 +301,8 @@ en:
en: 'English' en: 'English'
ar: 'Arabic' ar: 'Arabic'
posts: posts:
show:
front_matter: Post metadata
submit: submit:
save: 'Save' save: 'Save'
save_incomplete: 'Save as draft' save_incomplete: 'Save as draft'
@ -326,7 +329,6 @@ en:
edit: 'Edit' edit: 'Edit'
draft: revision draft: revision
incomplete: draft incomplete: draft
invalid: 'This field is required!'
open: 'Tip: You can add new options by typing them and pressing Enter' open: 'Tip: You can add new options by typing them and pressing Enter'
private: '&#128274; The values of this field will remain private' private: '&#128274; The values of this field will remain private'
select: select:

View file

@ -5,6 +5,7 @@ es:
update: 'Actualizado %{name}' update: 'Actualizado %{name}'
post_service: post_service:
created: 'Creado "%{title}"' created: 'Creado "%{title}"'
updated: 'Modificado "%{title}"'
metadata: metadata:
array: array:
cant_be_empty: 'El campo no puede estar vacío' cant_be_empty: 'El campo no puede estar vacío'
@ -313,6 +314,8 @@ es:
en: 'inglés' en: 'inglés'
ar: 'árabe' ar: 'árabe'
posts: posts:
show:
front_matter: Metadatos del artículo
submit: submit:
save: 'Guardar' save: 'Guardar'
save_incomplete: 'Guardar como borrador' save_incomplete: 'Guardar como borrador'

View file

@ -20,7 +20,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
@site.destroy @site.destroy
end end
test 'se pueden ver' do test 'se pueden ver todos' do
get site_posts_url(@site), headers: @authorization get site_posts_url(@site), headers: @authorization
assert_match @site.name, response.body assert_match @site.name, response.body
@ -39,7 +39,6 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
# TODO: implementar reload? # TODO: implementar reload?
site = Site.find(@site.id) site = Site.find(@site.id)
site.read
new_post = site.posts.first new_post = site.posts.first
assert_equal 302, response.status 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), assert_equal I18n.t('post_service.created', title: new_post.title.value),
@site.repository.rugged.head.target.message @site.repository.rugged.head.target.message
end 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 end

View file

@ -8,7 +8,6 @@ class PostTest < ActiveSupport::TestCase
# #
# TODO: Cambiar a skel cuando publiquemos los códigos y privacidad # TODO: Cambiar a skel cuando publiquemos los códigos y privacidad
@site = create :site, name: 'sutty.nl' @site = create :site, name: 'sutty.nl'
@site.read
@post = @site.posts.sample @post = @site.posts.sample
end end

View file

@ -61,7 +61,6 @@ class SiteTest < ActiveSupport::TestCase
test 'se puede leer un sitio' do test 'se puede leer un sitio' do
site = create :site, name: 'sutty.nl' site = create :site, name: 'sutty.nl'
site.read
assert site.valid? assert site.valid?
assert !site.posts.empty? assert !site.posts.empty?
@ -89,7 +88,6 @@ class SiteTest < ActiveSupport::TestCase
test 'el sitio tiene artículos en distintos idiomas' do test 'el sitio tiene artículos en distintos idiomas' do
site = create :site, name: 'sutty.nl' site = create :site, name: 'sutty.nl'
site.read
I18n.available_locales.each do |locale| I18n.available_locales.each do |locale|
assert site.posts(lang: locale).size.positive? assert site.posts(lang: locale).size.positive?