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
def lang
post.lang
post.lang.value
end
def slug

View file

@ -12,8 +12,8 @@ class Post < OpenStruct
# Atributos por defecto
DEFAULT_ATTRIBUTES = %i[site document layout].freeze
# Otros atributos que no vienen en los metadatos
PRIVATE_ATTRIBUTES = %i[lang path slug attributes errors].freeze
PUBLIC_ATTRIBUTES = %i[date].freeze
PRIVATE_ATTRIBUTES = %i[path slug attributes errors].freeze
PUBLIC_ATTRIBUTES = %i[lang date].freeze
# Redefinir el inicializador de OpenStruct
#
@ -47,6 +47,7 @@ class Post < OpenStruct
required: template['required'])
end
load_lang!
load_slug!
load_date!
load_path!
@ -142,7 +143,7 @@ class Post < OpenStruct
FileUtils.rm_f path.absolute
# 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
end
end
@ -231,6 +232,7 @@ class Post < OpenStruct
save
end
alias update update_attributes
private
@ -292,6 +294,13 @@ class Post < OpenStruct
required: true)
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
def save_attributes!
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
# al array
def build(**args)
args[:document] ||= build_document
args[:lang] ||= I18n.locale
args[:document] ||= build_document(collection: args[:lang])
args[:layout] = build_layout(args[:layout])
post = Post.new(site: site, **args)
@ -31,12 +31,22 @@ class PostRelation < Array
post
end
alias find_generic find
def find(id)
super() do |p|
find_generic do |p|
p.id == id
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
def save_all
map(&:save).all?
@ -51,14 +61,14 @@ class PostRelation < Array
end
# Devuelve una colección Jekyll que hace pasar el documento
def build_collection
Jekyll::Collection.new(site.jekyll, 'posts')
def build_collection(label:)
Jekyll::Collection.new(site.jekyll, label.to_s)
end
# Un documento borrador con algunas propiedades por defecto
def build_document
doc = Jekyll::Document.new('', site: site.jekyll,
collection: build_collection)
def build_document(collection:)
col = build_collection(label: collection)
doc = Jekyll::Document.new('', site: site.jekyll, collection: col)
doc.data['date'] = Date.today.to_time
doc
end

View file

@ -8,11 +8,9 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
# @return Post
def create
# TODO: Implementar layout
self.post = site.posts.build
# 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: :created)
self.post = site.posts(lang: params[:post][:lang] || I18n.locale).build
commit(action: :created) if post.update(post_params)
# Devolver el post aunque no se haya salvado para poder rescatar los
# errores
@ -20,10 +18,7 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
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)
commit(action: :updated) if post.update(post_params)
# Devolver el post aunque no se haya salvado para poder rescatar los
# errores
@ -31,7 +26,9 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
end
def destroy
post.destroy! && commit(action: :destroyed)
post.destroy!
commit(action: :destroyed) if post.destroyed?
post
end

View file

@ -17,6 +17,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
commit_config(action: :create)
end
add_licencias
site
end
@ -46,5 +48,27 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
site.roles << Rol.new(site: site, usuarie: usuarie,
temporal: temporal, rol: rol)
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
# 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:
models:
usuarie: User
licencia: License
attributes:
usuarie:
email: 'E-mail address'

View file

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

View file

@ -5,7 +5,7 @@ designs = YAML.safe_load(File.read('db/seeds/designs.yml'))
designs.each do |d|
design = Design.find_or_create_by(gem: d['gem'])
design.update_attributes d
design.update d
end
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|
licencia = Licencia.find_or_create_by(icons: l['icons'])
licencia.update_attributes l
licencia.update l
end
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_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: |
---
title: License
permalink: license/
layout: post
---
# Peer Production License (human-readable version)
This is a human-readable summary of the [full
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
material.
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
completa)](http://endefensadelsl.org/ppl_es.html)
@ -113,7 +97,7 @@
hacerlo es enlazar a esta página.
- 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,
adapt, and redistribute the contents of your site by requiring
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
source and indicate if they made changes to it."
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,
adaptar/modificar y redistribuir los contenidos de tu sitio con la
única condición de atribuirte la autoría original. Recomendamos esta
@ -131,12 +115,6 @@
indicar si hicieron cambios."
url_es: 'https://creativecommons.org/licenses/by/4.0/deed.es'
deed_en: |
---
title: License
permalink: license/
layout: post
---
This is a human-readable summary of (and not a substitute for) the
[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
material.
deed_es: |
---
title: Licencia
permalink: licencia/
layout: post
---
Este es un resumen legible por humanes (y no un sustituto) de la
[licencia](https://creativecommons.org/licenses/by/4.0/legalcode).
@ -215,8 +187,8 @@
publicidad, privacidad, o derechos morales pueden limitar la forma en que
utilice el material.
- icons: "/images/sa.png"
name_en: "Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)"
name_es: "Atribución-CompartirIgual 4.0 Internacional (CC BY-SA 4.0)"
name_en: "Creative Commons Attribution-ShareAlike 4.0 International (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_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
@ -232,12 +204,6 @@
están permitidos, las mejoras hechas con fines de lucro deben ser
compartidas bajo la misma licencia."
deed_en: |
---
title: License
permalink: license/
layout: post
---
This is a human-readable summary of (and not a substitute for) the
[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
material.
deed_es: |
---
title: Licencia
permalink: licencia/
layout: post
---
Este es un resumen legible por humanes (y no un sustituto) de la
[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
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

View file

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

View file

@ -32,7 +32,7 @@ class SitesControllerTest < ActionDispatch::IntegrationTest
test 'se pueden crear' do
name = SecureRandom.hex
design = create :design
design = Design.all.sample
post sites_url, headers: @authorization, params: {
site: {
@ -40,7 +40,7 @@ class SitesControllerTest < ActionDispatch::IntegrationTest
title: name,
description: name * 2,
design_id: design.id,
licencia_id: create(:licencia).id,
licencia_id: Licencia.first.id,
deploys_attributes: {
'0' => {
type: 'DeployLocal'
@ -62,8 +62,15 @@ class SitesControllerTest < ActionDispatch::IntegrationTest
assert_equal design.gem, site.config.theme
assert_equal name, site.config.title
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
end

View file

@ -42,6 +42,8 @@ class PostTest < ActiveSupport::TestCase
if metadata.empty?
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
assert_equal metadata.value, @post.document.send(attr), attr
else

View file

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

View file

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