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