From da77ecf43f926aeeb5356b68d8c01036395bd990 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 16 Aug 2019 20:12:22 -0300 Subject: [PATCH] =?UTF-8?q?actualizar=20y=20eliminar=20art=C3=ADculos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/posts_controller.rb | 39 ++++++--------- app/models/post.rb | 11 +++-- app/models/site.rb | 2 +- app/models/site/repository.rb | 59 ++++++++++++----------- app/services/post_service.rb | 7 +++ app/views/posts/_form.haml | 4 +- app/views/posts/edit.haml | 13 +++-- config/locales/en.yml | 1 + config/locales/es.yml | 1 + doc/posts.md | 5 +- test/controllers/posts_controller_test.rb | 34 +++++++++++++ 11 files changed, 107 insertions(+), 69 deletions(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index f36a06f1..cbe806e1 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -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 diff --git a/app/models/post.rb b/app/models/post.rb index 117e3c5a..9803b16a 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -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 diff --git a/app/models/site.rb b/app/models/site.rb index e81ffcd5..6571ccde 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -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 diff --git a/app/models/site/repository.rb b/app/models/site/repository.rb index ac9fc225..0204bd3e 100644 --- a/app/models/site/repository.rb +++ b/app/models/site/repository.rb @@ -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], - tree: merge.write_tree(rugged), - message: I18n.t('sites.fetch.merge.message'), - author: author, - committer: author, - update_ref: 'HEAD') + .create(rugged, update_ref: 'HEAD', + parents: [master, origin_master], + tree: merge.write_tree(rugged), + message: I18n.t('sites.fetch.merge.message'), + 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', - parents: [rugged.head.target], - tree: rugged.index.write_tree, - message: message, - author: author(usuarie), - committer: committer) + Rugged::Commit.create(rugged, message: message, update_ref: 'HEAD', + parents: [rugged.head.target], + tree: rugged.index.write_tree, + 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) diff --git a/app/services/post_service.rb b/app/services/post_service.rb index 884ca493..9c1566fc 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -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 diff --git a/app/views/posts/_form.haml b/app/views/posts/_form.haml index 5eb89873..3f2b2df6 100644 --- a/app/views/posts/_form.haml +++ b/app/views/posts/_form.haml @@ -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 diff --git a/app/views/posts/edit.haml b/app/views/posts/edit.haml index 855eaf9a..15da071b 100644 --- a/app/views/posts/edit.haml +++ b/app/views/posts/edit.haml @@ -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)), - t('posts.edit')] + 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 diff --git a/config/locales/en.yml b/config/locales/en.yml index 8a72e325..29fcbbe3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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' diff --git a/config/locales/es.yml b/config/locales/es.yml index 81afbb7e..e71d86cb 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -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' diff --git a/doc/posts.md b/doc/posts.md index 00b95182..ba5c946e 100644 --- a/doc/posts.md +++ b/doc/posts.md @@ -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í diff --git a/test/controllers/posts_controller_test.rb b/test/controllers/posts_controller_test.rb index 755d57f8..bad8d0f3 100644 --- a/test/controllers/posts_controller_test.rb +++ b/test/controllers/posts_controller_test.rb @@ -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