actualizar y eliminar artículos

This commit is contained in:
f 2019-08-16 20:12:22 -03:00
parent 1c96e0b0ff
commit da77ecf43f
No known key found for this signature in database
GPG key ID: 2AE5A13E321F953D
11 changed files with 107 additions and 69 deletions

View file

@ -58,29 +58,17 @@ class PostsController < ApplicationController
def update
@site = find_site
@lang = find_lang(@site)
@post = find_post(@site)
@post = @site.posts.find params[:id]
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 @site.usuarie? current_usuarie
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)
if service.update.persisted?
redirect_to site_posts_path(@site)
else
render 'posts/edit'
end
@ -89,14 +77,17 @@ class PostsController < ApplicationController
# Eliminar artículos
def destroy
@site = find_site
@lang = find_lang(@site)
@post = find_post(@site)
@post = @site.posts.find params[:id]
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],
lang: @lang)
# TODO: Notificar si se pudo o no
service.destroy
redirect_to site_posts_path(@site)
end
end

View file

@ -136,16 +136,13 @@ class Post < OpenStruct
# Eliminar el artículo del repositorio y de la lista de artículos del
# sitio
#
# XXX Commit
def destroy
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
end
!File.exist?(path.absolute) && !site.posts(lang: lang).include?(self)
end
alias destroy! destroy
@ -212,6 +209,10 @@ class Post < OpenStruct
File.exist?(path.absolute) && full_content == File.read(path.absolute)
end
def destroyed?
!File.exist?(path.absolute)
end
def update_attributes(hashable)
hashable.to_hash.each do |name, value|
self[name].value = value

View file

@ -143,7 +143,7 @@ class Site < ApplicationRecord
@posts ||= {}
lang ||= I18n.locale
return @posts[lang] if @posts[lang].present?
return @posts[lang] if @posts.key? lang
@posts[lang] = PostRelation.new site: self

View file

@ -33,12 +33,8 @@ class Site
# Incorpora los cambios en el repositorio actual
#
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def merge(author)
master = rugged.branches['master'].target
origin = rugged.branches['origin/master'].target
merge = rugged.merge_commits(master, origin)
def merge(usuarie)
merge = rugged.merge_commits(master, origin_master)
# No hacemos nada si hay conflictos
#
@ -47,23 +43,26 @@ class Site
# quién sabe.
return if merge.conflicts?
author = { name: author.name, email: author.email }
commit = Rugged::Commit
.create(rugged,
parents: [master, origin],
.create(rugged, update_ref: 'HEAD',
parents: [master, origin_master],
tree: merge.write_tree(rugged),
message: I18n.t('sites.fetch.merge.message'),
author: author,
committer: author,
update_ref: 'HEAD')
author: author(usuarie), committer: committer)
# Forzamos el checkout para mover el HEAD al último commit y
# escribir los cambios
rugged.checkout 'HEAD', strategy: :force
commit
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
# que luego los podamos mostrar.
@ -86,20 +85,18 @@ class Site
end
# Guarda los cambios en git, de a un archivo por vez
# rubocop:disable Metrics/AbcSize
def commit(file:, usuarie:, message:)
rugged.index.add(relativize(file))
def commit(file:, usuarie:, message:, remove: false)
remove ? rm(file) : add(file)
# Escribir los cambios para que el repositorio se vea tal cual
rugged.index.write
Rugged::Commit.create(rugged,
update_ref: 'HEAD',
Rugged::Commit.create(rugged, message: message, update_ref: 'HEAD',
parents: [rugged.head.target],
tree: rugged.index.write_tree,
message: message,
author: author(usuarie),
committer: committer)
end
# rubocop:enable Metrics/AbcSize
def author(author)
{ name: author.name, email: author.email, time: Time.now }
@ -109,6 +106,14 @@ class Site
{ name: 'Sutty', email: "sutty@#{Site.domain}", time: Time.now }
end
def add(file)
rugged.index.add(relativize(file))
end
def rm(file)
rugged.index.remove(relativize(file))
end
private
def relativize(file)

View file

@ -30,11 +30,18 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do
post
end
def destroy
post.destroy! && commit(action: :destroyed)
post
end
private
def commit(action:)
site.repository.commit(file: post.path.absolute,
usuarie: usuarie,
remove: action == :destroyed,
message: I18n.t("post_service.#{action}",
title: post.title.value))
end

View file

@ -13,7 +13,7 @@
url = site_posts_path(site)
method = :post
else
url = site_post_path(site, post)
url = site_post_path(site, post.id)
method = :patch
end
@ -29,7 +29,7 @@
- type = metadata.type
= render "posts/attributes/#{type}",
post: post, attribute: attribute,
metadata: metadata
metadata: metadata, site: site
-# Botones de guardado
= render 'posts/submit', site: site

View file

@ -1,13 +1,12 @@
.row
.col
= render 'layouts/breadcrumb',
crumbs: [ link_to(t('sites.index'), sites_path),
@site.name,
link_to(t('posts.index'),
site_posts_path(@site)),
link_to(@post.title, site_post_path(@site, @post)),
crumbs: [link_to(t('sites.index'), sites_path),
link_to(@site.name, site_posts_path(@site)),
link_to(t('posts.index'), site_posts_path(@site)),
link_to(@post.title.value, site_post_path(@site, @post.id)),
t('posts.edit')]
.row.justify-content-center
.col-md-8
= render 'posts/form'
= render 'posts/form', site: @site, post: @post

View file

@ -6,6 +6,7 @@ en:
post_service:
created: 'Created "%{title}"'
updated: 'Updated "%{title}"'
destroyed: 'Removed "%{title}"'
metadata:
array:
cant_be_empty: 'This field cannot be empty'

View file

@ -6,6 +6,7 @@ es:
post_service:
created: 'Creado "%{title}"'
updated: 'Modificado "%{title}"'
destroyed: 'Eliminado "%{title}"'
metadata:
array:
cant_be_empty: 'El campo no puede estar vacío'

View file

@ -93,13 +93,12 @@ Al instanciar un `Post`, se pasan el sitio y la plantilla por defecto.
## 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.
* Reimplementar glosario (se crea un artículo por cada categoría
utilizada)
* Reimplementar orden de artículos (ver doc)
* Reimplementar subida de imagenes/archivos
* 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?
* Implementar traducciones sin adivinar. Vincular artículos entre sí

View file

@ -58,4 +58,38 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
assert_equal 200, response.status
assert_match @post.title.value, response.body
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