Project

General

Profile

« Previous | Next » 

Revision 1415

Wiki page protection (#851, patch #1146 by Mateo Murphy with slight changes).
New permission added: protect wiki pages. Once a page is protected, it can be edited/renamed/deleted only by users who have this permission.

View differences:

trunk/app/controllers/wiki_controller.rb
21 21
  layout 'base'
22 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 26
  helper :attachments
27 27
  include AttachmentsHelper   
......
48 48
      send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
49 49
      return
50 50
    end
51
	@editable = editable?
51 52
    render :action => 'show'
52 53
  end
53 54
  
54 55
  # edit an existing page or a new one
55 56
  def edit
56 57
    @page = @wiki.find_or_new_page(params[:page])    
58
    return render_403 unless editable?
57 59
    @page.content = WikiContent.new(:page => @page) if @page.new_record?
58 60
    
59 61
    @content = @page.content_for_version(params[:version])
......
82 84
  
83 85
  # rename a page
84 86
  def rename
85
    @page = @wiki.find_page(params[:page])    
87
    @page = @wiki.find_page(params[:page])
88
	return render_403 unless editable?
86 89
    @page.redirect_existing_links = true
87 90
    # used to display the *original* title if some AR validation errors occur
88 91
    @original_title = @page.pretty_title
......
92 95
    end
93 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 104
  # show page history
96 105
  def history
97 106
    @page = @wiki.find_page(params[:page])
......
122 131
  # remove a wiki page and its history
123 132
  def destroy
124 133
    @page = @wiki.find_page(params[:page])
134
	return render_403 unless editable?
125 135
    @page.destroy if @page
126 136
    redirect_to :action => 'special', :id => @project, :page => 'Page_index'
127 137
  end
......
152 162
  
153 163
  def preview
154 164
    page = @wiki.find_page(params[:page])
165
    return render_403 unless editable?(page)
155 166
    @attachements = page.attachments if page
156 167
    @text = params[:content][:text]
157 168
    render :partial => 'common/preview'
......
159 170

  
160 171
  def add_attachment
161 172
    @page = @wiki.find_page(params[:page])
173
    return render_403 unless editable?
162 174
    attach_files(@page, params[:attachments])
163 175
    redirect_to :action => 'index', :page => @page.title
164 176
  end
165 177

  
166 178
  def destroy_attachment
167 179
    @page = @wiki.find_page(params[:page])
180
    return render_403 unless editable?
168 181
    @page.attachments.find(params[:attachment_id]).destroy
169 182
    redirect_to :action => 'index', :page => @page.title
170 183
  end
......
178 191
  rescue ActiveRecord::RecordNotFound
179 192
    render_404
180 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 199
end
trunk/app/models/wiki_page.rb
105 105
  def text
106 106
    content.text if content
107 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 113
end
109 114

  
110 115
class WikiDiff
trunk/app/views/wiki/show.rhtml
1 1
<div class="contextual">
2
<% if @editable %>
2 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 [email 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 6
<%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :page => @page.title}, :class => 'icon icon-move') if @content.version == @page.content.version %>
4 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 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 10
<%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>
7 11
</div>
8 12

  
......
22 26

  
23 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 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 33
                                             :id => 'attach_files_link' %></p>
30 34
<% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
trunk/db/migrate/093_add_wiki_pages_protected.rb
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
0 10

  
trunk/lib/redmine.rb
76 76
    map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
77 77
    map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :annotate, :special]
78 78
    map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment]
79
    map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
79 80
  end
80 81
    
81 82
  map.project_module :repository do |map|
trunk/test/fixtures/roles.yml
29 29
    - :manage_documents
30 30
    - :view_wiki_pages
31 31
    - :edit_wiki_pages
32
    - :protect_wiki_pages
32 33
    - :delete_wiki_pages
33 34
    - :rename_wiki_pages
34 35
    - :add_messages
......
69 70
    - :manage_documents
70 71
    - :view_wiki_pages
71 72
    - :edit_wiki_pages
73
    - :protect_wiki_pages
72 74
    - :delete_wiki_pages
73 75
    - :add_messages
74 76
    - :manage_boards
trunk/test/fixtures/wiki_pages.yml
4 4
  title: CookBook_documentation
5 5
  id: 1
6 6
  wiki_id: 1
7
  protected: true  
7 8
wiki_pages_002: 
8 9
  created_on: 2007-03-08 00:18:07 +01:00
9 10
  title: Another_page
10 11
  id: 2
11 12
  wiki_id: 1
13
  protected: false
12 14
wiki_pages_003: 
13 15
  created_on: 2007-03-08 00:18:07 +01:00
14 16
  title: Start_page
15 17
  id: 3
16 18
  wiki_id: 2
19
  protected: false
17 20
wiki_pages_004: 
18 21
  created_on: 2007-03-08 00:18:07 +01:00
19 22
  title: Page_with_an_inline_image
20 23
  id: 4
21 24
  wiki_id: 1
25
  protected: false
22 26
  
trunk/test/functional/wiki_controller_test.rb
160 160
    get :index, :id => 999
161 161
    assert_response 404
162 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 219
end

Also available in: Unified diff