##// END OF EJS Templates
Ability to delete a version from a wiki page history (#10852)....
Jean-Philippe Lang -
r10493:6cccdce06eff
parent child
Show More
@@ -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.has_attribute?(key)
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