##// 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
@@ -1,181 +1,199
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'diff'
19 19
20 20 class WikiController < ApplicationController
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
28 28
29 29 # display a page (in editing mode if it doesn't exist)
30 30 def index
31 31 page_title = params[:page]
32 32 @page = @wiki.find_or_new_page(page_title)
33 33 if @page.new_record?
34 34 if User.current.allowed_to?(:edit_wiki_pages, @project)
35 35 edit
36 36 render :action => 'edit'
37 37 else
38 38 render_404
39 39 end
40 40 return
41 41 end
42 42 @content = @page.content_for_version(params[:version])
43 43 if params[:export] == 'html'
44 44 export = render_to_string :action => 'export', :layout => false
45 45 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
46 46 return
47 47 elsif params[:export] == 'txt'
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])
60 62 @content.text = "h1. #{@page.pretty_title}" if @content.text.blank?
61 63 # don't keep previous comment
62 64 @content.comments = nil
63 65 if request.post?
64 66 if !@page.new_record? && @content.text == params[:content][:text]
65 67 # don't save if text wasn't changed
66 68 redirect_to :action => 'index', :id => @project, :page => @page.title
67 69 return
68 70 end
69 71 #@content.text = params[:content][:text]
70 72 #@content.comments = params[:content][:comments]
71 73 @content.attributes = params[:content]
72 74 @content.author = User.current
73 75 # if page is new @page.save will also save content, but not if page isn't a new record
74 76 if (@page.new_record? ? @page.save : @content.save)
75 77 redirect_to :action => 'index', :id => @project, :page => @page.title
76 78 end
77 79 end
78 80 rescue ActiveRecord::StaleObjectError
79 81 # Optimistic locking exception
80 82 flash[:error] = l(:notice_locking_conflict)
81 83 end
82 84
83 85 # rename a page
84 86 def rename
85 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
89 92 if request.post? && @page.update_attributes(params[:wiki_page])
90 93 flash[:notice] = l(:notice_successful_update)
91 94 redirect_to :action => 'index', :id => @project, :page => @page.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])
98 107
99 108 @version_count = @page.content.versions.count
100 109 @version_pages = Paginator.new self, @version_count, per_page_option, params['p']
101 110 # don't load text
102 111 @versions = @page.content.versions.find :all,
103 112 :select => "id, author_id, comments, updated_on, version",
104 113 :order => 'version DESC',
105 114 :limit => @version_pages.items_per_page + 1,
106 115 :offset => @version_pages.current.offset
107 116
108 117 render :layout => false if request.xhr?
109 118 end
110 119
111 120 def diff
112 121 @page = @wiki.find_page(params[:page])
113 122 @diff = @page.diff(params[:version], params[:version_from])
114 123 render_404 unless @diff
115 124 end
116 125
117 126 def annotate
118 127 @page = @wiki.find_page(params[:page])
119 128 @annotate = @page.annotate(params[:version])
120 129 end
121 130
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
128 138
129 139 # display special pages
130 140 def special
131 141 page_title = params[:page].downcase
132 142 case page_title
133 143 # show pages index, sorted by title
134 144 when 'page_index', 'date_index'
135 145 # eager load information about last updates, without loading text
136 146 @pages = @wiki.pages.find :all, :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
137 147 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
138 148 :order => 'title'
139 149 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
140 150 # export wiki to a single html file
141 151 when 'export'
142 152 @pages = @wiki.pages.find :all, :order => 'title'
143 153 export = render_to_string :action => 'export_multiple', :layout => false
144 154 send_data(export, :type => 'text/html', :filename => "wiki.html")
145 155 return
146 156 else
147 157 # requested special page doesn't exist, redirect to default page
148 158 redirect_to :action => 'index', :id => @project, :page => nil and return
149 159 end
150 160 render :action => "special_#{page_title}"
151 161 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'
158 169 end
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
171 184
172 185 private
173 186
174 187 def find_wiki
175 188 @project = Project.find(params[:id])
176 189 @wiki = @project.wiki
177 190 render_404 unless @wiki
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
@@ -1,160 +1,165
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'diff'
19 19 require 'enumerator'
20 20
21 21 class WikiPage < ActiveRecord::Base
22 22 belongs_to :wiki
23 23 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
24 24 has_many :attachments, :as => :container, :dependent => :destroy
25 25
26 26 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
27 27 :description => :text,
28 28 :datetime => :created_on,
29 29 :url => Proc.new {|o| {:controller => 'wiki', :id => o.wiki.project_id, :page => o.title}}
30 30
31 31 acts_as_searchable :columns => ['title', 'text'],
32 32 :include => [:wiki, :content],
33 33 :project_key => "#{Wiki.table_name}.project_id"
34 34
35 35 attr_accessor :redirect_existing_links
36 36
37 37 validates_presence_of :title
38 38 validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/
39 39 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
40 40 validates_associated :content
41 41
42 42 def title=(value)
43 43 value = Wiki.titleize(value)
44 44 @previous_title = read_attribute(:title) if @previous_title.blank?
45 45 write_attribute(:title, value)
46 46 end
47 47
48 48 def before_save
49 49 self.title = Wiki.titleize(title)
50 50 # Manage redirects if the title has changed
51 51 if !@previous_title.blank? && (@previous_title != title) && !new_record?
52 52 # Update redirects that point to the old title
53 53 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
54 54 r.redirects_to = title
55 55 r.title == r.redirects_to ? r.destroy : r.save
56 56 end
57 57 # Remove redirects for the new title
58 58 wiki.redirects.find_all_by_title(title).each(&:destroy)
59 59 # Create a redirect to the new title
60 60 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
61 61 @previous_title = nil
62 62 end
63 63 end
64 64
65 65 def before_destroy
66 66 # Remove redirects to this page
67 67 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
68 68 end
69 69
70 70 def pretty_title
71 71 WikiPage.pretty_title(title)
72 72 end
73 73
74 74 def content_for_version(version=nil)
75 75 result = content.versions.find_by_version(version.to_i) if version
76 76 result ||= content
77 77 result
78 78 end
79 79
80 80 def diff(version_to=nil, version_from=nil)
81 81 version_to = version_to ? version_to.to_i : self.content.version
82 82 version_from = version_from ? version_from.to_i : version_to - 1
83 83 version_to, version_from = version_from, version_to unless version_from < version_to
84 84
85 85 content_to = content.versions.find_by_version(version_to)
86 86 content_from = content.versions.find_by_version(version_from)
87 87
88 88 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
89 89 end
90 90
91 91 def annotate(version=nil)
92 92 version = version ? version.to_i : self.content.version
93 93 c = content.versions.find_by_version(version)
94 94 c ? WikiAnnotate.new(c) : nil
95 95 end
96 96
97 97 def self.pretty_title(str)
98 98 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
99 99 end
100 100
101 101 def project
102 102 wiki.project
103 103 end
104 104
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
111 116 attr_reader :diff, :words, :content_to, :content_from
112 117
113 118 def initialize(content_to, content_from)
114 119 @content_to = content_to
115 120 @content_from = content_from
116 121 @words = content_to.text.split(/(\s+)/)
117 122 @words = @words.select {|word| word != ' '}
118 123 words_from = content_from.text.split(/(\s+)/)
119 124 words_from = words_from.select {|word| word != ' '}
120 125 @diff = words_from.diff @words
121 126 end
122 127 end
123 128
124 129 class WikiAnnotate
125 130 attr_reader :lines, :content
126 131
127 132 def initialize(content)
128 133 @content = content
129 134 current = content
130 135 current_lines = current.text.split(/\r?\n/)
131 136 @lines = current_lines.collect {|t| [nil, nil, t]}
132 137 positions = []
133 138 current_lines.size.times {|i| positions << i}
134 139 while (current.previous)
135 140 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
136 141 d.each_slice(3) do |s|
137 142 sign, line = s[0], s[1]
138 143 if sign == '+' && positions[line] && positions[line] != -1
139 144 if @lines[positions[line]][0].nil?
140 145 @lines[positions[line]][0] = current.version
141 146 @lines[positions[line]][1] = current.author
142 147 end
143 148 end
144 149 end
145 150 d.each_slice(3) do |s|
146 151 sign, line = s[0], s[1]
147 152 if sign == '-'
148 153 positions.insert(line, -1)
149 154 else
150 155 positions[line] = nil
151 156 end
152 157 end
153 158 positions.compact!
154 159 # Stop if every line is annotated
155 160 break unless @lines.detect { |line| line[0].nil? }
156 161 current = current.previous
157 162 end
158 163 @lines.each { |line| line[0] ||= current.version }
159 164 end
160 165 end
@@ -1,53 +1,57
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 !@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 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
9 13 <% if @content.version != @page.content.version %>
10 14 <p>
11 15 <%= link_to(('&#171; ' + l(:label_previous)), :action => 'index', :page => @page.title, :version => (@content.version - 1)) + " - " if @content.version > 1 %>
12 16 <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %>
13 17 <%= '(' + link_to('diff', :controller => 'wiki', :action => 'diff', :page => @page.title, :version => @content.version) + ')' if @content.version > 1 %> -
14 18 <%= link_to((l(:label_next) + ' &#187;'), :action => 'index', :page => @page.title, :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %>
15 19 <%= link_to(l(:label_current_version), :action => 'index', :page => @page.title) %>
16 20 <br />
17 21 <em><%= @content.author ? @content.author.name : "anonyme" %>, <%= format_time(@content.updated_on) %> </em><br />
18 22 <%=h @content.comments %>
19 23 </p>
20 24 <hr />
21 25 <% end %>
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 %>
31 35 <div class="box">
32 36 <p><%= render :partial => 'attachments/form' %></p>
33 37 </div>
34 38 <%= submit_tag l(:button_add) %>
35 39 <%= link_to l(:button_cancel), {}, :onclick => "Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;" %>
36 40 <% end %>
37 41 <% end %>
38 42
39 43 <p class="other-formats">
40 44 <%= l(:label_export_to) %>
41 45 <span><%= link_to 'HTML', {:page => @page.title, :export => 'html', :version => @content.version}, :class => 'html' %></span>
42 46 <span><%= link_to 'TXT', {:page => @page.title, :export => 'txt', :version => @content.version}, :class => 'text' %></span>
43 47 </p>
44 48
45 49 <% content_for :header_tags do %>
46 50 <%= stylesheet_link_tag 'scm' %>
47 51 <% end %>
48 52
49 53 <% content_for :sidebar do %>
50 54 <%= render :partial => 'sidebar' %>
51 55 <% end %>
52 56
53 57 <% html_title @page.pretty_title %>
@@ -1,133 +1,134
1 1 require 'redmine/access_control'
2 2 require 'redmine/menu_manager'
3 3 require 'redmine/mime_type'
4 4 require 'redmine/core_ext'
5 5 require 'redmine/themes'
6 6 require 'redmine/plugin'
7 7
8 8 begin
9 9 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
10 10 rescue LoadError
11 11 # RMagick is not available
12 12 end
13 13
14 14 REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git )
15 15
16 16 # Permissions
17 17 Redmine::AccessControl.map do |map|
18 18 map.permission :view_project, {:projects => [:show, :activity]}, :public => true
19 19 map.permission :search_project, {:search => :index}, :public => true
20 20 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
21 21 map.permission :select_project_modules, {:projects => :modules}, :require => :member
22 22 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy]}, :require => :member
23 23 map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member
24 24
25 25 map.project_module :issue_tracking do |map|
26 26 # Issue categories
27 27 map.permission :manage_categories, {:projects => [:settings, :add_issue_category], :issue_categories => [:edit, :destroy]}, :require => :member
28 28 # Issues
29 29 map.permission :view_issues, {:projects => [:changelog, :roadmap],
30 30 :issues => [:index, :changes, :show, :context_menu],
31 31 :versions => [:show, :status_by],
32 32 :queries => :index,
33 33 :reports => :issue_report}, :public => true
34 34 map.permission :add_issues, {:issues => :new}
35 35 map.permission :edit_issues, {:issues => [:edit, :bulk_edit, :destroy_attachment]}
36 36 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
37 37 map.permission :add_issue_notes, {:issues => :edit}
38 38 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
39 39 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
40 40 map.permission :move_issues, {:issues => :move}, :require => :loggedin
41 41 map.permission :delete_issues, {:issues => :destroy}, :require => :member
42 42 # Queries
43 43 map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
44 44 map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
45 45 # Gantt & calendar
46 46 map.permission :view_gantt, :projects => :gantt
47 47 map.permission :view_calendar, :projects => :calendar
48 48 end
49 49
50 50 map.project_module :time_tracking do |map|
51 51 map.permission :log_time, {:timelog => :edit}, :require => :loggedin
52 52 map.permission :view_time_entries, :timelog => [:details, :report]
53 53 map.permission :edit_time_entries, {:timelog => [:edit, :destroy]}, :require => :member
54 54 map.permission :edit_own_time_entries, {:timelog => [:edit, :destroy]}, :require => :loggedin
55 55 end
56 56
57 57 map.project_module :news do |map|
58 58 map.permission :manage_news, {:news => [:new, :edit, :destroy, :destroy_comment]}, :require => :member
59 59 map.permission :view_news, {:news => [:index, :show]}, :public => true
60 60 map.permission :comment_news, {:news => :add_comment}
61 61 end
62 62
63 63 map.project_module :documents do |map|
64 64 map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment, :destroy_attachment]}, :require => :loggedin
65 65 map.permission :view_documents, :documents => [:index, :show, :download]
66 66 end
67 67
68 68 map.project_module :files do |map|
69 69 map.permission :manage_files, {:projects => :add_file, :versions => :destroy_file}, :require => :loggedin
70 70 map.permission :view_files, :projects => :list_files, :versions => :download
71 71 end
72 72
73 73 map.project_module :wiki do |map|
74 74 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
75 75 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
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|
82 83 map.permission :manage_repository, {:repositories => [:edit, :destroy]}, :require => :member
83 84 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph]
84 85 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
85 86 end
86 87
87 88 map.project_module :boards do |map|
88 89 map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
89 90 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
90 91 map.permission :add_messages, {:messages => [:new, :reply]}
91 92 map.permission :edit_messages, {:messages => :edit}, :require => :member
92 93 map.permission :delete_messages, {:messages => :destroy}, :require => :member
93 94 end
94 95 end
95 96
96 97 Redmine::MenuManager.map :top_menu do |menu|
97 98 menu.push :home, :home_path, :html => { :class => 'home' }
98 99 menu.push :my_page, { :controller => 'my', :action => 'page' }, :html => { :class => 'mypage' }, :if => Proc.new { User.current.logged? }
99 100 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural, :html => { :class => 'projects' }
100 101 menu.push :administration, { :controller => 'admin', :action => 'index' }, :html => { :class => 'admin' }, :if => Proc.new { User.current.admin? }
101 102 menu.push :help, Redmine::Info.help_url, :html => { :class => 'help' }
102 103 end
103 104
104 105 Redmine::MenuManager.map :account_menu do |menu|
105 106 menu.push :login, :signin_path, :html => { :class => 'login' }, :if => Proc.new { !User.current.logged? }
106 107 menu.push :register, { :controller => 'account', :action => 'register' }, :html => { :class => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
107 108 menu.push :my_account, { :controller => 'my', :action => 'account' }, :html => { :class => 'myaccount' }, :if => Proc.new { User.current.logged? }
108 109 menu.push :logout, :signout_path, :html => { :class => 'logout' }, :if => Proc.new { User.current.logged? }
109 110 end
110 111
111 112 Redmine::MenuManager.map :application_menu do |menu|
112 113 # Empty
113 114 end
114 115
115 116 Redmine::MenuManager.map :project_menu do |menu|
116 117 menu.push :overview, { :controller => 'projects', :action => 'show' }
117 118 menu.push :activity, { :controller => 'projects', :action => 'activity' }
118 119 menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' },
119 120 :if => Proc.new { |p| p.versions.any? }
120 121 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
121 122 menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
122 123 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
123 124 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
124 125 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
125 126 menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil },
126 127 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
127 128 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
128 129 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
129 130 menu.push :files, { :controller => 'projects', :action => 'list_files' }, :caption => :label_attachment_plural
130 131 menu.push :repository, { :controller => 'repositories', :action => 'show' },
131 132 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
132 133 menu.push :settings, { :controller => 'projects', :action => 'settings' }
133 134 end
1 NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file, binary diff hidden
@@ -1,161 +1,163
1 1 ---
2 2 roles_001:
3 3 name: Manager
4 4 id: 1
5 5 builtin: 0
6 6 permissions: |
7 7 ---
8 8 - :edit_project
9 9 - :manage_members
10 10 - :manage_versions
11 11 - :manage_categories
12 12 - :add_issues
13 13 - :edit_issues
14 14 - :manage_issue_relations
15 15 - :add_issue_notes
16 16 - :move_issues
17 17 - :delete_issues
18 18 - :manage_public_queries
19 19 - :save_queries
20 20 - :view_gantt
21 21 - :view_calendar
22 22 - :log_time
23 23 - :view_time_entries
24 24 - :edit_time_entries
25 25 - :delete_time_entries
26 26 - :manage_news
27 27 - :comment_news
28 28 - :view_documents
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
35 36 - :edit_messages
36 37 - :delete_messages
37 38 - :manage_boards
38 39 - :view_files
39 40 - :manage_files
40 41 - :browse_repository
41 42 - :view_changesets
42 43
43 44 position: 1
44 45 roles_002:
45 46 name: Developer
46 47 id: 2
47 48 builtin: 0
48 49 permissions: |
49 50 ---
50 51 - :edit_project
51 52 - :manage_members
52 53 - :manage_versions
53 54 - :manage_categories
54 55 - :add_issues
55 56 - :edit_issues
56 57 - :manage_issue_relations
57 58 - :add_issue_notes
58 59 - :move_issues
59 60 - :delete_issues
60 61 - :save_queries
61 62 - :view_gantt
62 63 - :view_calendar
63 64 - :log_time
64 65 - :view_time_entries
65 66 - :edit_own_time_entries
66 67 - :manage_news
67 68 - :comment_news
68 69 - :view_documents
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
75 77 - :view_files
76 78 - :manage_files
77 79 - :browse_repository
78 80 - :view_changesets
79 81
80 82 position: 2
81 83 roles_003:
82 84 name: Reporter
83 85 id: 3
84 86 builtin: 0
85 87 permissions: |
86 88 ---
87 89 - :edit_project
88 90 - :manage_members
89 91 - :manage_versions
90 92 - :manage_categories
91 93 - :add_issues
92 94 - :edit_issues
93 95 - :manage_issue_relations
94 96 - :add_issue_notes
95 97 - :move_issues
96 98 - :save_queries
97 99 - :view_gantt
98 100 - :view_calendar
99 101 - :log_time
100 102 - :view_time_entries
101 103 - :manage_news
102 104 - :comment_news
103 105 - :view_documents
104 106 - :manage_documents
105 107 - :view_wiki_pages
106 108 - :edit_wiki_pages
107 109 - :delete_wiki_pages
108 110 - :add_messages
109 111 - :manage_boards
110 112 - :view_files
111 113 - :manage_files
112 114 - :browse_repository
113 115 - :view_changesets
114 116
115 117 position: 3
116 118 roles_004:
117 119 name: Non member
118 120 id: 4
119 121 builtin: 1
120 122 permissions: |
121 123 ---
122 124 - :add_issues
123 125 - :edit_issues
124 126 - :manage_issue_relations
125 127 - :add_issue_notes
126 128 - :move_issues
127 129 - :save_queries
128 130 - :view_gantt
129 131 - :view_calendar
130 132 - :log_time
131 133 - :view_time_entries
132 134 - :comment_news
133 135 - :view_documents
134 136 - :manage_documents
135 137 - :view_wiki_pages
136 138 - :edit_wiki_pages
137 139 - :add_messages
138 140 - :view_files
139 141 - :manage_files
140 142 - :browse_repository
141 143 - :view_changesets
142 144
143 145 position: 4
144 146 roles_005:
145 147 name: Anonymous
146 148 id: 5
147 149 builtin: 2
148 150 permissions: |
149 151 ---
150 152 - :add_issue_notes
151 153 - :view_gantt
152 154 - :view_calendar
153 155 - :view_time_entries
154 156 - :view_documents
155 157 - :view_wiki_pages
156 158 - :view_files
157 159 - :browse_repository
158 160 - :view_changesets
159 161
160 162 position: 5
161 163 No newline at end of file
@@ -1,22 +1,26
1 1 ---
2 2 wiki_pages_001:
3 3 created_on: 2007-03-07 00:08:07 +01:00
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 No newline at end of file
@@ -1,163 +1,219
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19 require 'wiki_controller'
20 20
21 21 # Re-raise errors caught by the controller.
22 22 class WikiController; def rescue_action(e) raise e end; end
23 23
24 24 class WikiControllerTest < Test::Unit::TestCase
25 25 fixtures :projects, :users, :roles, :members, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :attachments
26 26
27 27 def setup
28 28 @controller = WikiController.new
29 29 @request = ActionController::TestRequest.new
30 30 @response = ActionController::TestResponse.new
31 31 User.current = nil
32 32 end
33 33
34 34 def test_show_start_page
35 35 get :index, :id => 1
36 36 assert_response :success
37 37 assert_template 'show'
38 38 assert_tag :tag => 'h1', :content => /CookBook documentation/
39 39 end
40 40
41 41 def test_show_page_with_name
42 42 get :index, :id => 1, :page => 'Another_page'
43 43 assert_response :success
44 44 assert_template 'show'
45 45 assert_tag :tag => 'h1', :content => /Another page/
46 46 # Included page with an inline image
47 47 assert_tag :tag => 'p', :content => /This is an inline image/
48 48 assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3',
49 49 :alt => 'This is a logo' }
50 50 end
51 51
52 52 def test_show_unexistent_page_without_edit_right
53 53 get :index, :id => 1, :page => 'Unexistent page'
54 54 assert_response 404
55 55 end
56 56
57 57 def test_show_unexistent_page_with_edit_right
58 58 @request.session[:user_id] = 2
59 59 get :index, :id => 1, :page => 'Unexistent page'
60 60 assert_response :success
61 61 assert_template 'edit'
62 62 end
63 63
64 64 def test_create_page
65 65 @request.session[:user_id] = 2
66 66 post :edit, :id => 1,
67 67 :page => 'New page',
68 68 :content => {:comments => 'Created the page',
69 69 :text => "h1. New page\n\nThis is a new page",
70 70 :version => 0}
71 71 assert_redirected_to 'wiki/ecookbook/New_page'
72 72 page = Project.find(1).wiki.find_page('New page')
73 73 assert !page.new_record?
74 74 assert_not_nil page.content
75 75 assert_equal 'Created the page', page.content.comments
76 76 end
77 77
78 78 def test_preview
79 79 @request.session[:user_id] = 2
80 80 xhr :post, :preview, :id => 1, :page => 'CookBook_documentation',
81 81 :content => { :comments => '',
82 82 :text => 'this is a *previewed text*',
83 83 :version => 3 }
84 84 assert_response :success
85 85 assert_template 'common/_preview'
86 86 assert_tag :tag => 'strong', :content => /previewed text/
87 87 end
88 88
89 89 def test_history
90 90 get :history, :id => 1, :page => 'CookBook_documentation'
91 91 assert_response :success
92 92 assert_template 'history'
93 93 assert_not_nil assigns(:versions)
94 94 assert_equal 3, assigns(:versions).size
95 95 end
96 96
97 97 def test_diff
98 98 get :diff, :id => 1, :page => 'CookBook_documentation', :version => 2, :version_from => 1
99 99 assert_response :success
100 100 assert_template 'diff'
101 101 assert_tag :tag => 'span', :attributes => { :class => 'diff_in'},
102 102 :content => /updated/
103 103 end
104 104
105 105 def test_annotate
106 106 get :annotate, :id => 1, :page => 'CookBook_documentation', :version => 2
107 107 assert_response :success
108 108 assert_template 'annotate'
109 109 # Line 1
110 110 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1' },
111 111 :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/ },
112 112 :child => { :tag => 'td', :content => /h1\. CookBook documentation/ }
113 113 # Line 2
114 114 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '2' },
115 115 :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/ },
116 116 :child => { :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ }
117 117 end
118 118
119 119 def test_rename_with_redirect
120 120 @request.session[:user_id] = 2
121 121 post :rename, :id => 1, :page => 'Another_page',
122 122 :wiki_page => { :title => 'Another renamed page',
123 123 :redirect_existing_links => 1 }
124 124 assert_redirected_to 'wiki/ecookbook/Another_renamed_page'
125 125 wiki = Project.find(1).wiki
126 126 # Check redirects
127 127 assert_not_nil wiki.find_page('Another page')
128 128 assert_nil wiki.find_page('Another page', :with_redirect => false)
129 129 end
130 130
131 131 def test_rename_without_redirect
132 132 @request.session[:user_id] = 2
133 133 post :rename, :id => 1, :page => 'Another_page',
134 134 :wiki_page => { :title => 'Another renamed page',
135 135 :redirect_existing_links => "0" }
136 136 assert_redirected_to 'wiki/ecookbook/Another_renamed_page'
137 137 wiki = Project.find(1).wiki
138 138 # Check that there's no redirects
139 139 assert_nil wiki.find_page('Another page')
140 140 end
141 141
142 142 def test_destroy
143 143 @request.session[:user_id] = 2
144 144 post :destroy, :id => 1, :page => 'CookBook_documentation'
145 145 assert_redirected_to 'wiki/ecookbook/Page_index/special'
146 146 end
147 147
148 148 def test_page_index
149 149 get :special, :id => 'ecookbook', :page => 'Page_index'
150 150 assert_response :success
151 151 assert_template 'special_page_index'
152 152 pages = assigns(:pages)
153 153 assert_not_nil pages
154 154 assert_equal Project.find(1).wiki.pages.size, pages.size
155 155 assert_tag :tag => 'a', :attributes => { :href => '/wiki/ecookbook/CookBook_documentation' },
156 156 :content => /CookBook documentation/
157 157 end
158 158
159 159 def test_not_found
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
General Comments 0
You need to be logged in to leave comments. Login now