crear licencias y gestionar correctamente las colecciones por idioma

habia un monton de inconsistencias que hacian que los posts se guardaran
en cualquier lado, que empezaron a saltar apenas introdujimos la gestión
de licencias
This commit is contained in:
f 2019-09-17 18:27:51 -03:00
parent 8f22215621
commit cad881db1c
No known key found for this signature in database
GPG key ID: 2AE5A13E321F953D
18 changed files with 110 additions and 76 deletions

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
# Un campo de idioma
class MetadataLang < MetadataTemplate
def default_value
I18n.locale
end
def value
self[:value] || document.collection.label.to_sym
end
def values
I18n.available_locales
end
end

View file

@ -28,7 +28,7 @@ class MetadataPath < MetadataTemplate
end end
def lang def lang
post.lang post.lang.value
end end
def slug def slug

View file

@ -12,8 +12,8 @@ class Post < OpenStruct
# Atributos por defecto # Atributos por defecto
DEFAULT_ATTRIBUTES = %i[site document layout].freeze DEFAULT_ATTRIBUTES = %i[site document layout].freeze
# Otros atributos que no vienen en los metadatos # Otros atributos que no vienen en los metadatos
PRIVATE_ATTRIBUTES = %i[lang path slug attributes errors].freeze PRIVATE_ATTRIBUTES = %i[path slug attributes errors].freeze
PUBLIC_ATTRIBUTES = %i[date].freeze PUBLIC_ATTRIBUTES = %i[lang date].freeze
# Redefinir el inicializador de OpenStruct # Redefinir el inicializador de OpenStruct
# #
@ -47,6 +47,7 @@ class Post < OpenStruct
required: template['required']) required: template['required'])
end end
load_lang!
load_slug! load_slug!
load_date! load_date!
load_path! load_path!
@ -142,7 +143,7 @@ class Post < OpenStruct
FileUtils.rm_f path.absolute FileUtils.rm_f path.absolute
# TODO: Devolver self en lugar de todo el array # TODO: Devolver self en lugar de todo el array
site.posts(lang: lang).reject! do |post| site.posts(lang: lang.value).reject! do |post|
post.path.absolute == path.absolute post.path.absolute == path.absolute
end end
end end
@ -231,6 +232,7 @@ class Post < OpenStruct
save save
end end
alias update update_attributes
private private
@ -292,6 +294,13 @@ class Post < OpenStruct
required: true) required: true)
end end
def load_lang!
self.lang = MetadataLang.new(document: document, site: site,
layout: layout, name: :lang,
type: :lang, post: self,
required: true)
end
# Ejecuta la acción de guardado en cada atributo # Ejecuta la acción de guardado en cada atributo
def save_attributes! def save_attributes!
attributes.map do |attr| attributes.map do |attr|

View file

@ -15,8 +15,8 @@ class PostRelation < Array
# Genera un artículo nuevo con los parámetros que le pasemos y lo suma # Genera un artículo nuevo con los parámetros que le pasemos y lo suma
# al array # al array
def build(**args) def build(**args)
args[:document] ||= build_document
args[:lang] ||= I18n.locale args[:lang] ||= I18n.locale
args[:document] ||= build_document(collection: args[:lang])
args[:layout] = build_layout(args[:layout]) args[:layout] = build_layout(args[:layout])
post = Post.new(site: site, **args) post = Post.new(site: site, **args)
@ -31,12 +31,22 @@ class PostRelation < Array
post post
end end
alias find_generic find
def find(id) def find(id)
super() do |p| find_generic do |p|
p.id == id p.id == id
end end
end end
# Encuentra el primer post por el valor de un atributo
# XXX: Acepta cualquier atributo
def find_by(**args)
find_generic do |p|
p.public_send(args.first.first).try(:value) == args.first.last
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?
@ -51,14 +61,14 @@ class PostRelation < Array
end end
# Devuelve una colección Jekyll que hace pasar el documento # Devuelve una colección Jekyll que hace pasar el documento
def build_collection def build_collection(label:)
Jekyll::Collection.new(site.jekyll, 'posts') Jekyll::Collection.new(site.jekyll, label.to_s)
end end
# Un documento borrador con algunas propiedades por defecto # Un documento borrador con algunas propiedades por defecto
def build_document def build_document(collection:)
doc = Jekyll::Document.new('', site: site.jekyll, col = build_collection(label: collection)
collection: build_collection) doc = Jekyll::Document.new('', site: site.jekyll, collection: col)
doc.data['date'] = Date.today.to_time doc.data['date'] = Date.today.to_time
doc doc
end end

View file

@ -8,11 +8,9 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
# @return Post # @return Post
def create def create
# TODO: Implementar layout # TODO: Implementar layout
self.post = site.posts.build self.post = site.posts(lang: params[:post][:lang] || I18n.locale).build
# TODO: No podemos pasar los post_params a build aun porque para
# saber los parámetros tenemos que haber instanciado el post commit(action: :created) if post.update(post_params)
# primero.
post.update_attributes(post_params) && commit(action: :created)
# 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
@ -20,10 +18,7 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
end end
def update def update
# TODO: No podemos pasar los post_params a build aun porque para commit(action: :updated) if post.update(post_params)
# 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
@ -31,7 +26,9 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
end end
def destroy def destroy
post.destroy! && commit(action: :destroyed) post.destroy!
commit(action: :destroyed) if post.destroyed?
post post
end end

View file

@ -17,6 +17,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
commit_config(action: :create) commit_config(action: :create)
end end
add_licencias
site site
end end
@ -46,5 +48,27 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
site.roles << Rol.new(site: site, usuarie: usuarie, site.roles << Rol.new(site: site, usuarie: usuarie,
temporal: temporal, rol: rol) temporal: temporal, rol: rol)
end end
# Crea la licencia del sitio para cada locale disponible
# rubocop:disable Metrics/MethodLength
def add_licencias
I18n.available_locales.each do |locale|
Mobility.with_locale(locale) do
params = ActionController::Parameters.new(
post: {
lang: locale,
title: site.licencia.name,
author: %w[Sutty],
permalink: "#{I18n.t('activerecord.models.licencia').downcase}/",
content: site.licencia.deed
}
)
PostService.new(site: site, usuarie: usuarie, params: params)
.create
end
end
end
# rubocop:enable Metrics/MethodLength
end end
# rubocop:enable Metrics/BlockLength # rubocop:enable Metrics/BlockLength

View file

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

View file

@ -0,0 +1,2 @@
-# TODO: Implementar i18n
= hidden_field 'post[lang]', I18n.locale

View file

@ -59,6 +59,7 @@ en:
activerecord: activerecord:
models: models:
usuarie: User usuarie: User
licencia: License
attributes: attributes:
usuarie: usuarie:
email: 'E-mail address' email: 'E-mail address'

View file

@ -61,6 +61,7 @@ es:
activerecord: activerecord:
models: models:
usuarie: Usuarie usuarie: Usuarie
licencia: Licencia
attributes: attributes:
usuarie: usuarie:
email: 'Correo electrónico' email: 'Correo electrónico'

View file

@ -5,7 +5,7 @@ designs = YAML.safe_load(File.read('db/seeds/designs.yml'))
designs.each do |d| designs.each do |d|
design = Design.find_or_create_by(gem: d['gem']) design = Design.find_or_create_by(gem: d['gem'])
design.update_attributes d design.update d
end end
licencias = YAML.safe_load(File.read('db/seeds/licencias.yml')) licencias = YAML.safe_load(File.read('db/seeds/licencias.yml'))
@ -13,7 +13,7 @@ licencias = YAML.safe_load(File.read('db/seeds/licencias.yml'))
licencias.each do |l| licencias.each do |l|
licencia = Licencia.find_or_create_by(icons: l['icons']) licencia = Licencia.find_or_create_by(icons: l['icons'])
licencia.update_attributes l licencia.update l
end end
YAML.safe_load(File.read('db/seeds/sites.yml')).each do |site| YAML.safe_load(File.read('db/seeds/sites.yml')).each do |site|

View file

@ -7,14 +7,6 @@
description_en: 'The Peer Production License is a license that allows use for any purpose under the same terms, except for commercial purposes, which are only allowed for collectives, cooperatives and other worker-owned "enterprises". We recommend this license if you are inclined towards non-profit terms, since it allows the development of more ethical economies while fending off capitalistic for-profit uses. If you want to know more about it, we invite you to read [The Telekommunist Manifesto](http://networkcultures.org/blog/publication/no-03-the-telekommunist-manifesto-dmytri-kleiner/)' description_en: 'The Peer Production License is a license that allows use for any purpose under the same terms, except for commercial purposes, which are only allowed for collectives, cooperatives and other worker-owned "enterprises". We recommend this license if you are inclined towards non-profit terms, since it allows the development of more ethical economies while fending off capitalistic for-profit uses. If you want to know more about it, we invite you to read [The Telekommunist Manifesto](http://networkcultures.org/blog/publication/no-03-the-telekommunist-manifesto-dmytri-kleiner/)'
description_es: 'La licencia de Producción de Pares permite el uso con cualquier propósito bajo la misma licencia, a excepción de los usos comerciales que solo están permitidos a colectivos, cooperativas y otras "empresas" en manos de sus trabajadorxs. Recomendamos esta licencia si te estabas inclinando hacia términos sin fines de lucro, ya que permite el desarrollo de economías más éticas al mismo tiempo que impide la explotación capitalista. Si te interesa saber más, te invitamos a leer [El manifiesto telecomunista](https://endefensadelsl.org/manifiesto_telecomunista.html).' description_es: 'La licencia de Producción de Pares permite el uso con cualquier propósito bajo la misma licencia, a excepción de los usos comerciales que solo están permitidos a colectivos, cooperativas y otras "empresas" en manos de sus trabajadorxs. Recomendamos esta licencia si te estabas inclinando hacia términos sin fines de lucro, ya que permite el desarrollo de economías más éticas al mismo tiempo que impide la explotación capitalista. Si te interesa saber más, te invitamos a leer [El manifiesto telecomunista](https://endefensadelsl.org/manifiesto_telecomunista.html).'
deed_en: | deed_en: |
---
title: License
permalink: license/
layout: post
---
# Peer Production License (human-readable version)
This is a human-readable summary of the [full This is a human-readable summary of the [full
license](https://wiki.p2pfoundation.net/Peer_Production_License). license](https://wiki.p2pfoundation.net/Peer_Production_License).
@ -54,14 +46,6 @@
such as publicity, privacy, or moral rights may limit how you use the such as publicity, privacy, or moral rights may limit how you use the
material. material.
deed_es: | deed_es: |
---
title: Licencia
permalink: licencia/
layout: post
---
# Licencia de producción de pares (versión legible por humanas)
Esto es un resumen legible por humanas del [texto legal (la licencia Esto es un resumen legible por humanas del [texto legal (la licencia
completa)](http://endefensadelsl.org/ppl_es.html) completa)](http://endefensadelsl.org/ppl_es.html)
@ -113,7 +97,7 @@
hacerlo es enlazar a esta página. hacerlo es enlazar a esta página.
- icons: "/images/by.png" - icons: "/images/by.png"
name_en: 'Attribution 4.0 International (CC BY 4.0)' name_en: 'Creative Commons Attribution 4.0 International (CC BY 4.0)'
description_en: "This license gives everyone the freedom to use, description_en: "This license gives everyone the freedom to use,
adapt, and redistribute the contents of your site by requiring adapt, and redistribute the contents of your site by requiring
attribution only. We recommend this license if you're publishing attribution only. We recommend this license if you're publishing
@ -121,7 +105,7 @@
you want to be attributed. Users of the site will have to mention the you want to be attributed. Users of the site will have to mention the
source and indicate if they made changes to it." source and indicate if they made changes to it."
url_en: 'https://creativecommons.org/licenses/by/4.0/' url_en: 'https://creativecommons.org/licenses/by/4.0/'
name_es: 'Atribución 4.0 Internacional (CC BY 4.0)' name_es: 'Creative Commons Atribución 4.0 Internacional (CC BY 4.0)'
description_es: "Esta licencia permite a todes la libertad de usar, description_es: "Esta licencia permite a todes la libertad de usar,
adaptar/modificar y redistribuir los contenidos de tu sitio con la adaptar/modificar y redistribuir los contenidos de tu sitio con la
única condición de atribuirte la autoría original. Recomendamos esta única condición de atribuirte la autoría original. Recomendamos esta
@ -131,12 +115,6 @@
indicar si hicieron cambios." indicar si hicieron cambios."
url_es: 'https://creativecommons.org/licenses/by/4.0/deed.es' url_es: 'https://creativecommons.org/licenses/by/4.0/deed.es'
deed_en: | deed_en: |
---
title: License
permalink: license/
layout: post
---
This is a human-readable summary of (and not a substitute for) the This is a human-readable summary of (and not a substitute for) the
[license](https://creativecommons.org/licenses/by/4.0/legalcode). [license](https://creativecommons.org/licenses/by/4.0/legalcode).
@ -173,12 +151,6 @@
such as publicity, privacy, or moral rights may limit how you use the such as publicity, privacy, or moral rights may limit how you use the
material. material.
deed_es: | deed_es: |
---
title: Licencia
permalink: licencia/
layout: post
---
Este es un resumen legible por humanes (y no un sustituto) de la Este es un resumen legible por humanes (y no un sustituto) de la
[licencia](https://creativecommons.org/licenses/by/4.0/legalcode). [licencia](https://creativecommons.org/licenses/by/4.0/legalcode).
@ -215,8 +187,8 @@
publicidad, privacidad, o derechos morales pueden limitar la forma en que publicidad, privacidad, o derechos morales pueden limitar la forma en que
utilice el material. utilice el material.
- icons: "/images/sa.png" - icons: "/images/sa.png"
name_en: "Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)" name_en: "Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)"
name_es: "Atribución-CompartirIgual 4.0 Internacional (CC BY-SA 4.0)" name_es: "Creative Commons Atribución-CompartirIgual 4.0 Internacional (CC BY-SA 4.0)"
url_en: 'https://creativecommons.org/licenses/by-sa/4.0/' url_en: 'https://creativecommons.org/licenses/by-sa/4.0/'
url_es: 'https://creativecommons.org/licenses/by-sa/4.0/deed.es' url_es: 'https://creativecommons.org/licenses/by-sa/4.0/deed.es'
description_en: "This license is the same as the CC-BY 4.0 but it adds description_en: "This license is the same as the CC-BY 4.0 but it adds
@ -232,12 +204,6 @@
están permitidos, las mejoras hechas con fines de lucro deben ser están permitidos, las mejoras hechas con fines de lucro deben ser
compartidas bajo la misma licencia." compartidas bajo la misma licencia."
deed_en: | deed_en: |
---
title: License
permalink: license/
layout: post
---
This is a human-readable summary of (and not a substitute for) the This is a human-readable summary of (and not a substitute for) the
[license](https://creativecommons.org/licenses/by-sa/4.0/legalcode). [license](https://creativecommons.org/licenses/by-sa/4.0/legalcode).
@ -279,12 +245,6 @@
such as publicity, privacy, or moral rights may limit how you use the such as publicity, privacy, or moral rights may limit how you use the
material. material.
deed_es: | deed_es: |
---
title: Licencia
permalink: licencia/
layout: post
---
Este es un resumen legible por humanes (y no un sustituto) de la Este es un resumen legible por humanes (y no un sustituto) de la
[licencia](https://creativecommons.org/licenses/by/4.0/legalcode). [licencia](https://creativecommons.org/licenses/by/4.0/legalcode).

View file

@ -33,7 +33,7 @@ module Api
test 'se puede obtener un listado de todos' do test 'se puede obtener un listado de todos' do
get v1_sites_url, headers: @authorization, as: :json get v1_sites_url, headers: @authorization, as: :json
assert_equal [@site.name], JSON.parse(response.body) assert_equal Site.all.pluck(:name), JSON.parse(response.body)
end end
end end
end end

View file

@ -39,7 +39,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
# TODO: implementar reload? # TODO: implementar reload?
site = Site.find(@site.id) site = Site.find(@site.id)
new_post = site.posts.first new_post = site.posts.find_by(title: title)
assert_equal 302, response.status assert_equal 302, response.status

View file

@ -32,7 +32,7 @@ class SitesControllerTest < ActionDispatch::IntegrationTest
test 'se pueden crear' do test 'se pueden crear' do
name = SecureRandom.hex name = SecureRandom.hex
design = create :design design = Design.all.sample
post sites_url, headers: @authorization, params: { post sites_url, headers: @authorization, params: {
site: { site: {
@ -40,7 +40,7 @@ class SitesControllerTest < ActionDispatch::IntegrationTest
title: name, title: name,
description: name * 2, description: name * 2,
design_id: design.id, design_id: design.id,
licencia_id: create(:licencia).id, licencia_id: Licencia.first.id,
deploys_attributes: { deploys_attributes: {
'0' => { '0' => {
type: 'DeployLocal' type: 'DeployLocal'
@ -62,8 +62,15 @@ class SitesControllerTest < ActionDispatch::IntegrationTest
assert_equal design.gem, site.config.theme assert_equal design.gem, site.config.theme
assert_equal name, site.config.title assert_equal name, site.config.title
assert_equal name * 2, site.config.description assert_equal name * 2, site.config.description
assert_equal I18n.t('site_service.create', name: name),
site.repository.rugged.head.target.message # TODO: Esto requiere que podamos buscar hacia atrás en la historia
# del repositorio
# assert_equal I18n.t('site_service.create', name: name),
# site.repository.rugged.head.target.message
I18n.available_locales.each do |locale|
assert_equal 3, site.posts(lang: locale).size
end
site.destroy site.destroy
end end

View file

@ -42,6 +42,8 @@ class PostTest < ActiveSupport::TestCase
if metadata.empty? if metadata.empty?
assert_not @post.document.data[attr.to_s].present? assert_not @post.document.data[attr.to_s].present?
elsif metadata.type == :lang
assert @post.path.relative.starts_with?("_#{metadata.value}/")
elsif @post.document.respond_to? attr elsif @post.document.respond_to? attr
assert_equal metadata.value, @post.document.send(attr), attr assert_equal metadata.value, @post.document.send(attr), attr
else else

View file

@ -60,7 +60,7 @@ class SiteTest < ActiveSupport::TestCase
end end
test 'se puede leer un sitio' do test 'se puede leer un sitio' do
site = create :site, name: 'sutty.nl' site = create :site
assert site.valid? assert site.valid?
assert !site.posts.empty? assert !site.posts.empty?
@ -87,10 +87,10 @@ class SiteTest < ActiveSupport::TestCase
end end
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
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?
end end
end end
end end

View file

@ -5,6 +5,8 @@ require 'rails/test_help'
require 'open3' require 'open3'
require 'sucker_punch/testing/inline' require 'sucker_punch/testing/inline'
Rails.application.load_seed
# rubocop:disable Style/ClassAndModuleChildren # rubocop:disable Style/ClassAndModuleChildren
class ActiveSupport::TestCase class ActiveSupport::TestCase
include FactoryBot::Syntax::Methods include FactoryBot::Syntax::Methods