actualizar y eliminar artículos
This commit is contained in:
parent
1c96e0b0ff
commit
da77ecf43f
11 changed files with 107 additions and 69 deletions
|
@ -58,29 +58,17 @@ class PostsController < ApplicationController
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@site = find_site
|
@site = find_site
|
||||||
@lang = find_lang(@site)
|
@post = @site.posts.find params[:id]
|
||||||
@post = find_post(@site)
|
|
||||||
|
|
||||||
authorize @post
|
authorize @post
|
||||||
|
|
||||||
@post.update_attributes(repair_nested_params(post_params))
|
service = PostService.new(site: @site,
|
||||||
|
post: @post,
|
||||||
|
usuarie: current_usuarie,
|
||||||
|
params: params)
|
||||||
|
|
||||||
# Solo las usuarias pueden modificar la autoría
|
if service.update.persisted?
|
||||||
if @site.usuarie? current_usuarie
|
redirect_to site_posts_path(@site)
|
||||||
if params[:post][:author].present?
|
|
||||||
@post.update_attributes(author: params[:post][:author])
|
|
||||||
end
|
|
||||||
@post.update_attributes(draft: false)
|
|
||||||
else
|
|
||||||
# Todo lo que crean les invitades es borrador
|
|
||||||
@post.update_attributes(draft: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
if @post.save
|
|
||||||
flash[:success] = @site.config.dig('thanks')
|
|
||||||
redirect_to site_posts_path(@site,
|
|
||||||
category: session[:category],
|
|
||||||
lang: @lang)
|
|
||||||
else
|
else
|
||||||
render 'posts/edit'
|
render 'posts/edit'
|
||||||
end
|
end
|
||||||
|
@ -89,14 +77,17 @@ class PostsController < ApplicationController
|
||||||
# Eliminar artículos
|
# Eliminar artículos
|
||||||
def destroy
|
def destroy
|
||||||
@site = find_site
|
@site = find_site
|
||||||
@lang = find_lang(@site)
|
@post = @site.posts.find params[:id]
|
||||||
@post = find_post(@site)
|
|
||||||
|
|
||||||
authorize @post
|
authorize @post
|
||||||
|
|
||||||
@post.destroy
|
service = PostService.new(site: @site,
|
||||||
|
post: @post,
|
||||||
|
usuarie: current_usuarie,
|
||||||
|
params: params)
|
||||||
|
|
||||||
redirect_to site_posts_path(@site, category: session[:category],
|
# TODO: Notificar si se pudo o no
|
||||||
lang: @lang)
|
service.destroy
|
||||||
|
redirect_to site_posts_path(@site)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -136,16 +136,13 @@ class Post < OpenStruct
|
||||||
|
|
||||||
# Eliminar el artículo del repositorio y de la lista de artículos del
|
# Eliminar el artículo del repositorio y de la lista de artículos del
|
||||||
# sitio
|
# sitio
|
||||||
#
|
|
||||||
# XXX Commit
|
|
||||||
def destroy
|
def destroy
|
||||||
FileUtils.rm_f path.absolute
|
FileUtils.rm_f path.absolute
|
||||||
|
|
||||||
site.posts(lang: lang).delete_if do |post|
|
# TODO: Devolver self en lugar de todo el array
|
||||||
|
site.posts(lang: lang).reject! do |post|
|
||||||
post.path.absolute == path.absolute
|
post.path.absolute == path.absolute
|
||||||
end
|
end
|
||||||
|
|
||||||
!File.exist?(path.absolute) && !site.posts(lang: lang).include?(self)
|
|
||||||
end
|
end
|
||||||
alias destroy! destroy
|
alias destroy! destroy
|
||||||
|
|
||||||
|
@ -212,6 +209,10 @@ class Post < OpenStruct
|
||||||
File.exist?(path.absolute) && full_content == File.read(path.absolute)
|
File.exist?(path.absolute) && full_content == File.read(path.absolute)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroyed?
|
||||||
|
!File.exist?(path.absolute)
|
||||||
|
end
|
||||||
|
|
||||||
def update_attributes(hashable)
|
def update_attributes(hashable)
|
||||||
hashable.to_hash.each do |name, value|
|
hashable.to_hash.each do |name, value|
|
||||||
self[name].value = value
|
self[name].value = value
|
||||||
|
|
|
@ -143,7 +143,7 @@ class Site < ApplicationRecord
|
||||||
@posts ||= {}
|
@posts ||= {}
|
||||||
lang ||= I18n.locale
|
lang ||= I18n.locale
|
||||||
|
|
||||||
return @posts[lang] if @posts[lang].present?
|
return @posts[lang] if @posts.key? lang
|
||||||
|
|
||||||
@posts[lang] = PostRelation.new site: self
|
@posts[lang] = PostRelation.new site: self
|
||||||
|
|
||||||
|
|
|
@ -33,12 +33,8 @@ class Site
|
||||||
|
|
||||||
# Incorpora los cambios en el repositorio actual
|
# Incorpora los cambios en el repositorio actual
|
||||||
#
|
#
|
||||||
# rubocop:disable Metrics/AbcSize
|
def merge(usuarie)
|
||||||
# rubocop:disable Metrics/MethodLength
|
merge = rugged.merge_commits(master, origin_master)
|
||||||
def merge(author)
|
|
||||||
master = rugged.branches['master'].target
|
|
||||||
origin = rugged.branches['origin/master'].target
|
|
||||||
merge = rugged.merge_commits(master, origin)
|
|
||||||
|
|
||||||
# No hacemos nada si hay conflictos
|
# No hacemos nada si hay conflictos
|
||||||
#
|
#
|
||||||
|
@ -47,23 +43,26 @@ class Site
|
||||||
# quién sabe.
|
# quién sabe.
|
||||||
return if merge.conflicts?
|
return if merge.conflicts?
|
||||||
|
|
||||||
author = { name: author.name, email: author.email }
|
|
||||||
commit = Rugged::Commit
|
commit = Rugged::Commit
|
||||||
.create(rugged,
|
.create(rugged, update_ref: 'HEAD',
|
||||||
parents: [master, origin],
|
parents: [master, origin_master],
|
||||||
tree: merge.write_tree(rugged),
|
tree: merge.write_tree(rugged),
|
||||||
message: I18n.t('sites.fetch.merge.message'),
|
message: I18n.t('sites.fetch.merge.message'),
|
||||||
author: author,
|
author: author(usuarie), committer: committer)
|
||||||
committer: author,
|
|
||||||
update_ref: 'HEAD')
|
|
||||||
|
|
||||||
# Forzamos el checkout para mover el HEAD al último commit y
|
# Forzamos el checkout para mover el HEAD al último commit y
|
||||||
# escribir los cambios
|
# escribir los cambios
|
||||||
rugged.checkout 'HEAD', strategy: :force
|
rugged.checkout 'HEAD', strategy: :force
|
||||||
commit
|
commit
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/AbcSize
|
|
||||||
# rubocop:enable Metrics/MethodLength
|
def master
|
||||||
|
rugged.branches['master'].target
|
||||||
|
end
|
||||||
|
|
||||||
|
def origin_master
|
||||||
|
rugged.branches['origin/master'].target
|
||||||
|
end
|
||||||
|
|
||||||
# Compara los commits entre el repositorio remoto y el actual para
|
# Compara los commits entre el repositorio remoto y el actual para
|
||||||
# que luego los podamos mostrar.
|
# que luego los podamos mostrar.
|
||||||
|
@ -86,20 +85,18 @@ class Site
|
||||||
end
|
end
|
||||||
|
|
||||||
# Guarda los cambios en git, de a un archivo por vez
|
# Guarda los cambios en git, de a un archivo por vez
|
||||||
# rubocop:disable Metrics/AbcSize
|
def commit(file:, usuarie:, message:, remove: false)
|
||||||
def commit(file:, usuarie:, message:)
|
remove ? rm(file) : add(file)
|
||||||
rugged.index.add(relativize(file))
|
|
||||||
|
# Escribir los cambios para que el repositorio se vea tal cual
|
||||||
rugged.index.write
|
rugged.index.write
|
||||||
|
|
||||||
Rugged::Commit.create(rugged,
|
Rugged::Commit.create(rugged, message: message, update_ref: 'HEAD',
|
||||||
update_ref: 'HEAD',
|
parents: [rugged.head.target],
|
||||||
parents: [rugged.head.target],
|
tree: rugged.index.write_tree,
|
||||||
tree: rugged.index.write_tree,
|
author: author(usuarie),
|
||||||
message: message,
|
committer: committer)
|
||||||
author: author(usuarie),
|
|
||||||
committer: committer)
|
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/AbcSize
|
|
||||||
|
|
||||||
def author(author)
|
def author(author)
|
||||||
{ name: author.name, email: author.email, time: Time.now }
|
{ name: author.name, email: author.email, time: Time.now }
|
||||||
|
@ -109,6 +106,14 @@ class Site
|
||||||
{ name: 'Sutty', email: "sutty@#{Site.domain}", time: Time.now }
|
{ name: 'Sutty', email: "sutty@#{Site.domain}", time: Time.now }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add(file)
|
||||||
|
rugged.index.add(relativize(file))
|
||||||
|
end
|
||||||
|
|
||||||
|
def rm(file)
|
||||||
|
rugged.index.remove(relativize(file))
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def relativize(file)
|
def relativize(file)
|
||||||
|
|
|
@ -30,11 +30,18 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
|
||||||
post
|
post
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
post.destroy! && commit(action: :destroyed)
|
||||||
|
|
||||||
|
post
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def commit(action:)
|
def commit(action:)
|
||||||
site.repository.commit(file: post.path.absolute,
|
site.repository.commit(file: post.path.absolute,
|
||||||
usuarie: usuarie,
|
usuarie: usuarie,
|
||||||
|
remove: action == :destroyed,
|
||||||
message: I18n.t("post_service.#{action}",
|
message: I18n.t("post_service.#{action}",
|
||||||
title: post.title.value))
|
title: post.title.value))
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
url = site_posts_path(site)
|
url = site_posts_path(site)
|
||||||
method = :post
|
method = :post
|
||||||
else
|
else
|
||||||
url = site_post_path(site, post)
|
url = site_post_path(site, post.id)
|
||||||
method = :patch
|
method = :patch
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
- type = metadata.type
|
- type = metadata.type
|
||||||
= render "posts/attributes/#{type}",
|
= render "posts/attributes/#{type}",
|
||||||
post: post, attribute: attribute,
|
post: post, attribute: attribute,
|
||||||
metadata: metadata
|
metadata: metadata, site: site
|
||||||
|
|
||||||
-# Botones de guardado
|
-# Botones de guardado
|
||||||
= render 'posts/submit', site: site
|
= render 'posts/submit', site: site
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
.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,
|
link_to(@site.name, site_posts_path(@site)),
|
||||||
link_to(t('posts.index'),
|
link_to(t('posts.index'), site_posts_path(@site)),
|
||||||
site_posts_path(@site)),
|
link_to(@post.title.value, site_post_path(@site, @post.id)),
|
||||||
link_to(@post.title, site_post_path(@site, @post)),
|
t('posts.edit')]
|
||||||
t('posts.edit')]
|
|
||||||
|
|
||||||
.row.justify-content-center
|
.row.justify-content-center
|
||||||
.col-md-8
|
.col-md-8
|
||||||
= render 'posts/form'
|
= render 'posts/form', site: @site, post: @post
|
||||||
|
|
|
@ -6,6 +6,7 @@ en:
|
||||||
post_service:
|
post_service:
|
||||||
created: 'Created "%{title}"'
|
created: 'Created "%{title}"'
|
||||||
updated: 'Updated "%{title}"'
|
updated: 'Updated "%{title}"'
|
||||||
|
destroyed: 'Removed "%{title}"'
|
||||||
metadata:
|
metadata:
|
||||||
array:
|
array:
|
||||||
cant_be_empty: 'This field cannot be empty'
|
cant_be_empty: 'This field cannot be empty'
|
||||||
|
|
|
@ -6,6 +6,7 @@ es:
|
||||||
post_service:
|
post_service:
|
||||||
created: 'Creado "%{title}"'
|
created: 'Creado "%{title}"'
|
||||||
updated: 'Modificado "%{title}"'
|
updated: 'Modificado "%{title}"'
|
||||||
|
destroyed: 'Eliminado "%{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'
|
||||||
|
|
|
@ -93,13 +93,12 @@ Al instanciar un `Post`, se pasan el sitio y la plantilla por defecto.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
|
* Reimplementar draft e incomplete (por qué eran distintos?)
|
||||||
|
* Reimplementar subida de imagenes/archivos
|
||||||
* Leer artículos a medida que se los necesita en lugar de todos juntos.
|
* Leer artículos a medida que se los necesita en lugar de todos juntos.
|
||||||
* Reimplementar glosario (se crea un artículo por cada categoría
|
* Reimplementar glosario (se crea un artículo por cada categoría
|
||||||
utilizada)
|
utilizada)
|
||||||
* Reimplementar orden de artículos (ver doc)
|
* Reimplementar orden de artículos (ver doc)
|
||||||
* Reimplementar subida de imagenes/archivos
|
|
||||||
* Reimplementar campo 'pre' y 'post' en los layouts.yml
|
* Reimplementar campo 'pre' y 'post' en los layouts.yml
|
||||||
* Implementar autoría como un array
|
|
||||||
* Reimplementar draft e incomplete (por qué eran distintos?)
|
|
||||||
* Convertir idiomas disponibles a pestañas?
|
* Convertir idiomas disponibles a pestañas?
|
||||||
* Implementar traducciones sin adivinar. Vincular artículos entre sí
|
* Implementar traducciones sin adivinar. Vincular artículos entre sí
|
||||||
|
|
|
@ -58,4 +58,38 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal 200, response.status
|
assert_equal 200, response.status
|
||||||
assert_match @post.title.value, response.body
|
assert_match @post.title.value, response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'se pueden actualizar' do
|
||||||
|
title = SecureRandom.hex
|
||||||
|
|
||||||
|
patch site_post_url(@site, @post.id), headers: @authorization,
|
||||||
|
params: { post: { title: title } }
|
||||||
|
|
||||||
|
assert_equal 302, response.status
|
||||||
|
|
||||||
|
get site_posts_url(@site), headers: @authorization
|
||||||
|
|
||||||
|
assert_match title, response.body
|
||||||
|
|
||||||
|
site = Site.find @site.id
|
||||||
|
assert site.posts.map { |p| p.title.value }.include?(title)
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'se pueden eliminar' do
|
||||||
|
params = ActionController::Parameters.new(post: { author: ['hola'] })
|
||||||
|
assert PostService.new(site: @site,
|
||||||
|
usuarie: @usuarie,
|
||||||
|
post: @post,
|
||||||
|
params: params).update
|
||||||
|
|
||||||
|
delete site_post_url(@site, @post.id), headers: @authorization
|
||||||
|
get site_posts_url(@site), headers: @authorization
|
||||||
|
|
||||||
|
site = Site.find @site.id
|
||||||
|
|
||||||
|
assert_not site.posts.include?(@post)
|
||||||
|
assert @post.destroyed?
|
||||||
|
assert_equal I18n.t('post_service.destroyed', title: @post.title.value),
|
||||||
|
@site.repository.rugged.head.target.message
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue