diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb
index 1aeb90c489..461715ba17 100644
--- a/app/controllers/wiki_controller.rb
+++ b/app/controllers/wiki_controller.rb
@@ -303,7 +303,8 @@ class WikiController < ApplicationController
end
end
@page.destroy
- redirect_to :action => 'index', :project_id => @project
+
+ redirect_to @wiki.pages.any? ? {:action => 'index', :project_id => @project} : project_path(@project)
end
# Export wiki to a single html file
diff --git a/app/controllers/wiki_menu_items_controller.rb b/app/controllers/wiki_menu_items_controller.rb
index ee65450409..867088f9f7 100644
--- a/app/controllers/wiki_menu_items_controller.rb
+++ b/app/controllers/wiki_menu_items_controller.rb
@@ -48,7 +48,13 @@ class WikiMenuItemsController < ApplicationController
get_data_from_params(params)
if wiki_menu_setting == 'no_item'
- @wiki_menu_item.destroy unless @wiki_menu_item.nil?
+ unless @wiki_menu_item.nil?
+ if @wiki_menu_item.is_only_main_item?
+ redirect_to(select_main_menu_item_project_wiki_path(@project, @page.id)) and return
+ else
+ @wiki_menu_item.destroy
+ end
+ end
else
@wiki_menu_item.wiki_id = @page.wiki.id
@wiki_menu_item.name = params[:wiki_menu_item][:name]
@@ -58,18 +64,7 @@ class WikiMenuItemsController < ApplicationController
@wiki_menu_item.parent_id = parent_wiki_menu_item
elsif wiki_menu_setting == 'main_item'
@wiki_menu_item.parent_id = nil
-
- if params[:wiki_menu_item][:new_wiki_page] == "1"
- @wiki_menu_item.new_wiki_page = true
- elsif params[:wiki_menu_item][:new_wiki_page] == "0"
- @wiki_menu_item.new_wiki_page = false
- end
-
- if params[:wiki_menu_item][:index_page] == "1"
- @wiki_menu_item.index_page = true
- elsif params[:wiki_menu_item][:index_page] == "0"
- @wiki_menu_item.index_page = false
- end
+ assign_wiki_menu_item_params @wiki_menu_item
end
end
@@ -83,10 +78,27 @@ class WikiMenuItemsController < ApplicationController
end
end
+ def select_main_menu_item
+ wiki_page_title = params[:id]
+ @possible_wiki_pages = @project.wiki.pages.all(:include => :parent).reject{|page| page.title == wiki_page_title || page.menu_item.present? && page.menu_item.is_main_item?}
+ end
+
+ def replace_main_menu_item
+ current_page = WikiPage.find params[:id]
+ current_menu_item = current_page.menu_item
+
+ if page = WikiPage.find_by_id(params[:wiki_page][:id])
+ create_main_menu_item_for_wiki_page(page, current_menu_item.options)
+ end
+
+ current_menu_item.destroy
+
+ redirect_to action: :edit, id: current_page.title
+ end
+
private
def get_data_from_params(params)
- @project = Project.find(params[:project_id])
@page_title = params[:id]
wiki_id = @project.wiki.id
@@ -102,4 +114,31 @@ class WikiMenuItemsController < ApplicationController
@page.nearest_parent_menu_item(:is_main_item => true).try :id
end
end
+
+ def assign_wiki_menu_item_params(menu_item)
+ if params[:wiki_menu_item][:new_wiki_page] == "1"
+ menu_item.new_wiki_page = true
+ elsif params[:wiki_menu_item][:new_wiki_page] == "0"
+ menu_item.new_wiki_page = false
+ end
+
+ if params[:wiki_menu_item][:index_page] == "1"
+ menu_item.index_page = true
+ elsif params[:wiki_menu_item][:index_page] == "0"
+ menu_item.index_page = false
+ end
+ end
+
+ def create_main_menu_item_for_wiki_page(page, options={})
+ wiki = page.wiki
+
+ menu_item = if item = page.menu_item
+ item.tap {|item| item.parent_id = nil}
+ else
+ wiki.wiki_menu_items.build(title: page.title, name: page.pretty_title)
+ end
+
+ menu_item.options = options
+ menu_item.save
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index aec2b2fd15..628c2338d6 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -718,6 +718,12 @@ class Project < ActiveRecord::Base
enabled_modules.collect(&:name)
end
+ def disable_module(module_name)
+ if module_enabled? module_name
+ self.enabled_module_names = enabled_module_names - [module_name.to_s]
+ end
+ end
+
safe_attributes 'name',
'description',
'summary',
diff --git a/app/models/wiki_menu_item.rb b/app/models/wiki_menu_item.rb
index 3accc221b6..c200de3412 100644
--- a/app/models/wiki_menu_item.rb
+++ b/app/models/wiki_menu_item.rb
@@ -39,7 +39,7 @@ class WikiMenuItem < ActiveRecord::Base
:order => 'id ASC'}
}
- attr_accessible :name, :title
+ attr_accessible :name, :title, :wiki_id
validates_presence_of :title
validates_format_of :title, :with => /\A[^,\.\/\?\;\|\:]*\z/
@@ -84,4 +84,8 @@ class WikiMenuItem < ActiveRecord::Base
def is_sub_item?
!parent_id.nil?
end
+
+ def is_only_main_item?
+ self.class.main_items(wiki.id) == [self]
+ end
end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index e6ac96ae48..2c9360d0ac 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -67,10 +67,17 @@ class WikiPage < ActiveRecord::Base
:joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id"
}
+ scope :main_pages, lambda {|wiki_id|
+ { conditions: {wiki_id: wiki_id, parent_id: nil} }
+ }
+
# Wiki pages that are protected by default
DEFAULT_PROTECTED_PAGES = %w(sidebar)
after_destroy :delete_wiki_menu_item
+ after_destroy do |wiki_page|
+ wiki_page.wiki.project.disable_module(:wiki) and wiki_page.wiki.destroy if is_only_wiki_page?
+ end
def check_and_mark_as_protected
if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
@@ -249,6 +256,10 @@ class WikiPage < ActiveRecord::Base
def validate_same_project
errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
end
+
+ def is_only_wiki_page?
+ wiki.pages.reject {|page| page == self}.empty?
+ end
end
class WikiDiff < Redmine::Helpers::Diff
diff --git a/app/views/wiki_menu_items/select_main_menu_item.html.erb b/app/views/wiki_menu_items/select_main_menu_item.html.erb
new file mode 100644
index 0000000000..c88066ec66
--- /dev/null
+++ b/app/views/wiki_menu_items/select_main_menu_item.html.erb
@@ -0,0 +1,45 @@
+<%#-- copyright
+OpenProject is a project management system.
+Copyright (C) 2012-2013 the OpenProject Foundation (OPF)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License version 3.
+
+OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
+Copyright (C) 2006-2013 Jean-Philippe Lang
+Copyright (C) 2010-2013 the ChiliProject Team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+See doc/COPYRIGHT.rdoc for more details.
+
+++#%>
+
+
+
+
+ <%= submit_tag t(:button_save) %>
+<% end %>
diff --git a/config/locales/de.yml b/config/locales/de.yml
index a151b4a256..04220175de 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -601,6 +601,7 @@ de:
label_calendar: "Kalender"
label_calendar_show: "Kalender anzeigen"
label_category: "Kategorie"
+ label_select_main_menu_item: Neuen Hauptmenüpunkt auwählen
label_change_plural: "Änderungen"
label_change_properties: "Eigenschaften ändern"
label_change_status: "Statuswechsel"
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 1daadea715..b716150df7 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -596,6 +596,7 @@ en:
label_calendar: "Calendar"
label_calendar_show: "Show Calendar"
label_category: "Category"
+ label_select_main_menu_item: Select new main menu item
label_change_plural: "Changes"
label_change_properties: "Change properties"
label_change_status: "Change status"
diff --git a/config/routes.rb b/config/routes.rb
index e5cbbe50ec..0e9f51c71f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -201,6 +201,8 @@ OpenProject::Application.routes.draw do
post :protect
post :add_attachment
get :list_attachments
+ get :select_main_menu_item, to: 'wiki_menu_items#select_main_menu_item'
+ post :replace_main_menu_item, to: 'wiki_menu_items#replace_main_menu_item'
end
end
# as routes for index and show are swapped
diff --git a/features/step_definitions/wiki_menu_item_steps.rb b/features/step_definitions/wiki_menu_item_steps.rb
new file mode 100644
index 0000000000..1889992138
--- /dev/null
+++ b/features/step_definitions/wiki_menu_item_steps.rb
@@ -0,0 +1,32 @@
+#-- copyright
+# OpenProject is a project management system.
+# Copyright (C) 2012-2013 the OpenProject Foundation (OPF)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version 3.
+#
+# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
+# Copyright (C) 2006-2013 Jean-Philippe Lang
+# Copyright (C) 2010-2013 the ChiliProject Team
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# See doc/COPYRIGHT.rdoc for more details.
+#++
+
+Given /^the wiki menu item of the wiki page "(.*?)" of project "(.*?)" has been deleted$/ do |item_name, project_name|
+ project = Project.find_by_name project_name
+ WikiPage.where(title: item_name, wiki_id: project.wiki.id).first.delete_wiki_menu_item
+end
diff --git a/features/wiki/wiki_index.feature b/features/wiki/wiki_index.feature
index a2321c029a..78816d1d4f 100644
--- a/features/wiki/wiki_index.feature
+++ b/features/wiki/wiki_index.feature
@@ -64,7 +64,3 @@ Feature: Viewing the wiki index page
When I go to the wiki index page below the "ParentWikiPage" page of the project called "project1"
Then I should see "Index by title" within "#content"
And there should be no menu item selected
-
-
-
-
diff --git a/features/wiki_menu_items/wiki_menu_items.feature b/features/wiki_menu_items/wiki_menu_items.feature
index f14184a15c..70b8d84633 100644
--- a/features/wiki_menu_items/wiki_menu_items.feature
+++ b/features/wiki_menu_items/wiki_menu_items.feature
@@ -29,13 +29,14 @@
Feature: Wiki menu items
Background:
Given there is 1 project with the following:
- | name | Awesome Project |
- | identifier | awesome-project |
+ | name | Awesome Project |
+ | identifier | awesome-project |
And there is a role "member"
And the role "member" may have the following rights:
- | view_wiki_pages |
- | edit_wiki_pages |
- | manage_wiki_menu |
+ | view_wiki_pages |
+ | edit_wiki_pages |
+ | delete_wiki_pages |
+ | manage_wiki_menu |
And there is 1 user with the following:
| login | bob |
And the user "bob" is a "member" in the project "Awesome Project"
@@ -116,3 +117,19 @@ Feature: Wiki menu items
And I choose "Do not show this wikipage in project navigation"
And I press "Save"
Then I should not see "Wiki" within "#main-menu"
+
+ @javascript
+ Scenario: When I delete the last wiki page with a menu item I can select a new menu item and the menu item is replaced
+ Given the project "Awesome Project" has a wiki menu item with the following:
+ | title | AwesomePage |
+ | name | AwesomePage |
+ And the wiki menu item of the wiki page "Wiki" of project "Awesome Project" has been deleted
+ When I go to the wiki page "AwesomePage" for the project called "Awesome Project"
+ And I click on "More functions"
+ And I click on "Configure menu item"
+ And I choose "Do not show this wikipage in project navigation"
+ And I press "Save"
+ And I select "Wiki" from "main-menu-item-select"
+ And I press "Save"
+ Then I should not see "AwesomePage" within "#main-menu"
+ Then I should see "Wiki" within "#main-menu"
diff --git a/lib/redmine.rb b/lib/redmine.rb
index fb457f7eab..9b88ea11b7 100644
--- a/lib/redmine.rb
+++ b/lib/redmine.rb
@@ -152,7 +152,7 @@ Redmine::AccessControl.map do |map|
map.project_module :wiki do |map|
map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
- map.permission :manage_wiki_menu, {:wiki_menu_items => [:edit, :update]}, :require => :member
+ map.permission :manage_wiki_menu, {:wiki_menu_items => [:edit, :update, :select_main_menu_item, :replace_main_menu_item]}, :require => :member
map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
map.permission :change_wiki_parent_page, {:wiki => [:edit_parent_page, :update_parent_page]},
:require => :member
diff --git a/spec/controllers/wiki_controller_spec.rb b/spec/controllers/wiki_controller_spec.rb
index 0bddfd7808..fb5067216f 100644
--- a/spec/controllers/wiki_controller_spec.rb
+++ b/spec/controllers/wiki_controller_spec.rb
@@ -49,7 +49,7 @@ describe WikiController do
# creating pages
@existing_page = FactoryGirl.create(:wiki_page, :wiki_id => @project.wiki.id,
- :title => 'ExisitingPage')
+ :title => 'ExistingPage')
# creating page contents
FactoryGirl.create(:wiki_content, :page_id => @existing_page.id,
@@ -187,7 +187,31 @@ describe WikiController do
end
end
end
- end
+
+ describe 'destroy' do
+ describe 'successful action' do
+ context 'when it is not the only wiki page' do
+ let(:wiki) { @project.wiki }
+
+ before do
+ another_wiki_page = FactoryGirl.create :wiki_page, wiki: wiki
+ end
+
+ it 'redirects to wiki#index' do
+ delete :destroy, project_id: @project, id: @existing_page
+ response.should redirect_to action: 'index', project_id: @project
+ end
+ end
+
+ context 'when it is the only wiki page' do
+ it 'redirects to projects#show' do
+ delete :destroy, project_id: @project, id: @existing_page
+ response.should redirect_to project_path(@project)
+ end
+ end
+ end
+ end
+ end # describe 'actions'
describe 'view related stuff' do
render_views
diff --git a/spec/controllers/wiki_menu_items_controller_spec.rb b/spec/controllers/wiki_menu_items_controller_spec.rb
index 445133d557..cfe7814ace 100644
--- a/spec/controllers/wiki_menu_items_controller_spec.rb
+++ b/spec/controllers/wiki_menu_items_controller_spec.rb
@@ -35,20 +35,8 @@ describe WikiMenuItemsController do
let(:project) { FactoryGirl.create(:project).reload } # a wiki is created for project, but the object doesn't know of it (FIXME?)
let(:wiki) { project.wiki }
- # wiki pages
let(:wiki_page) { FactoryGirl.create(:wiki_page, :wiki => wiki) } # first wiki page without child pages
- let!(:top_level_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => wiki_page.title) }
- let(:another_wiki_page) { FactoryGirl.create(:wiki_page, :wiki => wiki) } # second wiki page with two child pages
- let!(:another_wiki_page_top_level_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => another_wiki_page.title) }
-
- # child pages of another_wiki_page
- let(:child_page) { FactoryGirl.create(:wiki_page, :parent => another_wiki_page, :wiki => wiki) }
- let!(:child_page_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => child_page.title) }
- let(:another_child_page) { FactoryGirl.create(:wiki_page, :parent => another_wiki_page, :wiki => wiki) }
- let!(:another_child_page_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => another_child_page.title, :parent => top_level_wiki_menu_item) }
-
- let(:grand_child_page) { FactoryGirl.create(:wiki_page, :parent => child_page, :wiki => wiki) }
- let!(:grand_child_page_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => grand_child_page.title) }
+ let!(:top_level_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :with_menu_item_options, :wiki => wiki, :title => wiki_page.title) }
before :each do
# log in user
@@ -56,6 +44,19 @@ describe WikiMenuItemsController do
end
describe :edit do
+ # more wiki pages with menu items
+ let(:another_wiki_page) { FactoryGirl.create(:wiki_page, :wiki => wiki) } # second wiki page with two child pages
+ let!(:another_wiki_page_top_level_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => another_wiki_page.title) }
+
+ # child pages of another_wiki_page
+ let(:child_page) { FactoryGirl.create(:wiki_page, :parent => another_wiki_page, :wiki => wiki) }
+ let!(:child_page_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => child_page.title) }
+ let(:another_child_page) { FactoryGirl.create(:wiki_page, :parent => another_wiki_page, :wiki => wiki) }
+ let!(:another_child_page_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => another_child_page.title, :parent => top_level_wiki_menu_item) }
+
+ let(:grand_child_page) { FactoryGirl.create(:wiki_page, :parent => child_page, :wiki => wiki) }
+ let!(:grand_child_page_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => grand_child_page.title) }
+
context 'when no parent wiki menu item has been configured yet' do
context 'and it is a child page' do
before { get :edit, project_id: project.id, id: child_page.title }
@@ -91,4 +92,48 @@ describe WikiMenuItemsController do
end
end
end
+
+ shared_context 'when there is one more wiki page with a child page' do
+ let!(:another_wiki_page) { FactoryGirl.create(:wiki_page, :wiki => wiki) } # second wiki page with two child pages
+ let!(:child_page) { FactoryGirl.create(:wiki_page, :parent => another_wiki_page, :wiki => wiki) }
+ end
+
+ describe :select_main_menu_item do
+ include_context 'when there is one more wiki page with a child page'
+
+ before { get :select_main_menu_item, project_id: project, id: wiki_page.title }
+ subject { assigns['possible_wiki_pages'] }
+
+ context 'when selecting a new wiki page to replace the current main menu item' do
+ it { should include another_wiki_page }
+ it { should include child_page }
+ it { should_not include wiki_page }
+ end
+ end
+
+ describe :replace_main_menu_item do
+ include_context 'when there is one more wiki page with a child page'
+
+ let(:selected_page) { child_page }
+ let(:new_menu_item) { selected_page.menu_item }
+
+ before do
+ post :replace_main_menu_item, project_id: project,
+ id: wiki_page.id,
+ wiki_page: { id: selected_page.id }
+ end
+
+ it 'destroys the current wiki menu item' do
+ wiki_page.menu_item.should be_nil
+ end
+
+ it 'creates a new main menu item for the selected wiki page' do
+ selected_page.menu_item.should be_present
+ selected_page.menu_item.parent.should be_nil
+ end
+
+ it 'transfers the menu item options to the selected wiki page' do
+ new_menu_item.options.should == { index_page: true, new_wiki_page: true }
+ end
+ end
end
diff --git a/spec/factories/wiki_menu_item_factory.rb b/spec/factories/wiki_menu_item_factory.rb
index 60d0f97681..58ff08be2d 100644
--- a/spec/factories/wiki_menu_item_factory.rb
+++ b/spec/factories/wiki_menu_item_factory.rb
@@ -32,5 +32,10 @@ FactoryGirl.define do
sequence(:name) {|n| "Item No. #{n}" }
sequence(:title) {|n| "Wiki Title #{n}" }
+
+ trait :with_menu_item_options do
+ index_page true
+ new_wiki_page true
+ end
end
end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index 110b8c41a0..985c23fdeb 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -29,9 +29,11 @@
require 'spec_helper'
describe WikiPage do
+ let(:project) { FactoryGirl.create(:project).reload } # a wiki is created for project, but the object doesn't know of it (FIXME?)
+ let(:wiki) { project.wiki }
+ let(:wiki_page) { FactoryGirl.create(:wiki_page, :wiki => wiki) }
+
describe '#nearest_parent_menu_item' do
- let(:wiki_page) { FactoryGirl.create(:wiki_page) }
- let(:wiki) { wiki_page.wiki }
let!(:wiki_page_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => wiki_page.title) }
let(:child_page) { FactoryGirl.create(:wiki_page, :parent => wiki_page, :wiki => wiki) }
let!(:child_page_wiki_menu_item) { FactoryGirl.create(:wiki_menu_item, :wiki => wiki, :title => child_page.title, :parent => wiki_page_wiki_menu_item) }
@@ -50,4 +52,37 @@ describe WikiPage do
end
end
end
+
+ describe '#destroy' do
+ context 'when the only wiki page is destroyed' do
+ before do
+ wiki_page.destroy
+ project.reload
+ end
+
+ it 'deactivates the wiki module' do
+ project.module_enabled?(:wiki).should be_false
+ end
+
+ it 'destroys the project wiki' do
+ project.wiki.should be_nil
+ end
+ end
+
+ context 'when one of two wiki pages is destroyed' do
+ before do
+ another_wiki_page = FactoryGirl.create(:wiki_page, :wiki => wiki)
+ wiki_page.destroy
+ project.reload
+ end
+
+ it 'does not deactivate the wiki module' do
+ project.module_enabled?(:wiki).should be_true
+ end
+
+ it 'does not destroy the project wiki' do
+ project.wiki.should be_present
+ end
+ end
+ end
end