From 5dced8b4b624aabf4215ba21b13957080345c326 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Fri, 17 Jul 2026 23:14:17 +0200 Subject: Route and control trash, restore, and permanent deletion --- app/controllers/nodes_controller.rb | 37 ++++++++++++++++++++-- app/views/nodes/destroy.html.erb | 2 -- config/routes.rb | 2 ++ test/controllers/nodes_controller_test.rb | 52 +++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 4 deletions(-) delete mode 100644 app/views/nodes/destroy.html.erb diff --git a/app/controllers/nodes_controller.rb b/app/controllers/nodes_controller.rb index 9834a178..9ea66ada 100644 --- a/app/controllers/nodes_controller.rb +++ b/app/controllers/nodes_controller.rb @@ -13,7 +13,9 @@ class NodesController < ApplicationController :publish, :unlock, :autosave, - :revert + :revert, + :trash, + :restore_from_trash ] around_action :pin_to_default_locale, :only => [:show, :edit, :update, :autosave] @@ -139,8 +141,39 @@ class NodesController < ApplicationController redirect_to node_path(@node) end + def trash + if @node.trash!(current_user) + flash[:notice] = "Page has been moved to the Trash" + redirect_to node_path(Node.trash) + else + flash[:notice] = "Page is already in the Trash" + redirect_to node_path(@node) + end + rescue ActiveRecord::RecordInvalid, LockedByAnotherUser => e + flash[:error] = e.message + redirect_to node_path(@node) + end + + def restore_from_trash + parent = Node.find(params[:parent_id]) + @node.restore_from_trash!(parent, current_user) + flash[:notice] = "Page has been restored from the Trash" + redirect_to node_path(@node) + rescue ActiveRecord::RecordNotFound + flash[:error] = "Restore target not found" + redirect_to node_path(@node) + rescue ActiveRecord::RecordInvalid => e + flash[:error] = e.message + redirect_to node_path(@node) + end + def destroy - @node.destroy + @node.destroy_from_trash!(current_user) + flash[:notice] = "Page has been permanently deleted" + redirect_to node_path(Node.trash) + rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotDestroyed => e + flash[:error] = e.message + redirect_to node_path(@node) end def publish diff --git a/app/views/nodes/destroy.html.erb b/app/views/nodes/destroy.html.erb deleted file mode 100644 index 065cf1de..00000000 --- a/app/views/nodes/destroy.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -

Nodes#destroy

-

Find me in app/views/nodes/destroy.html.erb

diff --git a/config/routes.rb b/config/routes.rb index c2b95900..16145c53 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -53,6 +53,8 @@ Cccms::Application.routes.draw do put :revoke_shared_preview put :autosave put :revert + put :trash + put :restore_from_trash end resources :translations, controller: 'page_translations', diff --git a/test/controllers/nodes_controller_test.rb b/test/controllers/nodes_controller_test.rb index b0d74161..7e5a9903 100644 --- a/test/controllers/nodes_controller_test.rb +++ b/test/controllers/nodes_controller_test.rb @@ -672,4 +672,56 @@ class NodesControllerTest < ActionController::TestCase assert_equal "Brand New", action.metadata["title"] assert_equal Node.last.unique_name, action.metadata["path"] end + + test "trash moves the node and redirects to the Trash" do + login_as :quentin + node = Node.root.children.create!(:slug => "trash_me") + + put :trash, params: { :id => node.id } + + assert_redirected_to node_path(Node.trash) + assert node.reload.in_trash? + end + + test "trashing the Trash node itself is refused" do + login_as :quentin + + put :trash, params: { :id => Node.trash.id } + + assert_redirected_to node_path(Node.trash) + assert flash[:error].present? + end + + test "restore_from_trash reparents to the given parent" do + login_as :quentin + node = Node.root.children.create!(:slug => "restore_me") + node.trash!(users(:quentin)) + target = Node.root.children.create!(:slug => "restore_home") + + put :restore_from_trash, params: { :id => node.id, :parent_id => target.id } + + assert_redirected_to node_path(node) + assert_equal target, node.reload.parent + end + + test "destroy refuses a node outside the Trash" do + login_as :quentin + node = Node.root.children.create!(:slug => "not_deletable_here") + + delete :destroy, params: { :id => node.id } + + assert Node.exists?(node.id) + assert flash[:error].present? + end + + test "destroy deletes a trashed node and redirects to the Trash" do + login_as :quentin + node = Node.root.children.create!(:slug => "deletable") + node.trash!(users(:quentin)) + + delete :destroy, params: { :id => node.id } + + assert_not Node.exists?(node.id) + assert_redirected_to node_path(Node.trash) + end end -- cgit v1.3