Ask user what to do with child pages when deleting a parent wiki page (#3202).

3 options are available:
* move child pages as root pages
* move child pages to another parent page
* delete all descendants

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2676 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang 2009-04-21 12:19:56 +00:00
parent 65cbd94e42
commit bb44430b63
42 changed files with 256 additions and 7 deletions

View File

@ -131,9 +131,31 @@ class WikiController < ApplicationController
render_404 unless @annotate
end
# remove a wiki page and its history
# Removes a wiki page and its history
# Children can be either set as root pages, removed or reassigned to another parent page
def destroy
return render_403 unless editable?
@descendants_count = @page.descendants.size
if @descendants_count > 0
case params[:todo]
when 'nullify'
# Nothing to do
when 'destroy'
# Removes all its descendants
@page.descendants.each(&:destroy)
when 'reassign'
# Reassign children to another parent page
reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
return unless reassign_to
@page.children.each do |child|
child.update_attribute(:parent, reassign_to)
end
else
@reassignable_to = @wiki.pages - @page.self_and_descendants
return
end
end
@page.destroy
redirect_to :action => 'special', :id => @project, :page => 'Page_index'
end

View File

@ -17,6 +17,19 @@
module WikiHelper
def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0)
s = ''
pages.select {|p| p.parent == parent}.each do |page|
attrs = "value='#{page.id}'"
attrs << " selected='selected'" if selected == page
indent = (level > 0) ? ('&nbsp;' * level * 2 + '&#187; ') : nil
s << "<option value='#{page.id}'>#{indent}#{h page.pretty_title}</option>\n" +
wiki_page_options_for_select(pages, selected, page, level + 1)
end
s
end
def html_diff(wdiff)
words = wdiff.words.collect{|word| h(word)}
words_add = 0

View File

@ -22,7 +22,7 @@ class WikiPage < ActiveRecord::Base
belongs_to :wiki
has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
acts_as_tree :order => 'title'
acts_as_tree :dependent => :nullify, :order => 'title'
acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
:description => :text,

View File

@ -0,0 +1,19 @@
<h2><%=h @page.pretty_title %></h2>
<% form_tag({}) do %>
<div class="box">
<p><strong><%= l(:text_wiki_page_destroy_question, :descendants => @descendants_count) %></strong></p>
<p><label><%= radio_button_tag 'todo', 'nullify', true %> <%= l(:text_wiki_page_nullify_children) %></label><br />
<label><%= radio_button_tag 'todo', 'destroy', false %> <%= l(:text_wiki_page_destroy_children) %></label>
<% if @reassignable_to.any? %>
<br />
<label><%= radio_button_tag 'todo', 'reassign', false %> <%= l(:text_wiki_page_reassign_children) %></label>:
<%= select_tag 'reassign_to_id', wiki_page_options_for_select(@reassignable_to),
:onclick => "$('todo_reassign').checked = true;" %>
<% end %>
</p>
</div>
<%= submit_tag l(:button_apply) %>
<%= link_to l(:button_cancel), :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title %>
<% end %>

View File

@ -1,4 +1,4 @@
<h2><%= @page.pretty_title %></h2>
<h2><%=h @page.pretty_title %></h2>
<% form_for :content, @content, :url => {:action => 'edit', :page => @page.title}, :html => {:id => 'wiki_form'} do |f| %>
<%= f.hidden_field :version %>

View File

@ -784,3 +784,7 @@ bg:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -817,3 +817,7 @@ bs:
label_descending: Opadajuće
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -787,3 +787,7 @@ ca:
enumeration_activities: Activitats (seguidor de temps)
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -790,3 +790,7 @@ cs:
label_date_from_to: Od {{start}} do {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -817,3 +817,7 @@ da:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -816,3 +816,7 @@ de:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -761,6 +761,10 @@ en:
text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped."
text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.'
text_custom_field_possible_values_info: 'One line for each value'
text_wiki_page_destroy_question: "This page has {{descendants}} child page(s) and descendant(s). What do you want to do?"
text_wiki_page_nullify_children: "Keep child pages as root pages"
text_wiki_page_destroy_children: "Delete child pages and all their descendants"
text_wiki_page_reassign_children: "Reassign child pages to this parent page"
default_role_manager: Manager
default_role_developper: Developer

View File

@ -837,3 +837,7 @@ es:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -827,3 +827,7 @@ fi:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -791,6 +791,10 @@ fr:
text_repository_usernames_mapping: "Vous pouvez sélectionner ou modifier l'utilisateur Redmine associé à chaque nom d'utilisateur figurant dans l'historique du dépôt.\nLes utilisateurs avec le même identifiant ou la même adresse mail seront automatiquement associés."
text_diff_truncated: '... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.'
text_custom_field_possible_values_info: 'Une ligne par valeur'
text_wiki_page_destroy_question: "Cette page possède {{descendants}} sous-page(s) et descendante(s). Que voulez-vous faire ?"
text_wiki_page_nullify_children: "Conserver les sous-pages en tant que pages racines"
text_wiki_page_destroy_children: "Supprimer les sous-pages et toutes leurs descedantes"
text_wiki_page_reassign_children: "Réaffecter les sous-pages à cette page"
default_role_manager: Manager
default_role_developper: Développeur

View File

@ -816,3 +816,7 @@ gl:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -799,3 +799,7 @@ he:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -822,3 +822,7 @@
label_date_from_to: "{{start}} -tól {{end}} -ig"
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -802,3 +802,7 @@ it:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -815,3 +815,7 @@ ja:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -846,3 +846,7 @@ ko:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -827,3 +827,7 @@ lt:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -772,3 +772,7 @@ nl:
label_date_from_to: Van {{start}} tot {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -789,3 +789,7 @@
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -820,3 +820,7 @@ pl:
label_date_from_to: Od {{start}} do {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -822,3 +822,7 @@ pt-BR:
label_date_from_to: De {{start}} até {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -808,3 +808,7 @@ pt:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -787,3 +787,7 @@ ro:
enumeration_activities: Activitati (timp de lucru)
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -914,3 +914,7 @@ ru:
text_workflow_edit: Выберите роль и трекер для редактирования последовательности состояний
warning_attachments_not_saved: "{{count}} файл(ов) невозможно сохранить."
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -788,3 +788,7 @@ sk:
label_date_from_to: Od {{start}} do {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -786,3 +786,7 @@ sl:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -810,3 +810,7 @@
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -844,3 +844,7 @@ sv:
enumeration_issue_priorities: Ärendeprioriteter
enumeration_doc_categories: Dokumentkategorier
enumeration_activities: Aktiviteter (tidsuppföljning)
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -787,3 +787,7 @@ th:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -823,3 +823,7 @@ tr:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -786,3 +786,7 @@ uk:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -856,3 +856,7 @@ vi:
label_date_from_to: From {{start}} to {{end}}
label_greater_or_equal: ">="
label_less_or_equal: <=
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -894,3 +894,7 @@
enumeration_issue_priorities: 項目優先權
enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (時間追蹤)
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -819,3 +819,7 @@ zh:
enumeration_issue_priorities: 问题优先级
enumeration_doc_categories: 文档类别
enumeration_activities: 活动(时间跟踪)
text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do?
text_wiki_page_reassign_children: Reassign child pages to this parent page
text_wiki_page_nullify_children: Keep child pages as root pages
text_wiki_page_destroy_children: Delete child pages and all their descendants

View File

@ -240,12 +240,50 @@ class WikiControllerTest < Test::Unit::TestCase
)
end
def test_destroy
def test_destroy_child
@request.session[:user_id] = 2
post :destroy, :id => 1, :page => 'CookBook_documentation'
post :destroy, :id => 1, :page => 'Child_1'
assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
end
def test_destroy_parent
@request.session[:user_id] = 2
assert_no_difference('WikiPage.count') do
post :destroy, :id => 1, :page => 'Another_page'
end
assert_response :success
assert_template 'destroy'
end
def test_destroy_parent_with_nullify
@request.session[:user_id] = 2
assert_difference('WikiPage.count', -1) do
post :destroy, :id => 1, :page => 'Another_page', :todo => 'nullify'
end
assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
assert_nil WikiPage.find_by_id(2)
end
def test_destroy_parent_with_cascade
@request.session[:user_id] = 2
assert_difference('WikiPage.count', -3) do
post :destroy, :id => 1, :page => 'Another_page', :todo => 'destroy'
end
assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
assert_nil WikiPage.find_by_id(2)
assert_nil WikiPage.find_by_id(5)
end
def test_destroy_parent_with_reassign
@request.session[:user_id] = 2
assert_difference('WikiPage.count', -1) do
post :destroy, :id => 1, :page => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
end
assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
assert_nil WikiPage.find_by_id(2)
assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
end
def test_special_routing
assert_routing(
{:method => :get, :path => '/projects/567/wiki/page_index'},

View File

@ -100,4 +100,18 @@ class WikiPageTest < Test::Unit::TestCase
assert WikiContent.find_all_by_page_id(1).empty?
assert WikiContent.versioned_class.find_all_by_page_id(1).empty?
end
def test_destroy_should_not_nullify_children
page = WikiPage.find(2)
child_ids = page.child_ids
assert child_ids.any?
page.destroy
assert_nil WikiPage.find_by_id(2)
children = WikiPage.find_all_by_id(child_ids)
assert_equal child_ids.size, children.size
children.each do |child|
assert_nil child.parent_id
end
end
end

View File

@ -40,11 +40,11 @@ module ActiveRecord
# * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
# * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
def acts_as_tree(options = {})
configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil }
configuration = { :foreign_key => "parent_id", :dependent => :destroy, :order => nil, :counter_cache => nil }
configuration.update(options) if options.is_a?(Hash)
belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy
has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => configuration[:dependent]
class_eval <<-EOV
include ActiveRecord::Acts::Tree::InstanceMethods
@ -77,6 +77,13 @@ module ActiveRecord
children + children.collect(&:children).flatten
end
# Returns list of descendants and a reference to the current node.
#
# root.self_and_descendants # => [root, child1, subchild1, subchild2]
def self_and_descendants
[self] + descendants
end
# Returns the root node of the tree.
def root
node = self