reordenar articulos
This commit is contained in:
parent
8a5bfbd5f2
commit
14aa09b31e
10 changed files with 87 additions and 174 deletions
|
@ -90,4 +90,17 @@ class PostsController < ApplicationController
|
|||
service.destroy
|
||||
redirect_to site_posts_path(@site)
|
||||
end
|
||||
|
||||
# Reordenar los artículos
|
||||
def reorder
|
||||
@site = find_site
|
||||
authorize @site
|
||||
|
||||
service = PostService.new(site: @site,
|
||||
usuarie: current_usuarie,
|
||||
params: params)
|
||||
|
||||
service.reorder
|
||||
redirect_to site_posts_path(@site)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -221,47 +221,6 @@ class Site < ApplicationRecord
|
|||
status == 'enqueued'
|
||||
end
|
||||
|
||||
# Verifica si los posts están ordenados
|
||||
def ordered?(lang: nil)
|
||||
posts(lang: lang).map(&:order).all?
|
||||
end
|
||||
|
||||
# Reordena la colección usando la posición informada
|
||||
#
|
||||
# new_order es un hash cuya key es la posición actual del post y el
|
||||
# valor la posición nueva
|
||||
#
|
||||
# TODO: Refactorizar y testear
|
||||
def reorder_collection(collection, new_order)
|
||||
# Tenemos que pasar el mismo orden
|
||||
return if new_order.values.map(&:to_i).sort != new_order.keys.map(&:to_i).sort
|
||||
|
||||
# Solo traer los posts que vamos a modificar
|
||||
posts_to_order = posts_for(collection).values_at(*new_order.keys.map(&:to_i))
|
||||
|
||||
# Recorre todos los posts y asigna el nuevo orden
|
||||
posts_to_order.each_with_index do |p, i|
|
||||
# Usar el index si el artículo no estaba ordenado, para tener una
|
||||
# ruta de adopción
|
||||
oo = (p.order || i).to_s
|
||||
no = new_order[oo].to_i
|
||||
# No modificar nada si no hace falta
|
||||
next if p.order == no
|
||||
|
||||
p.update_attributes order: no
|
||||
p.save
|
||||
end
|
||||
|
||||
posts_to_order.map(&:ordered?).all?
|
||||
end
|
||||
|
||||
# Reordena la colección usando la posición actual de los artículos
|
||||
def reorder_collection!(collection = 'posts')
|
||||
order = Hash[posts_for(collection).count.times.map { |i| [i.to_s, i.to_s] }]
|
||||
reorder_collection collection, order
|
||||
end
|
||||
alias reorder_posts! reorder_collection!
|
||||
|
||||
# Obtener una ruta disponible para Sutty
|
||||
#
|
||||
# TODO: Refactorizar y testear
|
||||
|
|
|
@ -85,9 +85,13 @@ class Site
|
|||
!commits.empty?
|
||||
end
|
||||
|
||||
# Guarda los cambios en git, de a un archivo por vez
|
||||
# Guarda los cambios en git
|
||||
def commit(file:, usuarie:, message:, remove: false)
|
||||
remove ? rm(file) : add(file)
|
||||
file = [file] unless file.respond_to? :each
|
||||
|
||||
file.each do |f|
|
||||
remove ? rm(f) : add(f)
|
||||
end
|
||||
|
||||
# Escribir los cambios para que el repositorio se vea tal cual
|
||||
rugged.index.write
|
||||
|
|
|
@ -67,6 +67,11 @@ class SitePolicy
|
|||
pull?
|
||||
end
|
||||
|
||||
# Solo les usuaries pueden reordenar artículos
|
||||
def reorder?
|
||||
site.usuarie? usuarie
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_role
|
||||
|
|
|
@ -39,19 +39,50 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
|
|||
post
|
||||
end
|
||||
|
||||
# Reordena todos los posts que soporten orden de acuerdo a un array
|
||||
# con las nuevas posiciones. La posición actual la da la posición en
|
||||
# el array.
|
||||
#
|
||||
# [ 1, 0, 2 ] => mover el elemento 2 a la posición 1, mantener 3
|
||||
def reorder
|
||||
posts = site.posts(lang: lang)
|
||||
reorder = params.require(:post).permit(reorder: [])
|
||||
.try(:[], :reorder)
|
||||
.try(:map, &:to_i) || []
|
||||
|
||||
# Tenemos que pasar un array con la misma cantidad de elementos
|
||||
return false if reorder.size != posts.size
|
||||
|
||||
files = reorder.map.with_index do |new, cur|
|
||||
post = posts[cur]
|
||||
next unless post.attributes.include? :order
|
||||
|
||||
post.usuaries << usuarie
|
||||
post.order.value = new
|
||||
post.path.absolute
|
||||
end.compact
|
||||
|
||||
# TODO: Implementar transacciones!
|
||||
posts.save_all && commit(action: :reorder, file: files)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def commit(action:)
|
||||
site.repository.commit(file: post.path.absolute,
|
||||
def commit(action:, file: nil)
|
||||
site.repository.commit(file: file || post.path.absolute,
|
||||
usuarie: usuarie,
|
||||
remove: action == :destroyed,
|
||||
message: I18n.t("post_service.#{action}",
|
||||
title: post.title.value))
|
||||
title: post.try(:title).try(:value)))
|
||||
end
|
||||
|
||||
# Solo permitir cambiar estos atributos de cada articulo
|
||||
def post_params
|
||||
params.require(:post).permit(post.params)
|
||||
end
|
||||
|
||||
def lang
|
||||
params[:post][:lang] || I18n.locale
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/BlockLength
|
||||
|
|
|
@ -19,6 +19,7 @@ en:
|
|||
created: 'Created "%{title}"'
|
||||
updated: 'Updated "%{title}"'
|
||||
destroyed: 'Removed "%{title}"'
|
||||
reorder: 'Reorder'
|
||||
metadata:
|
||||
array:
|
||||
cant_be_empty: 'This field cannot be empty'
|
||||
|
|
|
@ -19,6 +19,7 @@ es:
|
|||
created: 'Creado "%{title}"'
|
||||
updated: 'Modificado "%{title}"'
|
||||
destroyed: 'Eliminado "%{title}"'
|
||||
reorder: 'Reordenados'
|
||||
metadata:
|
||||
array:
|
||||
cant_be_empty: 'El campo no puede estar vacío'
|
||||
|
|
|
@ -45,6 +45,7 @@ Rails.application.routes.draw do
|
|||
post 'collaborate', to: 'collaborations#accept_collaboration'
|
||||
|
||||
# Gestionar artículos
|
||||
post :'posts/reorder', to: 'posts#reorder'
|
||||
resources :posts
|
||||
|
||||
# Gestionar traducciones
|
||||
|
|
137
doc/reordenar.md
137
doc/reordenar.md
|
@ -1,134 +1,15 @@
|
|||
# Reordenar los articulos
|
||||
|
||||
La interfaz reordena los articulos y los envia en ese orden particular
|
||||
(se puede enviar un numero de orden completado con js para estar mas
|
||||
segurxs). Entonces el algoritmo...
|
||||
Todos los posts tienen un campo `order`.
|
||||
|
||||
* Chequea que los posts tengan fechas en orden
|
||||
|
||||
* Si alguno(s) no tienen, busca fechas intermedias
|
||||
|
||||
* Cuando todos tienen fechas en orden, guarda los cambios modificando
|
||||
cada post
|
||||
|
||||
---
|
||||
|
||||
* Compara el nuevo orden con el viejo para saber las diferencias
|
||||
|
||||
---
|
||||
|
||||
* Recorre el nuevo orden uno por uno
|
||||
* Se fija si el anterior tiene una fecha menor
|
||||
* Se fija si el siguiente tiene una fecha mayor
|
||||
* Se autoasigna una fecha en el medio
|
||||
* Se guarda al final
|
||||
|
||||
---
|
||||
|
||||
* Todos los posts tienen un ID (su id en el array de la colección)
|
||||
* Toma el post actual
|
||||
* Mueve el post a una posición arbitraria con un nuevo id
|
||||
* Toma la fecha del post siguiente (nuevo_id + 1)
|
||||
* Recorre hacia atrás los anteriores, corriéndolos de a un día hasta una
|
||||
fecha anterior
|
||||
* Los posts posteriores no se tocan
|
||||
|
||||
Teniendo estos artículos
|
||||
|
||||
```
|
||||
1 2017-01-01
|
||||
2 2017-01-02
|
||||
3 2017-01-03
|
||||
4 2017-01-04
|
||||
5 2017-01-05
|
||||
```
|
||||
|
||||
Movemos el artículo 2 a la posición 4
|
||||
|
||||
```
|
||||
1 1 2017-01-01
|
||||
2 3 2017-01-03
|
||||
3 4 2017-01-04
|
||||
4 2 2017-01-02
|
||||
5 5 2017-01-05
|
||||
```
|
||||
|
||||
Reordenamos las fechas
|
||||
|
||||
```
|
||||
1 1 2017-01-01 2017-01-01
|
||||
2 3 2017-01-03 2017-01-02
|
||||
3 4 2017-01-04 2017-01-03
|
||||
4 2 2017-01-02 2017-01-04
|
||||
5 5 2017-01-05 2017-01-05
|
||||
```
|
||||
|
||||
Movemos varios
|
||||
|
||||
```
|
||||
1 4 2017-01-04
|
||||
2 5 2017-01-05
|
||||
3 2 2017-01-02
|
||||
4 3 2017-01-03
|
||||
5 1 2017-01-01
|
||||
```
|
||||
|
||||
Cual es la fecha desde la que se empieza? Vamos hacia atras o hacia
|
||||
adelante?
|
||||
|
||||
Hacia atrás
|
||||
|
||||
```
|
||||
1 4 2017-01-04 2016-12-28
|
||||
2 5 2017-01-05 2016-12-29
|
||||
3 2 2017-01-02 2016-12-30
|
||||
4 3 2017-01-03 2016-12-31
|
||||
5 1 2017-01-01 2017-01-01
|
||||
```
|
||||
|
||||
Hacia adelante
|
||||
|
||||
```
|
||||
1 4 2017-01-04 2017-01-04
|
||||
2 5 2017-01-05 2017-01-05
|
||||
3 2 2017-01-02 2017-01-06
|
||||
4 3 2017-01-03 2017-01-07
|
||||
5 1 2017-01-01 2017-01-08
|
||||
```
|
||||
|
||||
En si las fechas no importan, porque estamos priorizando el orden, las
|
||||
fechas son arbitrarias para engañar a jekyll a tener los posts en cierto
|
||||
orden.
|
||||
|
||||
Por el contrario, para mantener los cambios mínimos, podemos reemplazar
|
||||
hacia adelante comenzando desde la fecha mas baja del orden original.
|
||||
|
||||
```
|
||||
1 4 2017-01-04 2017-01-01
|
||||
2 5 2017-01-05 2017-01-02
|
||||
3 2 2017-01-02 2017-01-03
|
||||
4 3 2017-01-03 2017-01-04
|
||||
5 1 2017-01-01 2017-01-05
|
||||
```
|
||||
|
||||
No quiere decir que en ordenes de fechas mas dispersas se mantengan los
|
||||
cambios mínimos.
|
||||
|
||||
También podemos tomar todo el set original de fechas y asociarselo al
|
||||
orden nuevo de posts. Las fechas se mantienen igual, pero cambia el
|
||||
orden de los posts.
|
||||
|
||||
Qué pasa cuando dos o más artículos comparten la misma fecha?
|
||||
Normalmente se ordenan por nombre, pero en este algoritmo no entra ese
|
||||
orden, se asume que siempre están una fecha adelante o atrás
|
||||
|
||||
---
|
||||
|
||||
Todos los posts tienen un campo order.
|
||||
|
||||
El orden se actualiza en base al orden cronologico.
|
||||
El orden se actualiza en base al orden cronológico.
|
||||
|
||||
En la plantilla se puede ordenar cronólogicamente o por orden numérico.
|
||||
|
||||
Es más simple de implementar y no tiene comportamientos inesperados,
|
||||
como "por qué cambió de fecha?"
|
||||
El orden es independiente de otros metadatos (como layout, categoria,
|
||||
etc), todos los artículos siguen un orden
|
||||
|
||||
Como el orden es un metadato, tenemos que ignorar los tipos de posts que
|
||||
no lo tienen
|
||||
|
||||
El orden por defecto es orden natural, más bajo es más alto.
|
||||
|
|
|
@ -141,4 +141,21 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
|
|||
assert_equal 200, response.status
|
||||
assert_match I18n.t('metadata.image.not_an_image'), response.body
|
||||
end
|
||||
|
||||
test 'se pueden reordenar' do
|
||||
lang = :es
|
||||
posts = @site.posts(lang: lang)
|
||||
reorder = posts.each_index.to_a.shuffle
|
||||
|
||||
post site_posts_reorder_url(@site),
|
||||
headers: @authorization,
|
||||
params: { post: { lang: lang, reorder: reorder } }
|
||||
|
||||
@site = Site.find @site.id
|
||||
|
||||
assert_equal I18n.t('post_service.reorder'),
|
||||
@site.repository.rugged.head.target.message
|
||||
assert_equal reorder,
|
||||
@site.posts(lang: lang).map(&:order).map(&:value)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue