@@ -0,0 +1,68 | |||||
|
1 | # Redmine - project management software | |||
|
2 | # Copyright (C) 2006-2012 Jean-Philippe Lang | |||
|
3 | # | |||
|
4 | # This program is free software; you can redistribute it and/or | |||
|
5 | # modify it under the terms of the GNU General Public License | |||
|
6 | # as published by the Free Software Foundation; either version 2 | |||
|
7 | # of the License, or (at your option) any later version. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU General Public License | |||
|
15 | # along with this program; if not, write to the Free Software | |||
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
|
17 | ||||
|
18 | require File.expand_path('../../test_helper', __FILE__) | |||
|
19 | ||||
|
20 | class WikiContentTest < ActiveSupport::TestCase | |||
|
21 | fixtures :projects, :users, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions | |||
|
22 | ||||
|
23 | def setup | |||
|
24 | end | |||
|
25 | ||||
|
26 | def test_destroy | |||
|
27 | v = WikiContent::Version.find(2) | |||
|
28 | ||||
|
29 | assert_difference 'WikiContent::Version.count', -1 do | |||
|
30 | v.destroy | |||
|
31 | end | |||
|
32 | end | |||
|
33 | ||||
|
34 | def test_destroy_last_version_should_revert_content | |||
|
35 | v = WikiContent::Version.find(3) | |||
|
36 | ||||
|
37 | assert_no_difference 'WikiPage.count' do | |||
|
38 | assert_no_difference 'WikiContent.count' do | |||
|
39 | assert_difference 'WikiContent::Version.count', -1 do | |||
|
40 | assert v.destroy | |||
|
41 | end | |||
|
42 | end | |||
|
43 | end | |||
|
44 | c = WikiContent.find(1) | |||
|
45 | v = c.versions.last | |||
|
46 | assert_equal 2, c.version | |||
|
47 | assert_equal v.version, c.version | |||
|
48 | assert_equal v.comments, c.comments | |||
|
49 | assert_equal v.text, c.text | |||
|
50 | assert_equal v.author, c.author | |||
|
51 | assert_equal v.updated_on, c.updated_on | |||
|
52 | end | |||
|
53 | ||||
|
54 | def test_destroy_all_versions_should_delete_page | |||
|
55 | WikiContent::Version.find(1).destroy | |||
|
56 | WikiContent::Version.find(2).destroy | |||
|
57 | v = WikiContent::Version.find(3) | |||
|
58 | ||||
|
59 | assert_difference 'WikiPage.count', -1 do | |||
|
60 | assert_difference 'WikiContent.count', -1 do | |||
|
61 | assert_difference 'WikiContent::Version.count', -1 do | |||
|
62 | assert v.destroy | |||
|
63 | end | |||
|
64 | end | |||
|
65 | end | |||
|
66 | assert_nil WikiPage.find_by_id(1) | |||
|
67 | end | |||
|
68 | end |
@@ -35,7 +35,7 class WikiController < ApplicationController | |||||
35 | default_search_scope :wiki_pages |
|
35 | default_search_scope :wiki_pages | |
36 | before_filter :find_wiki, :authorize |
|
36 | before_filter :find_wiki, :authorize | |
37 | before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] |
|
37 | before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] | |
38 | before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy] |
|
38 | before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version] | |
39 |
|
39 | |||
40 | helper :attachments |
|
40 | helper :attachments | |
41 | include AttachmentsHelper |
|
41 | include AttachmentsHelper | |
@@ -237,6 +237,14 class WikiController < ApplicationController | |||||
237 | redirect_to :action => 'index', :project_id => @project |
|
237 | redirect_to :action => 'index', :project_id => @project | |
238 | end |
|
238 | end | |
239 |
|
239 | |||
|
240 | def destroy_version | |||
|
241 | return render_403 unless editable? | |||
|
242 | ||||
|
243 | @content = @page.content_for_version(params[:version]) | |||
|
244 | @content.destroy | |||
|
245 | redirect_to_referer_or :action => 'history', :id => @page.title, :project_id => @project | |||
|
246 | end | |||
|
247 | ||||
240 | # Export wiki to a single pdf or html file |
|
248 | # Export wiki to a single pdf or html file | |
241 | def export |
|
249 | def export | |
242 | @pages = @wiki.pages.all(:order => 'title', :include => [:content, :attachments], :limit => 75) |
|
250 | @pages = @wiki.pages.all(:order => 'title', :include => [:content, :attachments], :limit => 75) |
@@ -147,6 +147,10 module ApplicationHelper | |||||
147 | end |
|
147 | end | |
148 | end |
|
148 | end | |
149 |
|
149 | |||
|
150 | def wiki_page_path(page, options={}) | |||
|
151 | url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options)) | |||
|
152 | end | |||
|
153 | ||||
150 | def thumbnail_tag(attachment) |
|
154 | def thumbnail_tag(attachment) | |
151 | link_to image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment)), |
|
155 | link_to image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment)), | |
152 | {:controller => 'attachments', :action => 'show', :id => attachment, :filename => attachment.filename}, |
|
156 | {:controller => 'attachments', :action => 'show', :id => attachment, :filename => attachment.filename}, |
@@ -73,6 +73,8 class WikiContent < ActiveRecord::Base | |||||
73 | "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " + |
|
73 | "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " + | |
74 | "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"} |
|
74 | "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"} | |
75 |
|
75 | |||
|
76 | after_destroy :page_update_after_destroy | |||
|
77 | ||||
76 | def text=(plain) |
|
78 | def text=(plain) | |
77 | case Setting.wiki_compression |
|
79 | case Setting.wiki_compression | |
78 | when 'gzip' |
|
80 | when 'gzip' | |
@@ -128,5 +130,18 class WikiContent < ActiveRecord::Base | |||||
128 | includes(:author). |
|
130 | includes(:author). | |
129 | where("wiki_content_id = ? AND version > ?", wiki_content_id, version).first |
|
131 | where("wiki_content_id = ? AND version > ?", wiki_content_id, version).first | |
130 | end |
|
132 | end | |
|
133 | ||||
|
134 | private | |||
|
135 | ||||
|
136 | # Updates page's content if the latest version is removed | |||
|
137 | # or destroys the page if it was the only version | |||
|
138 | def page_update_after_destroy | |||
|
139 | latest = page.content.versions.reorder("#{self.class.table_name}.version DESC").first | |||
|
140 | if latest && page.content.version != latest.version | |||
|
141 | raise ActiveRecord::Rollback unless page.content.revert_to!(latest) | |||
|
142 | elsif latest.nil? | |||
|
143 | raise ActiveRecord::Rollback unless page.destroy | |||
|
144 | end | |||
|
145 | end | |||
131 | end |
|
146 | end | |
132 | end |
|
147 | end |
@@ -28,7 +28,10 | |||||
28 | <td class="updated_on"><%= format_time(ver.updated_on) %></td> |
|
28 | <td class="updated_on"><%= format_time(ver.updated_on) %></td> | |
29 | <td class="author"><%= link_to_user ver.author %></td> |
|
29 | <td class="author"><%= link_to_user ver.author %></td> | |
30 | <td class="comments"><%=h ver.comments %></td> |
|
30 | <td class="comments"><%=h ver.comments %></td> | |
31 | <td class="buttons"><%= link_to l(:button_annotate), :action => 'annotate', :id => @page.title, :version => ver.version %></td> |
|
31 | <td class="buttons"> | |
|
32 | <%= link_to l(:button_annotate), :action => 'annotate', :id => @page.title, :version => ver.version %> | |||
|
33 | <%= delete_link wiki_page_path(@page, :version => ver.version) if User.current.allowed_to?(:delete_wiki_pages, @page.project) && @version_count > 1 %> | |||
|
34 | </td> | |||
32 | </tr> |
|
35 | </tr> | |
33 | <% line_num += 1 %> |
|
36 | <% line_num += 1 %> | |
34 | <% end %> |
|
37 | <% end %> |
@@ -160,6 +160,7 RedmineApp::Application.routes.draw do | |||||
160 | end |
|
160 | end | |
161 | match 'wiki', :controller => 'wiki', :action => 'show', :via => :get |
|
161 | match 'wiki', :controller => 'wiki', :action => 'show', :via => :get | |
162 | get 'wiki/:id/:version', :to => 'wiki#show' |
|
162 | get 'wiki/:id/:version', :to => 'wiki#show' | |
|
163 | delete 'wiki/:id/:version', :to => 'wiki#destroy_version' | |||
163 | get 'wiki/:id/:version/annotate', :to => 'wiki#annotate' |
|
164 | get 'wiki/:id/:version/annotate', :to => 'wiki#annotate' | |
164 | get 'wiki/:id/:version/diff', :to => 'wiki#diff' |
|
165 | get 'wiki/:id/:version/diff', :to => 'wiki#diff' | |
165 | end |
|
166 | end |
@@ -374,7 +374,7 module ActiveRecord #:nodoc: | |||||
374 | # Clones a model. Used when saving a new version or reverting a model's version. |
|
374 | # Clones a model. Used when saving a new version or reverting a model's version. | |
375 | def clone_versioned_model(orig_model, new_model) |
|
375 | def clone_versioned_model(orig_model, new_model) | |
376 | self.versioned_attributes.each do |key| |
|
376 | self.versioned_attributes.each do |key| | |
377 |
new_model.send("#{key}=", orig_model.send(key)) if orig_model. |
|
377 | new_model.send("#{key}=", orig_model.send(key)) if orig_model.respond_to?(key) | |
378 | end |
|
378 | end | |
379 |
|
379 | |||
380 | if self.class.columns_hash.include?(self.class.inheritance_column) |
|
380 | if self.class.columns_hash.include?(self.class.inheritance_column) |
@@ -118,7 +118,7 Redmine::AccessControl.map do |map| | |||||
118 | map.project_module :wiki do |map| |
|
118 | map.project_module :wiki do |map| | |
119 | map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member |
|
119 | map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member | |
120 | map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member |
|
120 | map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member | |
121 | map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member |
|
121 | map.permission :delete_wiki_pages, {:wiki => [:destroy, :destroy_version]}, :require => :member | |
122 | map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true |
|
122 | map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true | |
123 | map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true |
|
123 | map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true | |
124 | map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true |
|
124 | map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true |
@@ -499,6 +499,7 class WikiControllerTest < ActionController::TestCase | |||||
499 | end |
|
499 | end | |
500 |
|
500 | |||
501 | def test_history |
|
501 | def test_history | |
|
502 | @request.session[:user_id] = 2 | |||
502 | get :history, :project_id => 'ecookbook', :id => 'CookBook_documentation' |
|
503 | get :history, :project_id => 'ecookbook', :id => 'CookBook_documentation' | |
503 | assert_response :success |
|
504 | assert_response :success | |
504 | assert_template 'history' |
|
505 | assert_template 'history' | |
@@ -508,17 +509,24 class WikiControllerTest < ActionController::TestCase | |||||
508 | assert_select "input[type=submit][name=commit]" |
|
509 | assert_select "input[type=submit][name=commit]" | |
509 | assert_select 'td' do |
|
510 | assert_select 'td' do | |
510 | assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => '2' |
|
511 | assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => '2' | |
511 | assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/annotate' |
|
512 | assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/annotate', :text => 'Annotate' | |
|
513 | assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => 'Delete' | |||
512 | end |
|
514 | end | |
513 | end |
|
515 | end | |
514 |
|
516 | |||
515 | def test_history_with_one_version |
|
517 | def test_history_with_one_version | |
516 | get :history, :project_id => 1, :id => 'Another_page' |
|
518 | @request.session[:user_id] = 2 | |
|
519 | get :history, :project_id => 'ecookbook', :id => 'Another_page' | |||
517 | assert_response :success |
|
520 | assert_response :success | |
518 | assert_template 'history' |
|
521 | assert_template 'history' | |
519 | assert_not_nil assigns(:versions) |
|
522 | assert_not_nil assigns(:versions) | |
520 | assert_equal 1, assigns(:versions).size |
|
523 | assert_equal 1, assigns(:versions).size | |
521 | assert_select "input[type=submit][name=commit]", false |
|
524 | assert_select "input[type=submit][name=commit]", false | |
|
525 | assert_select 'td' do | |||
|
526 | assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => '1' | |||
|
527 | assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1/annotate', :text => 'Annotate' | |||
|
528 | assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => 'Delete', :count => 0 | |||
|
529 | end | |||
522 | end |
|
530 | end | |
523 |
|
531 | |||
524 | def test_diff |
|
532 | def test_diff | |
@@ -681,6 +689,18 class WikiControllerTest < ActionController::TestCase | |||||
681 | assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent |
|
689 | assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent | |
682 | end |
|
690 | end | |
683 |
|
691 | |||
|
692 | def test_destroy_version | |||
|
693 | @request.session[:user_id] = 2 | |||
|
694 | assert_difference 'WikiContent::Version.count', -1 do | |||
|
695 | assert_no_difference 'WikiContent.count' do | |||
|
696 | assert_no_difference 'WikiPage.count' do | |||
|
697 | delete :destroy_version, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 2 | |||
|
698 | assert_redirected_to '/projects/ecookbook/wiki/CookBook_documentation/history' | |||
|
699 | end | |||
|
700 | end | |||
|
701 | end | |||
|
702 | end | |||
|
703 | ||||
684 | def test_index |
|
704 | def test_index | |
685 | get :index, :project_id => 'ecookbook' |
|
705 | get :index, :project_id => 'ecookbook' | |
686 | assert_response :success |
|
706 | assert_response :success |
@@ -39,6 +39,11 class RoutingWikiTest < ActionController::IntegrationTest | |||||
39 | :id => 'CookBook_documentation' } |
|
39 | :id => 'CookBook_documentation' } | |
40 | ) |
|
40 | ) | |
41 | assert_routing( |
|
41 | assert_routing( | |
|
42 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2" }, | |||
|
43 | { :controller => 'wiki', :action => 'show', :project_id => '1', | |||
|
44 | :id => 'CookBook_documentation', :version => '2' } | |||
|
45 | ) | |||
|
46 | assert_routing( | |||
42 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2/diff" }, |
|
47 | { :method => 'get', :path => "/projects/1/wiki/CookBook_documentation/2/diff" }, | |
43 | { :controller => 'wiki', :action => 'diff', :project_id => '1', |
|
48 | { :controller => 'wiki', :action => 'diff', :project_id => '1', | |
44 | :id => 'CookBook_documentation', :version => '2' } |
|
49 | :id => 'CookBook_documentation', :version => '2' } | |
@@ -117,5 +122,10 class RoutingWikiTest < ActionController::IntegrationTest | |||||
117 | { :controller => 'wiki', :action => 'destroy', :project_id => '22', |
|
122 | { :controller => 'wiki', :action => 'destroy', :project_id => '22', | |
118 | :id => 'ladida' } |
|
123 | :id => 'ladida' } | |
119 | ) |
|
124 | ) | |
|
125 | assert_routing( | |||
|
126 | { :method => 'delete', :path => "/projects/22/wiki/ladida/3" }, | |||
|
127 | { :controller => 'wiki', :action => 'destroy_version', :project_id => '22', | |||
|
128 | :id => 'ladida', :version => '3' } | |||
|
129 | ) | |||
120 | end |
|
130 | end | |
121 | end |
|
131 | end |
General Comments 0
You need to be logged in to leave comments.
Login now