##// END OF EJS Templates
Wiki page protection (#851, patch #1146 by Mateo Murphy with slight changes)....
Jean-Philippe Lang -
r1400:04766697357b
parent child
Show More
@@ -0,0 +1,9
1 class AddWikiPagesProtected < ActiveRecord::Migration
2 def self.up
3 add_column :wiki_pages, :protected, :boolean, :default => false, :null => false
4 end
5
6 def self.down
7 remove_column :wiki_pages, :protected
8 end
9 end
@@ -21,7 +21,7 class WikiController < ApplicationController
21 layout 'base'
21 layout 'base'
22 before_filter :find_wiki, :authorize
22 before_filter :find_wiki, :authorize
23
23
24 verify :method => :post, :only => [:destroy, :destroy_attachment], :redirect_to => { :action => :index }
24 verify :method => :post, :only => [:destroy, :destroy_attachment, :protect], :redirect_to => { :action => :index }
25
25
26 helper :attachments
26 helper :attachments
27 include AttachmentsHelper
27 include AttachmentsHelper
@@ -48,12 +48,14 class WikiController < ApplicationController
48 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
48 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
49 return
49 return
50 end
50 end
51 @editable = editable?
51 render :action => 'show'
52 render :action => 'show'
52 end
53 end
53
54
54 # edit an existing page or a new one
55 # edit an existing page or a new one
55 def edit
56 def edit
56 @page = @wiki.find_or_new_page(params[:page])
57 @page = @wiki.find_or_new_page(params[:page])
58 return render_403 unless editable?
57 @page.content = WikiContent.new(:page => @page) if @page.new_record?
59 @page.content = WikiContent.new(:page => @page) if @page.new_record?
58
60
59 @content = @page.content_for_version(params[:version])
61 @content = @page.content_for_version(params[:version])
@@ -82,7 +84,8 class WikiController < ApplicationController
82
84
83 # rename a page
85 # rename a page
84 def rename
86 def rename
85 @page = @wiki.find_page(params[:page])
87 @page = @wiki.find_page(params[:page])
88 return render_403 unless editable?
86 @page.redirect_existing_links = true
89 @page.redirect_existing_links = true
87 # used to display the *original* title if some AR validation errors occur
90 # used to display the *original* title if some AR validation errors occur
88 @original_title = @page.pretty_title
91 @original_title = @page.pretty_title
@@ -92,6 +95,12 class WikiController < ApplicationController
92 end
95 end
93 end
96 end
94
97
98 def protect
99 page = @wiki.find_page(params[:page])
100 page.update_attribute :protected, params[:protected]
101 redirect_to :action => 'index', :id => @project, :page => page.title
102 end
103
95 # show page history
104 # show page history
96 def history
105 def history
97 @page = @wiki.find_page(params[:page])
106 @page = @wiki.find_page(params[:page])
@@ -122,6 +131,7 class WikiController < ApplicationController
122 # remove a wiki page and its history
131 # remove a wiki page and its history
123 def destroy
132 def destroy
124 @page = @wiki.find_page(params[:page])
133 @page = @wiki.find_page(params[:page])
134 return render_403 unless editable?
125 @page.destroy if @page
135 @page.destroy if @page
126 redirect_to :action => 'special', :id => @project, :page => 'Page_index'
136 redirect_to :action => 'special', :id => @project, :page => 'Page_index'
127 end
137 end
@@ -152,6 +162,7 class WikiController < ApplicationController
152
162
153 def preview
163 def preview
154 page = @wiki.find_page(params[:page])
164 page = @wiki.find_page(params[:page])
165 return render_403 unless editable?(page)
155 @attachements = page.attachments if page
166 @attachements = page.attachments if page
156 @text = params[:content][:text]
167 @text = params[:content][:text]
157 render :partial => 'common/preview'
168 render :partial => 'common/preview'
@@ -159,12 +170,14 class WikiController < ApplicationController
159
170
160 def add_attachment
171 def add_attachment
161 @page = @wiki.find_page(params[:page])
172 @page = @wiki.find_page(params[:page])
173 return render_403 unless editable?
162 attach_files(@page, params[:attachments])
174 attach_files(@page, params[:attachments])
163 redirect_to :action => 'index', :page => @page.title
175 redirect_to :action => 'index', :page => @page.title
164 end
176 end
165
177
166 def destroy_attachment
178 def destroy_attachment
167 @page = @wiki.find_page(params[:page])
179 @page = @wiki.find_page(params[:page])
180 return render_403 unless editable?
168 @page.attachments.find(params[:attachment_id]).destroy
181 @page.attachments.find(params[:attachment_id]).destroy
169 redirect_to :action => 'index', :page => @page.title
182 redirect_to :action => 'index', :page => @page.title
170 end
183 end
@@ -178,4 +191,9 private
178 rescue ActiveRecord::RecordNotFound
191 rescue ActiveRecord::RecordNotFound
179 render_404
192 render_404
180 end
193 end
194
195 # Returns true if the current user is allowed to edit the page, otherwise false
196 def editable?(page = @page)
197 page.editable_by?(User.current)
198 end
181 end
199 end
@@ -105,6 +105,11 class WikiPage < ActiveRecord::Base
105 def text
105 def text
106 content.text if content
106 content.text if content
107 end
107 end
108
109 # Returns true if usr is allowed to edit the page, otherwise false
110 def editable_by?(usr)
111 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
112 end
108 end
113 end
109
114
110 class WikiDiff
115 class WikiDiff
@@ -1,8 +1,12
1 <div class="contextual">
1 <div class="contextual">
2 <% if @editable %>
2 <%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :page => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.version == @page.content.version %>
3 <%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :page => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.version == @page.content.version %>
4 <%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :page => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %>
5 <%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :page => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %>
3 <%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :page => @page.title}, :class => 'icon icon-move') if @content.version == @page.content.version %>
6 <%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :page => @page.title}, :class => 'icon icon-move') if @content.version == @page.content.version %>
4 <%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :page => @page.title}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %>
7 <%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :page => @page.title}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %>
5 <%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :page => @page.title, :version => @content.version }, :class => 'icon icon-cancel') if @content.version < @page.content.version %>
8 <%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :page => @page.title, :version => @content.version }, :class => 'icon icon-cancel') if @content.version < @page.content.version %>
9 <% end %>
6 <%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>
10 <%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>
7 </div>
11 </div>
8
12
@@ -22,9 +26,9
22
26
23 <%= render(:partial => "wiki/content", :locals => {:content => @content}) %>
27 <%= render(:partial => "wiki/content", :locals => {:content => @content}) %>
24
28
25 <%= link_to_attachments @page.attachments, :delete_url => (authorize_for('wiki', 'destroy_attachment') ? {:controller => 'wiki', :action => 'destroy_attachment', :page => @page.title} : nil) %>
29 <%= link_to_attachments @page.attachments, :delete_url => ((@editable && authorize_for('wiki', 'destroy_attachment')) ? {:controller => 'wiki', :action => 'destroy_attachment', :page => @page.title} : nil) %>
26
30
27 <% if authorize_for('wiki', 'add_attachment') %>
31 <% if @editable && authorize_for('wiki', 'add_attachment') %>
28 <p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
32 <p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
29 :id => 'attach_files_link' %></p>
33 :id => 'attach_files_link' %></p>
30 <% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
34 <% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
@@ -76,6 +76,7 Redmine::AccessControl.map do |map|
76 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
76 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
77 map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :annotate, :special]
77 map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :annotate, :special]
78 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment]
78 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment]
79 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
79 end
80 end
80
81
81 map.project_module :repository do |map|
82 map.project_module :repository do |map|
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -29,6 +29,7 roles_001:
29 - :manage_documents
29 - :manage_documents
30 - :view_wiki_pages
30 - :view_wiki_pages
31 - :edit_wiki_pages
31 - :edit_wiki_pages
32 - :protect_wiki_pages
32 - :delete_wiki_pages
33 - :delete_wiki_pages
33 - :rename_wiki_pages
34 - :rename_wiki_pages
34 - :add_messages
35 - :add_messages
@@ -69,6 +70,7 roles_002:
69 - :manage_documents
70 - :manage_documents
70 - :view_wiki_pages
71 - :view_wiki_pages
71 - :edit_wiki_pages
72 - :edit_wiki_pages
73 - :protect_wiki_pages
72 - :delete_wiki_pages
74 - :delete_wiki_pages
73 - :add_messages
75 - :add_messages
74 - :manage_boards
76 - :manage_boards
@@ -4,19 +4,23 wiki_pages_001:
4 title: CookBook_documentation
4 title: CookBook_documentation
5 id: 1
5 id: 1
6 wiki_id: 1
6 wiki_id: 1
7 protected: true
7 wiki_pages_002:
8 wiki_pages_002:
8 created_on: 2007-03-08 00:18:07 +01:00
9 created_on: 2007-03-08 00:18:07 +01:00
9 title: Another_page
10 title: Another_page
10 id: 2
11 id: 2
11 wiki_id: 1
12 wiki_id: 1
13 protected: false
12 wiki_pages_003:
14 wiki_pages_003:
13 created_on: 2007-03-08 00:18:07 +01:00
15 created_on: 2007-03-08 00:18:07 +01:00
14 title: Start_page
16 title: Start_page
15 id: 3
17 id: 3
16 wiki_id: 2
18 wiki_id: 2
19 protected: false
17 wiki_pages_004:
20 wiki_pages_004:
18 created_on: 2007-03-08 00:18:07 +01:00
21 created_on: 2007-03-08 00:18:07 +01:00
19 title: Page_with_an_inline_image
22 title: Page_with_an_inline_image
20 id: 4
23 id: 4
21 wiki_id: 1
24 wiki_id: 1
25 protected: false
22 No newline at end of file
26
@@ -160,4 +160,60 class WikiControllerTest < Test::Unit::TestCase
160 get :index, :id => 999
160 get :index, :id => 999
161 assert_response 404
161 assert_response 404
162 end
162 end
163
164 def test_protect_page
165 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
166 assert !page.protected?
167 @request.session[:user_id] = 2
168 post :protect, :id => 1, :page => page.title, :protected => '1'
169 assert_redirected_to 'wiki/ecookbook/Another_page'
170 assert page.reload.protected?
171 end
172
173 def test_unprotect_page
174 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
175 assert page.protected?
176 @request.session[:user_id] = 2
177 post :protect, :id => 1, :page => page.title, :protected => '0'
178 assert_redirected_to 'wiki/ecookbook'
179 assert !page.reload.protected?
180 end
181
182 def test_show_page_with_edit_link
183 @request.session[:user_id] = 2
184 get :index, :id => 1
185 assert_response :success
186 assert_template 'show'
187 assert_tag :tag => 'a', :attributes => { :href => '/wiki/1/CookBook_documentation/edit' }
188 end
189
190 def test_show_page_without_edit_link
191 @request.session[:user_id] = 4
192 get :index, :id => 1
193 assert_response :success
194 assert_template 'show'
195 assert_no_tag :tag => 'a', :attributes => { :href => '/wiki/1/CookBook_documentation/edit' }
196 end
197
198 def test_edit_unprotected_page
199 # Non members can edit unprotected wiki pages
200 @request.session[:user_id] = 4
201 get :edit, :id => 1, :page => 'Another_page'
202 assert_response :success
203 assert_template 'edit'
204 end
205
206 def test_edit_protected_page_by_nonmember
207 # Non members can't edit protected wiki pages
208 @request.session[:user_id] = 4
209 get :edit, :id => 1, :page => 'CookBook_documentation'
210 assert_response 403
211 end
212
213 def test_edit_protected_page_by_member
214 @request.session[:user_id] = 2
215 get :edit, :id => 1, :page => 'CookBook_documentation'
216 assert_response :success
217 assert_template 'edit'
218 end
163 end
219 end
General Comments 0
You need to be logged in to leave comments. Login now