mirror of
https://github.com/redmine/redmine.git
synced 2025-11-08 06:15:59 +01:00
Move wiki page to other project (#5450).
git-svn-id: http://svn.redmine.org/redmine/trunk@13643 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -198,9 +198,10 @@ class WikiController < ApplicationController
|
|||||||
@page.redirect_existing_links = true
|
@page.redirect_existing_links = true
|
||||||
# used to display the *original* title if some AR validation errors occur
|
# used to display the *original* title if some AR validation errors occur
|
||||||
@original_title = @page.pretty_title
|
@original_title = @page.pretty_title
|
||||||
if request.post? && @page.update_attributes(params[:wiki_page])
|
@page.safe_attributes = params[:wiki_page]
|
||||||
|
if request.post? && @page.save
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to project_wiki_page_path(@project, @page.title)
|
redirect_to project_wiki_page_path(@page.project, @page.title)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -344,7 +345,11 @@ private
|
|||||||
end
|
end
|
||||||
|
|
||||||
def redirect_to_page(page)
|
def redirect_to_page(page)
|
||||||
redirect_to :action => action_name, :project_id => page.wiki.project, :id => page.title
|
if page.project && page.project.visible?
|
||||||
|
redirect_to :action => action_name, :project_id => page.project, :id => page.title
|
||||||
|
else
|
||||||
|
render_404
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns true if the current user is allowed to edit the page, otherwise false
|
# Returns true if the current user is allowed to edit the page, otherwise false
|
||||||
|
|||||||
@@ -35,6 +35,16 @@ module WikiHelper
|
|||||||
s
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def wiki_page_wiki_options_for_select(page)
|
||||||
|
projects = Project.allowed_to(:rename_wiki_pages).joins(:wiki).preload(:wiki).to_a
|
||||||
|
projects << page.project unless projects.include?(page.project)
|
||||||
|
|
||||||
|
project_tree_options_for_select(projects, :selected => page.project) do |project|
|
||||||
|
wiki_id = project.wiki.try(:id)
|
||||||
|
{:value => wiki_id, :selected => wiki_id == page.wiki_id}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def wiki_page_breadcrumb(page)
|
def wiki_page_breadcrumb(page)
|
||||||
breadcrumb(page.ancestors.reverse.collect {|parent|
|
breadcrumb(page.ancestors.reverse.collect {|parent|
|
||||||
link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project, :version => nil})
|
link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project, :version => nil})
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Wiki < ActiveRecord::Base
|
|||||||
include Redmine::SafeAttributes
|
include Redmine::SafeAttributes
|
||||||
belongs_to :project
|
belongs_to :project
|
||||||
has_many :pages, lambda {order('title')}, :class_name => 'WikiPage', :dependent => :destroy
|
has_many :pages, lambda {order('title')}, :class_name => 'WikiPage', :dependent => :destroy
|
||||||
has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
|
has_many :redirects, :class_name => 'WikiRedirect'
|
||||||
|
|
||||||
acts_as_watchable
|
acts_as_watchable
|
||||||
|
|
||||||
@@ -27,6 +27,8 @@ class Wiki < ActiveRecord::Base
|
|||||||
validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/
|
validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/
|
||||||
attr_protected :id
|
attr_protected :id
|
||||||
|
|
||||||
|
before_destroy :delete_redirects
|
||||||
|
|
||||||
safe_attributes 'start_page'
|
safe_attributes 'start_page'
|
||||||
|
|
||||||
def visible?(user=User.current)
|
def visible?(user=User.current)
|
||||||
@@ -52,11 +54,11 @@ class Wiki < ActiveRecord::Base
|
|||||||
title = start_page if title.blank?
|
title = start_page if title.blank?
|
||||||
title = Wiki.titleize(title)
|
title = Wiki.titleize(title)
|
||||||
page = pages.where("LOWER(title) = LOWER(?)", title).first
|
page = pages.where("LOWER(title) = LOWER(?)", title).first
|
||||||
if !page && !(options[:with_redirect] == false)
|
if page.nil? && options[:with_redirect] != false
|
||||||
# search for a redirect
|
# search for a redirect
|
||||||
redirect = redirects.where("LOWER(title) = LOWER(?)", title).first
|
redirect = redirects.where("LOWER(title) = LOWER(?)", title).first
|
||||||
if redirect
|
if redirect
|
||||||
page = find_page(redirect.redirects_to, :with_redirect => false)
|
page = redirect.target_page
|
||||||
@page_found_with_redirect = true
|
@page_found_with_redirect = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -68,6 +70,12 @@ class Wiki < ActiveRecord::Base
|
|||||||
@page_found_with_redirect
|
@page_found_with_redirect
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Deletes all redirects from/to the wiki
|
||||||
|
def delete_redirects
|
||||||
|
WikiRedirect.where(:wiki_id => id).delete_all
|
||||||
|
WikiRedirect.where(:redirects_to_wiki_id => id).delete_all
|
||||||
|
end
|
||||||
|
|
||||||
# Finds a page by title
|
# Finds a page by title
|
||||||
# The given string can be of one of the forms: "title" or "project:title"
|
# The given string can be of one of the forms: "title" or "project:title"
|
||||||
# Examples:
|
# Examples:
|
||||||
|
|||||||
@@ -46,8 +46,9 @@ class WikiPage < ActiveRecord::Base
|
|||||||
attr_protected :id
|
attr_protected :id
|
||||||
|
|
||||||
validate :validate_parent_title
|
validate :validate_parent_title
|
||||||
before_destroy :remove_redirects
|
before_destroy :delete_redirects
|
||||||
before_save :handle_redirects
|
before_save :handle_rename_or_move
|
||||||
|
after_save :handle_children_move
|
||||||
|
|
||||||
# eager load information about last updates, without loading text
|
# eager load information about last updates, without loading text
|
||||||
scope :with_updated_on, lambda {
|
scope :with_updated_on, lambda {
|
||||||
@@ -58,7 +59,7 @@ class WikiPage < ActiveRecord::Base
|
|||||||
# Wiki pages that are protected by default
|
# Wiki pages that are protected by default
|
||||||
DEFAULT_PROTECTED_PAGES = %w(sidebar)
|
DEFAULT_PROTECTED_PAGES = %w(sidebar)
|
||||||
|
|
||||||
safe_attributes 'parent_id', 'parent_title',
|
safe_attributes 'parent_id', 'parent_title', 'title', 'redirect_existing_links', 'wiki_id',
|
||||||
:if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)}
|
:if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)}
|
||||||
|
|
||||||
def initialize(attributes=nil, *args)
|
def initialize(attributes=nil, *args)
|
||||||
@@ -74,30 +75,67 @@ class WikiPage < ActiveRecord::Base
|
|||||||
|
|
||||||
def title=(value)
|
def title=(value)
|
||||||
value = Wiki.titleize(value)
|
value = Wiki.titleize(value)
|
||||||
@previous_title = read_attribute(:title) if @previous_title.blank?
|
|
||||||
write_attribute(:title, value)
|
write_attribute(:title, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_redirects
|
def safe_attributes=(attrs, user=User.current)
|
||||||
self.title = Wiki.titleize(title)
|
return unless attrs.is_a?(Hash)
|
||||||
# Manage redirects if the title has changed
|
attrs = attrs.deep_dup
|
||||||
if !@previous_title.blank? && (@previous_title != title) && !new_record?
|
|
||||||
# Update redirects that point to the old title
|
# Project and Tracker must be set before since new_statuses_allowed_to depends on it.
|
||||||
wiki.redirects.where(:redirects_to => @previous_title).each do |r|
|
if (w_id = attrs.delete('wiki_id')) && safe_attribute?('wiki_id')
|
||||||
r.redirects_to = title
|
if (w = Wiki.find_by_id(w_id)) && w.project && user.allowed_to?(:rename_wiki_pages, w.project)
|
||||||
r.title == r.redirects_to ? r.destroy : r.save
|
self.wiki = w
|
||||||
end
|
|
||||||
# Remove redirects for the new title
|
|
||||||
wiki.redirects.where(:title => title).each(&:destroy)
|
|
||||||
# Create a redirect to the new title
|
|
||||||
wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
|
|
||||||
@previous_title = nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_redirects
|
super attrs, user
|
||||||
# Remove redirects to this page
|
end
|
||||||
wiki.redirects.where(:redirects_to => title).each(&:destroy)
|
|
||||||
|
# Manages redirects if page is renamed or moved
|
||||||
|
def handle_rename_or_move
|
||||||
|
if !new_record? && (title_changed? || wiki_id_changed?)
|
||||||
|
# Update redirects that point to the old title
|
||||||
|
WikiRedirect.where(:redirects_to => title_was, :redirects_to_wiki_id => wiki_id_was).each do |r|
|
||||||
|
r.redirects_to = title
|
||||||
|
r.redirects_to_wiki_id = wiki_id
|
||||||
|
(r.title == r.redirects_to && r.wiki_id == r.redirects_to_wiki_id) ? r.destroy : r.save
|
||||||
|
end
|
||||||
|
# Remove redirects for the new title
|
||||||
|
WikiRedirect.where(:wiki_id => wiki_id, :title => title).delete_all
|
||||||
|
# Create a redirect to the new title
|
||||||
|
unless redirect_existing_links == "0"
|
||||||
|
WikiRedirect.create(
|
||||||
|
:wiki_id => wiki_id_was, :title => title_was,
|
||||||
|
:redirects_to_wiki_id => wiki_id, :redirects_to => title
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if !new_record? && wiki_id_changed? && parent.present?
|
||||||
|
unless parent.wiki_id == wiki_id
|
||||||
|
self.parent_id = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
private :handle_rename_or_move
|
||||||
|
|
||||||
|
# Moves child pages if page was moved
|
||||||
|
def handle_children_move
|
||||||
|
if !new_record? && wiki_id_changed?
|
||||||
|
children.each do |child|
|
||||||
|
child.wiki_id = wiki_id
|
||||||
|
child.redirect_existing_links = redirect_existing_links
|
||||||
|
unless child.save
|
||||||
|
WikiPage.where(:id => child.id).update_all :parent_nil => nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
private :handle_children_move
|
||||||
|
|
||||||
|
# Deletes redirects to this page
|
||||||
|
def delete_redirects
|
||||||
|
WikiRedirect.where(:redirects_to_wiki_id => wiki_id, :redirects_to => title).delete_all
|
||||||
end
|
end
|
||||||
|
|
||||||
def pretty_title
|
def pretty_title
|
||||||
@@ -136,7 +174,7 @@ class WikiPage < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def project
|
def project
|
||||||
wiki.project
|
wiki.try(:project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def text
|
def text
|
||||||
@@ -196,7 +234,9 @@ class WikiPage < ActiveRecord::Base
|
|||||||
def validate_parent_title
|
def validate_parent_title
|
||||||
errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
|
errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
|
||||||
errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
|
errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
|
||||||
errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
|
if parent_id_changed? && parent && (parent.wiki_id != wiki_id)
|
||||||
|
errors.add(:parent_title, :not_same_project)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,22 @@
|
|||||||
class WikiRedirect < ActiveRecord::Base
|
class WikiRedirect < ActiveRecord::Base
|
||||||
belongs_to :wiki
|
belongs_to :wiki
|
||||||
|
|
||||||
validates_presence_of :title, :redirects_to
|
validates_presence_of :wiki_id, :title, :redirects_to
|
||||||
validates_length_of :title, :redirects_to, :maximum => 255
|
validates_length_of :title, :redirects_to, :maximum => 255
|
||||||
attr_protected :id
|
attr_protected :id
|
||||||
|
|
||||||
|
before_save :set_redirects_to_wiki_id
|
||||||
|
|
||||||
|
def target_page
|
||||||
|
wiki = Wiki.find_by_id(redirects_to_wiki_id)
|
||||||
|
if wiki
|
||||||
|
wiki.find_page(redirects_to, :with_redirect => false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_redirects_to_wiki_id
|
||||||
|
self.redirects_to_wiki_id ||= wiki_id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
@wiki.pages.includes(:parent).to_a - @page.self_and_descendants,
|
@wiki.pages.includes(:parent).to_a - @page.self_and_descendants,
|
||||||
@page.parent),
|
@page.parent),
|
||||||
:label => :field_parent_title %></p>
|
:label => :field_parent_title %></p>
|
||||||
|
|
||||||
|
<% if @page.safe_attribute? 'wiki_id' %>
|
||||||
|
<p><%= f.select :wiki_id, wiki_page_wiki_options_for_select(@page), :label => :label_project %></p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<%= submit_tag l(:button_rename) %>
|
<%= submit_tag l(:button_rename) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
class AddWikiRedirectsRedirectsToWikiId < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
add_column :wiki_redirects, :redirects_to_wiki_id, :integer
|
||||||
|
WikiRedirect.update_all "redirects_to_wiki_id = wiki_id"
|
||||||
|
change_column :wiki_redirects, :redirects_to_wiki_id, :integer, :null => false
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column :wiki_redirects, :redirects_to_wiki_id
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -660,6 +660,39 @@ class WikiControllerTest < ActionController::TestCase
|
|||||||
assert_nil WikiPage.find_by_title('Child_1').parent
|
assert_nil WikiPage.find_by_title('Child_1').parent
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_get_rename_should_show_target_projects_list
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
project = Project.find(5)
|
||||||
|
project.enable_module! :wiki
|
||||||
|
|
||||||
|
get :rename, :project_id => 1, :id => 'Another_page'
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'rename'
|
||||||
|
|
||||||
|
assert_select 'select[name=?]', 'wiki_page[wiki_id]' do
|
||||||
|
assert_select 'option', 2
|
||||||
|
assert_select 'option[value=?][selected=selected]', '1', :text => /eCookbook/
|
||||||
|
assert_select 'option[value=?]', project.wiki.id.to_s, :text => /#{project.name}/
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_rename_with_move
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
project = Project.find(5)
|
||||||
|
project.enable_module! :wiki
|
||||||
|
|
||||||
|
post :rename, :project_id => 1, :id => 'Another_page',
|
||||||
|
:wiki_page => {
|
||||||
|
:wiki_id => project.wiki.id.to_s,
|
||||||
|
:title => 'Another renamed page',
|
||||||
|
:redirect_existing_links => 1
|
||||||
|
}
|
||||||
|
assert_redirected_to '/projects/private-child/wiki/Another_renamed_page'
|
||||||
|
|
||||||
|
page = WikiPage.find(2)
|
||||||
|
assert_equal project.wiki.id, page.wiki_id
|
||||||
|
end
|
||||||
|
|
||||||
def test_destroy_a_page_without_children_should_not_ask_confirmation
|
def test_destroy_a_page_without_children_should_not_ask_confirmation
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
delete :destroy, :project_id => 1, :id => 'Child_2'
|
delete :destroy, :project_id => 1, :id => 'Child_2'
|
||||||
|
|||||||
@@ -101,6 +101,26 @@ class WikiPageTest < ActiveSupport::TestCase
|
|||||||
assert page.save
|
assert page.save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_move_child_should_clear_parent
|
||||||
|
parent = WikiPage.create!(:wiki_id => 1, :title => 'Parent')
|
||||||
|
child = WikiPage.create!(:wiki_id => 1, :title => 'Child', :parent => parent)
|
||||||
|
|
||||||
|
child.wiki_id = 2
|
||||||
|
child.save!
|
||||||
|
assert_equal nil, child.reload.parent_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_move_parent_should_move_child_page
|
||||||
|
parent = WikiPage.create!(:wiki_id => 1, :title => 'Parent')
|
||||||
|
child = WikiPage.create!(:wiki_id => 1, :title => 'Child', :parent => parent)
|
||||||
|
parent.reload
|
||||||
|
|
||||||
|
parent.wiki_id = 2
|
||||||
|
parent.save!
|
||||||
|
assert_equal 2, child.reload.wiki_id
|
||||||
|
assert_equal parent, child.parent
|
||||||
|
end
|
||||||
|
|
||||||
def test_destroy
|
def test_destroy
|
||||||
page = WikiPage.find(1)
|
page = WikiPage.find(1)
|
||||||
page.destroy
|
page.destroy
|
||||||
|
|||||||
@@ -25,15 +25,38 @@ class WikiRedirectTest < ActiveSupport::TestCase
|
|||||||
@original = WikiPage.create(:wiki => @wiki, :title => 'Original title')
|
@original = WikiPage.create(:wiki => @wiki, :title => 'Original title')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_create_redirect
|
def test_create_redirect_on_rename
|
||||||
@original.title = 'New title'
|
@original.title = 'New title'
|
||||||
assert @original.save
|
@original.save!
|
||||||
@original.reload
|
|
||||||
|
|
||||||
assert_equal 'New_title', @original.title
|
redirect = @wiki.redirects.find_by_title('Original_title')
|
||||||
assert @wiki.redirects.find_by_title('Original_title')
|
assert_not_nil redirect
|
||||||
assert @wiki.find_page('Original title')
|
assert_equal 1, redirect.redirects_to_wiki_id
|
||||||
assert @wiki.find_page('ORIGINAL title')
|
assert_equal 'New_title', redirect.redirects_to
|
||||||
|
assert_equal @original, redirect.target_page
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_redirect_on_move
|
||||||
|
@original.wiki_id = 2
|
||||||
|
@original.save!
|
||||||
|
|
||||||
|
redirect = @wiki.redirects.find_by_title('Original_title')
|
||||||
|
assert_not_nil redirect
|
||||||
|
assert_equal 2, redirect.redirects_to_wiki_id
|
||||||
|
assert_equal 'Original_title', redirect.redirects_to
|
||||||
|
assert_equal @original, redirect.target_page
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_redirect_on_rename_and_move
|
||||||
|
@original.title = 'New title'
|
||||||
|
@original.wiki_id = 2
|
||||||
|
@original.save!
|
||||||
|
|
||||||
|
redirect = @wiki.redirects.find_by_title('Original_title')
|
||||||
|
assert_not_nil redirect
|
||||||
|
assert_equal 2, redirect.redirects_to_wiki_id
|
||||||
|
assert_equal 'New_title', redirect.redirects_to
|
||||||
|
assert_equal @original, redirect.target_page
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_update_redirect
|
def test_update_redirect
|
||||||
|
|||||||
@@ -97,4 +97,18 @@ class WikiTest < ActiveSupport::TestCase
|
|||||||
assert_kind_of WikiPage, @wiki.sidebar
|
assert_kind_of WikiPage, @wiki.sidebar
|
||||||
assert_equal 'Sidebar', @wiki.sidebar.title
|
assert_equal 'Sidebar', @wiki.sidebar.title
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_destroy_should_remove_redirects_from_the_wiki
|
||||||
|
WikiRedirect.create!(:wiki_id => 1, :title => 'Foo', :redirects_to_wiki_id => 2, :redirects_to => 'Bar')
|
||||||
|
|
||||||
|
Wiki.find(1).destroy
|
||||||
|
assert_equal 0, WikiRedirect.where(:wiki_id => 1).count
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_destroy_should_remove_redirects_to_the_wiki
|
||||||
|
WikiRedirect.create!(:wiki_id => 2, :title => 'Foo', :redirects_to_wiki_id => 1, :redirects_to => 'Bar')
|
||||||
|
|
||||||
|
Wiki.find(1).destroy
|
||||||
|
assert_equal 0, WikiRedirect.where(:redirects_to_wiki_id => 1).count
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user