mirror of
https://0xacab.org/sutty/sutty
synced 2024-11-22 21:16:22 +00:00
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
|
service.destroy
|
||||||
redirect_to site_posts_path(@site)
|
redirect_to site_posts_path(@site)
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -221,47 +221,6 @@ class Site < ApplicationRecord
|
||||||
status == 'enqueued'
|
status == 'enqueued'
|
||||||
end
|
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
|
# Obtener una ruta disponible para Sutty
|
||||||
#
|
#
|
||||||
# TODO: Refactorizar y testear
|
# TODO: Refactorizar y testear
|
||||||
|
|
|
@ -85,9 +85,13 @@ class Site
|
||||||
!commits.empty?
|
!commits.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Guarda los cambios en git, de a un archivo por vez
|
# Guarda los cambios en git
|
||||||
def commit(file:, usuarie:, message:, remove: false)
|
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
|
# Escribir los cambios para que el repositorio se vea tal cual
|
||||||
rugged.index.write
|
rugged.index.write
|
||||||
|
|
|
@ -67,6 +67,11 @@ class SitePolicy
|
||||||
pull?
|
pull?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Solo les usuaries pueden reordenar artículos
|
||||||
|
def reorder?
|
||||||
|
site.usuarie? usuarie
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def current_role
|
def current_role
|
||||||
|
|
|
@ -39,19 +39,50 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
|
||||||
post
|
post
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def commit(action:)
|
def commit(action:, file: nil)
|
||||||
site.repository.commit(file: post.path.absolute,
|
site.repository.commit(file: file || post.path.absolute,
|
||||||
usuarie: usuarie,
|
usuarie: usuarie,
|
||||||
remove: action == :destroyed,
|
remove: action == :destroyed,
|
||||||
message: I18n.t("post_service.#{action}",
|
message: I18n.t("post_service.#{action}",
|
||||||
title: post.title.value))
|
title: post.try(:title).try(:value)))
|
||||||
end
|
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)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lang
|
||||||
|
params[:post][:lang] || I18n.locale
|
||||||
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/BlockLength
|
# rubocop:enable Metrics/BlockLength
|
||||||
|
|
|
@ -19,6 +19,7 @@ en:
|
||||||
created: 'Created "%{title}"'
|
created: 'Created "%{title}"'
|
||||||
updated: 'Updated "%{title}"'
|
updated: 'Updated "%{title}"'
|
||||||
destroyed: 'Removed "%{title}"'
|
destroyed: 'Removed "%{title}"'
|
||||||
|
reorder: 'Reorder'
|
||||||
metadata:
|
metadata:
|
||||||
array:
|
array:
|
||||||
cant_be_empty: 'This field cannot be empty'
|
cant_be_empty: 'This field cannot be empty'
|
||||||
|
|
|
@ -19,6 +19,7 @@ es:
|
||||||
created: 'Creado "%{title}"'
|
created: 'Creado "%{title}"'
|
||||||
updated: 'Modificado "%{title}"'
|
updated: 'Modificado "%{title}"'
|
||||||
destroyed: 'Eliminado "%{title}"'
|
destroyed: 'Eliminado "%{title}"'
|
||||||
|
reorder: 'Reordenados'
|
||||||
metadata:
|
metadata:
|
||||||
array:
|
array:
|
||||||
cant_be_empty: 'El campo no puede estar vacío'
|
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'
|
post 'collaborate', to: 'collaborations#accept_collaboration'
|
||||||
|
|
||||||
# Gestionar artículos
|
# Gestionar artículos
|
||||||
|
post :'posts/reorder', to: 'posts#reorder'
|
||||||
resources :posts
|
resources :posts
|
||||||
|
|
||||||
# Gestionar traducciones
|
# Gestionar traducciones
|
||||||
|
|
137
doc/reordenar.md
137
doc/reordenar.md
|
@ -1,134 +1,15 @@
|
||||||
# Reordenar los articulos
|
# Reordenar los articulos
|
||||||
|
|
||||||
La interfaz reordena los articulos y los envia en ese orden particular
|
Todos los posts tienen un campo `order`.
|
||||||
(se puede enviar un numero de orden completado con js para estar mas
|
|
||||||
segurxs). Entonces el algoritmo...
|
|
||||||
|
|
||||||
* Chequea que los posts tengan fechas en orden
|
El orden se actualiza en base al orden cronológico.
|
||||||
|
|
||||||
* 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.
|
|
||||||
|
|
||||||
En la plantilla se puede ordenar cronólogicamente o por orden numérico.
|
En la plantilla se puede ordenar cronólogicamente o por orden numérico.
|
||||||
|
|
||||||
Es más simple de implementar y no tiene comportamientos inesperados,
|
El orden es independiente de otros metadatos (como layout, categoria,
|
||||||
como "por qué cambió de fecha?"
|
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_equal 200, response.status
|
||||||
assert_match I18n.t('metadata.image.not_an_image'), response.body
|
assert_match I18n.t('metadata.image.not_an_image'), response.body
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Reference in a new issue