##// END OF EJS Templates
Ability to edit a wiki page's parent on the edit page (#6449)....
Jean-Philippe Lang -
r8667:001b255b081b
parent child
Show More
@@ -1,320 +1,319
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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 # The WikiController follows the Rails REST controller pattern but with
20 # The WikiController follows the Rails REST controller pattern but with
21 # a few differences
21 # a few differences
22 #
22 #
23 # * index - shows a list of WikiPages grouped by page or date
23 # * index - shows a list of WikiPages grouped by page or date
24 # * new - not used
24 # * new - not used
25 # * create - not used
25 # * create - not used
26 # * show - will also show the form for creating a new wiki page
26 # * show - will also show the form for creating a new wiki page
27 # * edit - used to edit an existing or new page
27 # * edit - used to edit an existing or new page
28 # * update - used to save a wiki page update to the database, including new pages
28 # * update - used to save a wiki page update to the database, including new pages
29 # * destroy - normal
29 # * destroy - normal
30 #
30 #
31 # Other member and collection methods are also used
31 # Other member and collection methods are also used
32 #
32 #
33 # TODO: still being worked on
33 # TODO: still being worked on
34 class WikiController < ApplicationController
34 class WikiController < ApplicationController
35 default_search_scope :wiki_pages
35 default_search_scope :wiki_pages
36 before_filter :find_wiki, :authorize
36 before_filter :find_wiki, :authorize
37 before_filter :find_existing_or_new_page, :only => [:show, :edit, :update]
37 before_filter :find_existing_or_new_page, :only => [:show, :edit, :update]
38 before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
38 before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
39
39
40 helper :attachments
40 helper :attachments
41 include AttachmentsHelper
41 include AttachmentsHelper
42 helper :watchers
42 helper :watchers
43 include Redmine::Export::PDF
43 include Redmine::Export::PDF
44
44
45 # List of pages, sorted alphabetically and by parent (hierarchy)
45 # List of pages, sorted alphabetically and by parent (hierarchy)
46 def index
46 def index
47 load_pages_for_index
47 load_pages_for_index
48 @pages_by_parent_id = @pages.group_by(&:parent_id)
48 @pages_by_parent_id = @pages.group_by(&:parent_id)
49 end
49 end
50
50
51 # List of page, by last update
51 # List of page, by last update
52 def date_index
52 def date_index
53 load_pages_for_index
53 load_pages_for_index
54 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
54 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
55 end
55 end
56
56
57 # display a page (in editing mode if it doesn't exist)
57 # display a page (in editing mode if it doesn't exist)
58 def show
58 def show
59 if @page.new_record?
59 if @page.new_record?
60 if User.current.allowed_to?(:edit_wiki_pages, @project) && editable?
60 if User.current.allowed_to?(:edit_wiki_pages, @project) && editable?
61 edit
61 edit
62 render :action => 'edit'
62 render :action => 'edit'
63 else
63 else
64 render_404
64 render_404
65 end
65 end
66 return
66 return
67 end
67 end
68 if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
68 if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
69 # Redirects user to the current version if he's not allowed to view previous versions
69 # Redirects user to the current version if he's not allowed to view previous versions
70 redirect_to :version => nil
70 redirect_to :version => nil
71 return
71 return
72 end
72 end
73 @content = @page.content_for_version(params[:version])
73 @content = @page.content_for_version(params[:version])
74 if User.current.allowed_to?(:export_wiki_pages, @project)
74 if User.current.allowed_to?(:export_wiki_pages, @project)
75 if params[:format] == 'pdf'
75 if params[:format] == 'pdf'
76 send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
76 send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
77 return
77 return
78 elsif params[:format] == 'html'
78 elsif params[:format] == 'html'
79 export = render_to_string :action => 'export', :layout => false
79 export = render_to_string :action => 'export', :layout => false
80 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
80 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
81 return
81 return
82 elsif params[:format] == 'txt'
82 elsif params[:format] == 'txt'
83 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
83 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
84 return
84 return
85 end
85 end
86 end
86 end
87 @editable = editable?
87 @editable = editable?
88 @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) &&
88 @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) &&
89 @content.current_version? &&
89 @content.current_version? &&
90 Redmine::WikiFormatting.supports_section_edit?
90 Redmine::WikiFormatting.supports_section_edit?
91
91
92 render :action => 'show'
92 render :action => 'show'
93 end
93 end
94
94
95 # edit an existing page or a new one
95 # edit an existing page or a new one
96 def edit
96 def edit
97 return render_403 unless editable?
97 return render_403 unless editable?
98 if @page.new_record?
98 if @page.new_record?
99 @page.content = WikiContent.new(:page => @page)
99 @page.content = WikiContent.new(:page => @page)
100 if params[:parent].present?
100 if params[:parent].present?
101 @page.parent = @page.wiki.find_page(params[:parent].to_s)
101 @page.parent = @page.wiki.find_page(params[:parent].to_s)
102 end
102 end
103 end
103 end
104
104
105 @content = @page.content_for_version(params[:version])
105 @content = @page.content_for_version(params[:version])
106 @content.text = initial_page_content(@page) if @content.text.blank?
106 @content.text = initial_page_content(@page) if @content.text.blank?
107 # don't keep previous comment
107 # don't keep previous comment
108 @content.comments = nil
108 @content.comments = nil
109
109
110 # To prevent StaleObjectError exception when reverting to a previous version
110 # To prevent StaleObjectError exception when reverting to a previous version
111 @content.version = @page.content.version
111 @content.version = @page.content.version
112
112
113 @text = @content.text
113 @text = @content.text
114 if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
114 if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
115 @section = params[:section].to_i
115 @section = params[:section].to_i
116 @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section)
116 @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section)
117 render_404 if @text.blank?
117 render_404 if @text.blank?
118 end
118 end
119 end
119 end
120
120
121 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
121 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
122 # Creates a new page or updates an existing one
122 # Creates a new page or updates an existing one
123 def update
123 def update
124 return render_403 unless editable?
124 return render_403 unless editable?
125 @page.content = WikiContent.new(:page => @page) if @page.new_record?
125 @page.content = WikiContent.new(:page => @page) if @page.new_record?
126 @page.safe_attributes = params[:wiki_page]
126
127
127 @content = @page.content_for_version(params[:version])
128 @content = @page.content_for_version(params[:version])
128 @content.text = initial_page_content(@page) if @content.text.blank?
129 @content.text = initial_page_content(@page) if @content.text.blank?
129 # don't keep previous comment
130 # don't keep previous comment
130 @content.comments = nil
131 @content.comments = nil
131
132
132 if !@page.new_record? && params[:content].present? && @content.text == params[:content][:text]
133 if !@page.new_record? && params[:content].present? && @content.text == params[:content][:text]
133 attachments = Attachment.attach_files(@page, params[:attachments])
134 attachments = Attachment.attach_files(@page, params[:attachments])
134 render_attachment_warning_if_needed(@page)
135 render_attachment_warning_if_needed(@page)
135 # don't save if text wasn't changed
136 # don't save content if text wasn't changed
137 @page.save
136 redirect_to :action => 'show', :project_id => @project, :id => @page.title
138 redirect_to :action => 'show', :project_id => @project, :id => @page.title
137 return
139 return
138 end
140 end
139
141
140 @content.comments = params[:content][:comments]
142 @content.comments = params[:content][:comments]
141 @text = params[:content][:text]
143 @text = params[:content][:text]
142 if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
144 if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
143 @section = params[:section].to_i
145 @section = params[:section].to_i
144 @section_hash = params[:section_hash]
146 @section_hash = params[:section_hash]
145 @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash)
147 @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash)
146 else
148 else
147 @content.version = params[:content][:version]
149 @content.version = params[:content][:version]
148 @content.text = @text
150 @content.text = @text
149 end
151 end
150 @content.author = User.current
152 @content.author = User.current
151 if @page.new_record? && params[:page]
153 @page.content = @content
152 @page.parent_id = params[:page][:parent_id]
154 if @page.save
153 end
154 # if page is new @page.save will also save content, but not if page isn't a new record
155 if (@page.new_record? ? @page.save : @content.save)
156 attachments = Attachment.attach_files(@page, params[:attachments])
155 attachments = Attachment.attach_files(@page, params[:attachments])
157 render_attachment_warning_if_needed(@page)
156 render_attachment_warning_if_needed(@page)
158 call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
157 call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
159 redirect_to :action => 'show', :project_id => @project, :id => @page.title
158 redirect_to :action => 'show', :project_id => @project, :id => @page.title
160 else
159 else
161 render :action => 'edit'
160 render :action => 'edit'
162 end
161 end
163
162
164 rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError
163 rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError
165 # Optimistic locking exception
164 # Optimistic locking exception
166 flash.now[:error] = l(:notice_locking_conflict)
165 flash.now[:error] = l(:notice_locking_conflict)
167 render :action => 'edit'
166 render :action => 'edit'
168 end
167 end
169
168
170 # rename a page
169 # rename a page
171 def rename
170 def rename
172 return render_403 unless editable?
171 return render_403 unless editable?
173 @page.redirect_existing_links = true
172 @page.redirect_existing_links = true
174 # used to display the *original* title if some AR validation errors occur
173 # used to display the *original* title if some AR validation errors occur
175 @original_title = @page.pretty_title
174 @original_title = @page.pretty_title
176 if request.post? && @page.update_attributes(params[:wiki_page])
175 if request.post? && @page.update_attributes(params[:wiki_page])
177 flash[:notice] = l(:notice_successful_update)
176 flash[:notice] = l(:notice_successful_update)
178 redirect_to :action => 'show', :project_id => @project, :id => @page.title
177 redirect_to :action => 'show', :project_id => @project, :id => @page.title
179 end
178 end
180 end
179 end
181
180
182 verify :method => :post, :only => :protect, :redirect_to => { :action => :show }
181 verify :method => :post, :only => :protect, :redirect_to => { :action => :show }
183 def protect
182 def protect
184 @page.update_attribute :protected, params[:protected]
183 @page.update_attribute :protected, params[:protected]
185 redirect_to :action => 'show', :project_id => @project, :id => @page.title
184 redirect_to :action => 'show', :project_id => @project, :id => @page.title
186 end
185 end
187
186
188 # show page history
187 # show page history
189 def history
188 def history
190 @version_count = @page.content.versions.count
189 @version_count = @page.content.versions.count
191 @version_pages = Paginator.new self, @version_count, per_page_option, params['p']
190 @version_pages = Paginator.new self, @version_count, per_page_option, params['p']
192 # don't load text
191 # don't load text
193 @versions = @page.content.versions.find :all,
192 @versions = @page.content.versions.find :all,
194 :select => "id, author_id, comments, updated_on, version",
193 :select => "id, author_id, comments, updated_on, version",
195 :order => 'version DESC',
194 :order => 'version DESC',
196 :limit => @version_pages.items_per_page + 1,
195 :limit => @version_pages.items_per_page + 1,
197 :offset => @version_pages.current.offset
196 :offset => @version_pages.current.offset
198
197
199 render :layout => false if request.xhr?
198 render :layout => false if request.xhr?
200 end
199 end
201
200
202 def diff
201 def diff
203 @diff = @page.diff(params[:version], params[:version_from])
202 @diff = @page.diff(params[:version], params[:version_from])
204 render_404 unless @diff
203 render_404 unless @diff
205 end
204 end
206
205
207 def annotate
206 def annotate
208 @annotate = @page.annotate(params[:version])
207 @annotate = @page.annotate(params[:version])
209 render_404 unless @annotate
208 render_404 unless @annotate
210 end
209 end
211
210
212 verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show }
211 verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show }
213 # Removes a wiki page and its history
212 # Removes a wiki page and its history
214 # Children can be either set as root pages, removed or reassigned to another parent page
213 # Children can be either set as root pages, removed or reassigned to another parent page
215 def destroy
214 def destroy
216 return render_403 unless editable?
215 return render_403 unless editable?
217
216
218 @descendants_count = @page.descendants.size
217 @descendants_count = @page.descendants.size
219 if @descendants_count > 0
218 if @descendants_count > 0
220 case params[:todo]
219 case params[:todo]
221 when 'nullify'
220 when 'nullify'
222 # Nothing to do
221 # Nothing to do
223 when 'destroy'
222 when 'destroy'
224 # Removes all its descendants
223 # Removes all its descendants
225 @page.descendants.each(&:destroy)
224 @page.descendants.each(&:destroy)
226 when 'reassign'
225 when 'reassign'
227 # Reassign children to another parent page
226 # Reassign children to another parent page
228 reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
227 reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
229 return unless reassign_to
228 return unless reassign_to
230 @page.children.each do |child|
229 @page.children.each do |child|
231 child.update_attribute(:parent, reassign_to)
230 child.update_attribute(:parent, reassign_to)
232 end
231 end
233 else
232 else
234 @reassignable_to = @wiki.pages - @page.self_and_descendants
233 @reassignable_to = @wiki.pages - @page.self_and_descendants
235 return
234 return
236 end
235 end
237 end
236 end
238 @page.destroy
237 @page.destroy
239 redirect_to :action => 'index', :project_id => @project
238 redirect_to :action => 'index', :project_id => @project
240 end
239 end
241
240
242 # Export wiki to a single pdf or html file
241 # Export wiki to a single pdf or html file
243 def export
242 def export
244 @pages = @wiki.pages.all(:order => 'title', :include => [:content, :attachments], :limit => 75)
243 @pages = @wiki.pages.all(:order => 'title', :include => [:content, :attachments], :limit => 75)
245 respond_to do |format|
244 respond_to do |format|
246 format.html {
245 format.html {
247 export = render_to_string :action => 'export_multiple', :layout => false
246 export = render_to_string :action => 'export_multiple', :layout => false
248 send_data(export, :type => 'text/html', :filename => "wiki.html")
247 send_data(export, :type => 'text/html', :filename => "wiki.html")
249 }
248 }
250 format.pdf {
249 format.pdf {
251 send_data(wiki_pages_to_pdf(@pages, @project), :type => 'application/pdf', :filename => "#{@project.identifier}.pdf")
250 send_data(wiki_pages_to_pdf(@pages, @project), :type => 'application/pdf', :filename => "#{@project.identifier}.pdf")
252 }
251 }
253 end
252 end
254 end
253 end
255
254
256 def preview
255 def preview
257 page = @wiki.find_page(params[:id])
256 page = @wiki.find_page(params[:id])
258 # page is nil when previewing a new page
257 # page is nil when previewing a new page
259 return render_403 unless page.nil? || editable?(page)
258 return render_403 unless page.nil? || editable?(page)
260 if page
259 if page
261 @attachements = page.attachments
260 @attachements = page.attachments
262 @previewed = page.content
261 @previewed = page.content
263 end
262 end
264 @text = params[:content][:text]
263 @text = params[:content][:text]
265 render :partial => 'common/preview'
264 render :partial => 'common/preview'
266 end
265 end
267
266
268 def add_attachment
267 def add_attachment
269 return render_403 unless editable?
268 return render_403 unless editable?
270 attachments = Attachment.attach_files(@page, params[:attachments])
269 attachments = Attachment.attach_files(@page, params[:attachments])
271 render_attachment_warning_if_needed(@page)
270 render_attachment_warning_if_needed(@page)
272 redirect_to :action => 'show', :id => @page.title, :project_id => @project
271 redirect_to :action => 'show', :id => @page.title, :project_id => @project
273 end
272 end
274
273
275 private
274 private
276
275
277 def find_wiki
276 def find_wiki
278 @project = Project.find(params[:project_id])
277 @project = Project.find(params[:project_id])
279 @wiki = @project.wiki
278 @wiki = @project.wiki
280 render_404 unless @wiki
279 render_404 unless @wiki
281 rescue ActiveRecord::RecordNotFound
280 rescue ActiveRecord::RecordNotFound
282 render_404
281 render_404
283 end
282 end
284
283
285 # Finds the requested page or a new page if it doesn't exist
284 # Finds the requested page or a new page if it doesn't exist
286 def find_existing_or_new_page
285 def find_existing_or_new_page
287 @page = @wiki.find_or_new_page(params[:id])
286 @page = @wiki.find_or_new_page(params[:id])
288 if @wiki.page_found_with_redirect?
287 if @wiki.page_found_with_redirect?
289 redirect_to params.update(:id => @page.title)
288 redirect_to params.update(:id => @page.title)
290 end
289 end
291 end
290 end
292
291
293 # Finds the requested page and returns a 404 error if it doesn't exist
292 # Finds the requested page and returns a 404 error if it doesn't exist
294 def find_existing_page
293 def find_existing_page
295 @page = @wiki.find_page(params[:id])
294 @page = @wiki.find_page(params[:id])
296 if @page.nil?
295 if @page.nil?
297 render_404
296 render_404
298 return
297 return
299 end
298 end
300 if @wiki.page_found_with_redirect?
299 if @wiki.page_found_with_redirect?
301 redirect_to params.update(:id => @page.title)
300 redirect_to params.update(:id => @page.title)
302 end
301 end
303 end
302 end
304
303
305 # Returns true if the current user is allowed to edit the page, otherwise false
304 # Returns true if the current user is allowed to edit the page, otherwise false
306 def editable?(page = @page)
305 def editable?(page = @page)
307 page.editable_by?(User.current)
306 page.editable_by?(User.current)
308 end
307 end
309
308
310 # Returns the default content of a new wiki page
309 # Returns the default content of a new wiki page
311 def initial_page_content(page)
310 def initial_page_content(page)
312 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
311 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
313 extend helper unless self.instance_of?(helper)
312 extend helper unless self.instance_of?(helper)
314 helper.instance_method(:initial_page_content).bind(self).call(page)
313 helper.instance_method(:initial_page_content).bind(self).call(page)
315 end
314 end
316
315
317 def load_pages_for_index
316 def load_pages_for_index
318 @pages = @wiki.pages.with_updated_on.all(:order => 'title', :include => {:wiki => :project})
317 @pages = @wiki.pages.with_updated_on.all(:order => 'title', :include => {:wiki => :project})
319 end
318 end
320 end
319 end
@@ -1,229 +1,234
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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 include Redmine::SafeAttributes
23
22 belongs_to :wiki
24 belongs_to :wiki
23 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
25 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
24 acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
26 acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
25 acts_as_tree :dependent => :nullify, :order => 'title'
27 acts_as_tree :dependent => :nullify, :order => 'title'
26
28
27 acts_as_watchable
29 acts_as_watchable
28 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
30 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
29 :description => :text,
31 :description => :text,
30 :datetime => :created_on,
32 :datetime => :created_on,
31 :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}}
33 :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}}
32
34
33 acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
35 acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
34 :include => [{:wiki => :project}, :content],
36 :include => [{:wiki => :project}, :content],
35 :permission => :view_wiki_pages,
37 :permission => :view_wiki_pages,
36 :project_key => "#{Wiki.table_name}.project_id"
38 :project_key => "#{Wiki.table_name}.project_id"
37
39
38 attr_accessor :redirect_existing_links
40 attr_accessor :redirect_existing_links
39
41
40 validates_presence_of :title
42 validates_presence_of :title
41 validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/
43 validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/
42 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
44 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
43 validates_associated :content
45 validates_associated :content
44
46
45 validate :validate_parent_title
47 validate :validate_parent_title
46 before_destroy :remove_redirects
48 before_destroy :remove_redirects
47 before_save :handle_redirects
49 before_save :handle_redirects
48
50
49 # eager load information about last updates, without loading text
51 # eager load information about last updates, without loading text
50 named_scope :with_updated_on, {
52 named_scope :with_updated_on, {
51 :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
53 :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
52 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id"
54 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id"
53 }
55 }
54
56
55 # Wiki pages that are protected by default
57 # Wiki pages that are protected by default
56 DEFAULT_PROTECTED_PAGES = %w(sidebar)
58 DEFAULT_PROTECTED_PAGES = %w(sidebar)
57
59
60 safe_attributes 'parent_id',
61 :if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)}
62
58 def initialize(attributes=nil, *args)
63 def initialize(attributes=nil, *args)
59 super
64 super
60 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
65 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
61 self.protected = true
66 self.protected = true
62 end
67 end
63 end
68 end
64
69
65 def visible?(user=User.current)
70 def visible?(user=User.current)
66 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
71 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
67 end
72 end
68
73
69 def title=(value)
74 def title=(value)
70 value = Wiki.titleize(value)
75 value = Wiki.titleize(value)
71 @previous_title = read_attribute(:title) if @previous_title.blank?
76 @previous_title = read_attribute(:title) if @previous_title.blank?
72 write_attribute(:title, value)
77 write_attribute(:title, value)
73 end
78 end
74
79
75 def handle_redirects
80 def handle_redirects
76 self.title = Wiki.titleize(title)
81 self.title = Wiki.titleize(title)
77 # Manage redirects if the title has changed
82 # Manage redirects if the title has changed
78 if !@previous_title.blank? && (@previous_title != title) && !new_record?
83 if !@previous_title.blank? && (@previous_title != title) && !new_record?
79 # Update redirects that point to the old title
84 # Update redirects that point to the old title
80 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
85 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
81 r.redirects_to = title
86 r.redirects_to = title
82 r.title == r.redirects_to ? r.destroy : r.save
87 r.title == r.redirects_to ? r.destroy : r.save
83 end
88 end
84 # Remove redirects for the new title
89 # Remove redirects for the new title
85 wiki.redirects.find_all_by_title(title).each(&:destroy)
90 wiki.redirects.find_all_by_title(title).each(&:destroy)
86 # Create a redirect to the new title
91 # Create a redirect to the new title
87 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
92 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
88 @previous_title = nil
93 @previous_title = nil
89 end
94 end
90 end
95 end
91
96
92 def remove_redirects
97 def remove_redirects
93 # Remove redirects to this page
98 # Remove redirects to this page
94 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
99 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
95 end
100 end
96
101
97 def pretty_title
102 def pretty_title
98 WikiPage.pretty_title(title)
103 WikiPage.pretty_title(title)
99 end
104 end
100
105
101 def content_for_version(version=nil)
106 def content_for_version(version=nil)
102 result = content.versions.find_by_version(version.to_i) if version
107 result = content.versions.find_by_version(version.to_i) if version
103 result ||= content
108 result ||= content
104 result
109 result
105 end
110 end
106
111
107 def diff(version_to=nil, version_from=nil)
112 def diff(version_to=nil, version_from=nil)
108 version_to = version_to ? version_to.to_i : self.content.version
113 version_to = version_to ? version_to.to_i : self.content.version
109 version_from = version_from ? version_from.to_i : version_to - 1
114 version_from = version_from ? version_from.to_i : version_to - 1
110 version_to, version_from = version_from, version_to unless version_from < version_to
115 version_to, version_from = version_from, version_to unless version_from < version_to
111
116
112 content_to = content.versions.find_by_version(version_to)
117 content_to = content.versions.find_by_version(version_to)
113 content_from = content.versions.find_by_version(version_from)
118 content_from = content.versions.find_by_version(version_from)
114
119
115 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
120 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
116 end
121 end
117
122
118 def annotate(version=nil)
123 def annotate(version=nil)
119 version = version ? version.to_i : self.content.version
124 version = version ? version.to_i : self.content.version
120 c = content.versions.find_by_version(version)
125 c = content.versions.find_by_version(version)
121 c ? WikiAnnotate.new(c) : nil
126 c ? WikiAnnotate.new(c) : nil
122 end
127 end
123
128
124 def self.pretty_title(str)
129 def self.pretty_title(str)
125 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
130 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
126 end
131 end
127
132
128 def project
133 def project
129 wiki.project
134 wiki.project
130 end
135 end
131
136
132 def text
137 def text
133 content.text if content
138 content.text if content
134 end
139 end
135
140
136 def updated_on
141 def updated_on
137 unless @updated_on
142 unless @updated_on
138 if time = read_attribute(:updated_on)
143 if time = read_attribute(:updated_on)
139 # content updated_on was eager loaded with the page
144 # content updated_on was eager loaded with the page
140 begin
145 begin
141 @updated_on = Time.zone ? Time.zone.parse(time.to_s) : Time.parse(time.to_s)
146 @updated_on = Time.zone ? Time.zone.parse(time.to_s) : Time.parse(time.to_s)
142 rescue
147 rescue
143 end
148 end
144 else
149 else
145 @updated_on = content && content.updated_on
150 @updated_on = content && content.updated_on
146 end
151 end
147 end
152 end
148 @updated_on
153 @updated_on
149 end
154 end
150
155
151 # Returns true if usr is allowed to edit the page, otherwise false
156 # Returns true if usr is allowed to edit the page, otherwise false
152 def editable_by?(usr)
157 def editable_by?(usr)
153 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
158 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
154 end
159 end
155
160
156 def attachments_deletable?(usr=User.current)
161 def attachments_deletable?(usr=User.current)
157 editable_by?(usr) && super(usr)
162 editable_by?(usr) && super(usr)
158 end
163 end
159
164
160 def parent_title
165 def parent_title
161 @parent_title || (self.parent && self.parent.pretty_title)
166 @parent_title || (self.parent && self.parent.pretty_title)
162 end
167 end
163
168
164 def parent_title=(t)
169 def parent_title=(t)
165 @parent_title = t
170 @parent_title = t
166 parent_page = t.blank? ? nil : self.wiki.find_page(t)
171 parent_page = t.blank? ? nil : self.wiki.find_page(t)
167 self.parent = parent_page
172 self.parent = parent_page
168 end
173 end
169
174
170 protected
175 protected
171
176
172 def validate_parent_title
177 def validate_parent_title
173 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
178 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
174 errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
179 errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
175 errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
180 errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
176 end
181 end
177 end
182 end
178
183
179 class WikiDiff < Redmine::Helpers::Diff
184 class WikiDiff < Redmine::Helpers::Diff
180 attr_reader :content_to, :content_from
185 attr_reader :content_to, :content_from
181
186
182 def initialize(content_to, content_from)
187 def initialize(content_to, content_from)
183 @content_to = content_to
188 @content_to = content_to
184 @content_from = content_from
189 @content_from = content_from
185 super(content_to.text, content_from.text)
190 super(content_to.text, content_from.text)
186 end
191 end
187 end
192 end
188
193
189 class WikiAnnotate
194 class WikiAnnotate
190 attr_reader :lines, :content
195 attr_reader :lines, :content
191
196
192 def initialize(content)
197 def initialize(content)
193 @content = content
198 @content = content
194 current = content
199 current = content
195 current_lines = current.text.split(/\r?\n/)
200 current_lines = current.text.split(/\r?\n/)
196 @lines = current_lines.collect {|t| [nil, nil, t]}
201 @lines = current_lines.collect {|t| [nil, nil, t]}
197 positions = []
202 positions = []
198 current_lines.size.times {|i| positions << i}
203 current_lines.size.times {|i| positions << i}
199 while (current.previous)
204 while (current.previous)
200 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
205 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
201 d.each_slice(3) do |s|
206 d.each_slice(3) do |s|
202 sign, line = s[0], s[1]
207 sign, line = s[0], s[1]
203 if sign == '+' && positions[line] && positions[line] != -1
208 if sign == '+' && positions[line] && positions[line] != -1
204 if @lines[positions[line]][0].nil?
209 if @lines[positions[line]][0].nil?
205 @lines[positions[line]][0] = current.version
210 @lines[positions[line]][0] = current.version
206 @lines[positions[line]][1] = current.author
211 @lines[positions[line]][1] = current.author
207 end
212 end
208 end
213 end
209 end
214 end
210 d.each_slice(3) do |s|
215 d.each_slice(3) do |s|
211 sign, line = s[0], s[1]
216 sign, line = s[0], s[1]
212 if sign == '-'
217 if sign == '-'
213 positions.insert(line, -1)
218 positions.insert(line, -1)
214 else
219 else
215 positions[line] = nil
220 positions[line] = nil
216 end
221 end
217 end
222 end
218 positions.compact!
223 positions.compact!
219 # Stop if every line is annotated
224 # Stop if every line is annotated
220 break unless @lines.detect { |line| line[0].nil? }
225 break unless @lines.detect { |line| line[0].nil? }
221 current = current.previous
226 current = current.previous
222 end
227 end
223 @lines.each { |line|
228 @lines.each { |line|
224 line[0] ||= current.version
229 line[0] ||= current.version
225 # if the last known version is > 1 (eg. history was cleared), we don't know the author
230 # if the last known version is > 1 (eg. history was cleared), we don't know the author
226 line[1] ||= current.author if current.version == 1
231 line[1] ||= current.author if current.version == 1
227 }
232 }
228 end
233 end
229 end
234 end
@@ -1,42 +1,47
1 <%= wiki_page_breadcrumb(@page) %>
1 <%= wiki_page_breadcrumb(@page) %>
2
2
3 <h2><%=h @page.pretty_title %></h2>
3 <h2><%=h @page.pretty_title %></h2>
4
4
5 <% form_for :content, @content, :url => {:action => 'update', :id => @page.title}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %>
5 <% form_for :content, @content, :url => {:action => 'update', :id => @page.title}, :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %>
6 <%= f.hidden_field :version %>
6 <%= f.hidden_field :version %>
7 <% if @section %>
7 <% if @section %>
8 <%= hidden_field_tag 'section', @section %>
8 <%= hidden_field_tag 'section', @section %>
9 <%= hidden_field_tag 'section_hash', @section_hash %>
9 <%= hidden_field_tag 'section_hash', @section_hash %>
10 <% end %>
10 <% end %>
11 <%= error_messages_for 'content' %>
11 <%= error_messages_for 'content' %>
12
12
13 <div class="box tabular">
13 <div class="box tabular">
14 <%= text_area_tag 'content[text]', @text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit) %>
14 <%= text_area_tag 'content[text]', @text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit) %>
15
15
16 <% if @page.new_record? && @page.parent %>
16 <% if @page.safe_attribute_names.include?('parent_id') && @wiki.pages.any? %>
17 <p><label><%= check_box_tag 'page[parent_id]', @page.parent.id, true %> <%= l(:field_parent_title) %></label> <%=h @page.parent.pretty_title %></p>
17 <% fields_for @page do |fp| %>
18 <p>
19 <label><%= l(:field_parent_title) %></label>
20 <%= fp.select :parent_id, "<option value=''></option>" + wiki_page_options_for_select(@wiki.pages.all(:include => :parent) - @page.self_and_descendants, @page.parent) %>
21 </p>
22 <% end %>
18 <% end %>
23 <% end %>
19
24
20 <p><label><%= l(:field_comments) %></label><%= f.text_field :comments, :size => 120 %></p>
25 <p><label><%= l(:field_comments) %></label><%= f.text_field :comments, :size => 120 %></p>
21 <p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>
26 <p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>
22 </div>
27 </div>
23
28
24 <p><%= submit_tag l(:button_save) %>
29 <p><%= submit_tag l(:button_save) %>
25 <%= link_to_remote l(:label_preview),
30 <%= link_to_remote l(:label_preview),
26 { :url => { :controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title },
31 { :url => { :controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title },
27 :method => :post,
32 :method => :post,
28 :update => 'preview',
33 :update => 'preview',
29 :with => "Form.serialize('wiki_form')",
34 :with => "Form.serialize('wiki_form')",
30 :complete => "Element.scrollTo('preview')"
35 :complete => "Element.scrollTo('preview')"
31 }, :accesskey => accesskey(:preview) %></p>
36 }, :accesskey => accesskey(:preview) %></p>
32 <%= wikitoolbar_for 'content_text' %>
37 <%= wikitoolbar_for 'content_text' %>
33 <% end %>
38 <% end %>
34
39
35 <div id="preview" class="wiki"></div>
40 <div id="preview" class="wiki"></div>
36
41
37 <% content_for :header_tags do %>
42 <% content_for :header_tags do %>
38 <%= stylesheet_link_tag 'scm' %>
43 <%= stylesheet_link_tag 'scm' %>
39 <%= robot_exclusion_tag %>
44 <%= robot_exclusion_tag %>
40 <% end %>
45 <% end %>
41
46
42 <% html_title @page.pretty_title %>
47 <% html_title @page.pretty_title %>
@@ -1,771 +1,819
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
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 < ActionController::TestCase
24 class WikiControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles,
25 fixtures :projects, :users, :roles, :members, :member_roles,
26 :enabled_modules, :wikis, :wiki_pages, :wiki_contents,
26 :enabled_modules, :wikis, :wiki_pages, :wiki_contents,
27 :wiki_content_versions, :attachments
27 :wiki_content_versions, :attachments
28
28
29 def setup
29 def setup
30 @controller = WikiController.new
30 @controller = WikiController.new
31 @request = ActionController::TestRequest.new
31 @request = ActionController::TestRequest.new
32 @response = ActionController::TestResponse.new
32 @response = ActionController::TestResponse.new
33 User.current = nil
33 User.current = nil
34 end
34 end
35
35
36 def test_show_start_page
36 def test_show_start_page
37 get :show, :project_id => 'ecookbook'
37 get :show, :project_id => 'ecookbook'
38 assert_response :success
38 assert_response :success
39 assert_template 'show'
39 assert_template 'show'
40 assert_tag :tag => 'h1', :content => /CookBook documentation/
40 assert_tag :tag => 'h1', :content => /CookBook documentation/
41
41
42 # child_pages macro
42 # child_pages macro
43 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
43 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
44 :child => { :tag => 'li',
44 :child => { :tag => 'li',
45 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
45 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
46 :content => 'Page with an inline image' } }
46 :content => 'Page with an inline image' } }
47 end
47 end
48
48
49 def test_export_link
49 def test_export_link
50 Role.anonymous.add_permission! :export_wiki_pages
50 Role.anonymous.add_permission! :export_wiki_pages
51 get :show, :project_id => 'ecookbook'
51 get :show, :project_id => 'ecookbook'
52 assert_response :success
52 assert_response :success
53 assert_tag 'a', :attributes => {:href => '/projects/ecookbook/wiki/CookBook_documentation.txt'}
53 assert_tag 'a', :attributes => {:href => '/projects/ecookbook/wiki/CookBook_documentation.txt'}
54 end
54 end
55
55
56 def test_show_page_with_name
56 def test_show_page_with_name
57 get :show, :project_id => 1, :id => 'Another_page'
57 get :show, :project_id => 1, :id => 'Another_page'
58 assert_response :success
58 assert_response :success
59 assert_template 'show'
59 assert_template 'show'
60 assert_tag :tag => 'h1', :content => /Another page/
60 assert_tag :tag => 'h1', :content => /Another page/
61 # Included page with an inline image
61 # Included page with an inline image
62 assert_tag :tag => 'p', :content => /This is an inline image/
62 assert_tag :tag => 'p', :content => /This is an inline image/
63 assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3',
63 assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3',
64 :alt => 'This is a logo' }
64 :alt => 'This is a logo' }
65 end
65 end
66
66
67 def test_show_redirected_page
67 def test_show_redirected_page
68 WikiRedirect.create!(:wiki_id => 1, :title => 'Old_title', :redirects_to => 'Another_page')
68 WikiRedirect.create!(:wiki_id => 1, :title => 'Old_title', :redirects_to => 'Another_page')
69
69
70 get :show, :project_id => 'ecookbook', :id => 'Old_title'
70 get :show, :project_id => 'ecookbook', :id => 'Old_title'
71 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
71 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
72 end
72 end
73
73
74 def test_show_with_sidebar
74 def test_show_with_sidebar
75 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
75 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
76 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
76 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
77 page.save!
77 page.save!
78
78
79 get :show, :project_id => 1, :id => 'Another_page'
79 get :show, :project_id => 1, :id => 'Another_page'
80 assert_response :success
80 assert_response :success
81 assert_tag :tag => 'div', :attributes => {:id => 'sidebar'},
81 assert_tag :tag => 'div', :attributes => {:id => 'sidebar'},
82 :content => /Side bar content for test_show_with_sidebar/
82 :content => /Side bar content for test_show_with_sidebar/
83 end
83 end
84
84
85 def test_show_should_display_section_edit_links
85 def test_show_should_display_section_edit_links
86 @request.session[:user_id] = 2
86 @request.session[:user_id] = 2
87 get :show, :project_id => 1, :id => 'Page with sections'
87 get :show, :project_id => 1, :id => 'Page with sections'
88 assert_no_tag 'a', :attributes => {
88 assert_no_tag 'a', :attributes => {
89 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=1'
89 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=1'
90 }
90 }
91 assert_tag 'a', :attributes => {
91 assert_tag 'a', :attributes => {
92 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
92 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
93 }
93 }
94 assert_tag 'a', :attributes => {
94 assert_tag 'a', :attributes => {
95 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=3'
95 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=3'
96 }
96 }
97 end
97 end
98
98
99 def test_show_current_version_should_display_section_edit_links
99 def test_show_current_version_should_display_section_edit_links
100 @request.session[:user_id] = 2
100 @request.session[:user_id] = 2
101 get :show, :project_id => 1, :id => 'Page with sections', :version => 3
101 get :show, :project_id => 1, :id => 'Page with sections', :version => 3
102
102
103 assert_tag 'a', :attributes => {
103 assert_tag 'a', :attributes => {
104 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
104 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
105 }
105 }
106 end
106 end
107
107
108 def test_show_old_version_should_not_display_section_edit_links
108 def test_show_old_version_should_not_display_section_edit_links
109 @request.session[:user_id] = 2
109 @request.session[:user_id] = 2
110 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
110 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
111
111
112 assert_no_tag 'a', :attributes => {
112 assert_no_tag 'a', :attributes => {
113 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
113 :href => '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
114 }
114 }
115 end
115 end
116
116
117 def test_show_unexistent_page_without_edit_right
117 def test_show_unexistent_page_without_edit_right
118 get :show, :project_id => 1, :id => 'Unexistent page'
118 get :show, :project_id => 1, :id => 'Unexistent page'
119 assert_response 404
119 assert_response 404
120 end
120 end
121
121
122 def test_show_unexistent_page_with_edit_right
122 def test_show_unexistent_page_with_edit_right
123 @request.session[:user_id] = 2
123 @request.session[:user_id] = 2
124 get :show, :project_id => 1, :id => 'Unexistent page'
124 get :show, :project_id => 1, :id => 'Unexistent page'
125 assert_response :success
125 assert_response :success
126 assert_template 'edit'
126 assert_template 'edit'
127 assert_no_tag 'input', :attributes => {:name => 'page[parent_id]'}
128 end
127 end
129
128
130 def test_show_unexistent_page_with_parent
129 def test_show_unexistent_page_with_parent_should_preselect_parent
131 @request.session[:user_id] = 2
130 @request.session[:user_id] = 2
132 get :show, :project_id => 1, :id => 'Unexistent page', :parent => 'Another_page'
131 get :show, :project_id => 1, :id => 'Unexistent page', :parent => 'Another_page'
133 assert_response :success
132 assert_response :success
134 assert_template 'edit'
133 assert_template 'edit'
135 assert_tag 'input', :attributes => {:name => 'page[parent_id]', :value => '2'}
134 assert_tag 'select', :attributes => {:name => 'wiki_page[parent_id]'},
135 :child => {:tag => 'option', :attributes => {:value => '2', :selected => 'selected'}}
136 end
136 end
137
137
138 def test_show_should_not_show_history_without_permission
138 def test_show_should_not_show_history_without_permission
139 Role.anonymous.remove_permission! :view_wiki_edits
139 Role.anonymous.remove_permission! :view_wiki_edits
140 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
140 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
141
141
142 assert_response 302
142 assert_response 302
143 end
143 end
144
144
145 def test_create_page
145 def test_create_page
146 @request.session[:user_id] = 2
146 @request.session[:user_id] = 2
147 assert_difference 'WikiPage.count' do
147 assert_difference 'WikiPage.count' do
148 assert_difference 'WikiContent.count' do
148 assert_difference 'WikiContent.count' do
149 put :update, :project_id => 1,
149 put :update, :project_id => 1,
150 :id => 'New page',
150 :id => 'New page',
151 :content => {:comments => 'Created the page',
151 :content => {:comments => 'Created the page',
152 :text => "h1. New page\n\nThis is a new page",
152 :text => "h1. New page\n\nThis is a new page",
153 :version => 0}
153 :version => 0}
154 end
154 end
155 end
155 end
156 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
156 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
157 page = Project.find(1).wiki.find_page('New page')
157 page = Project.find(1).wiki.find_page('New page')
158 assert !page.new_record?
158 assert !page.new_record?
159 assert_not_nil page.content
159 assert_not_nil page.content
160 assert_nil page.parent
160 assert_nil page.parent
161 assert_equal 'Created the page', page.content.comments
161 assert_equal 'Created the page', page.content.comments
162 end
162 end
163
163
164 def test_create_page_with_attachments
164 def test_create_page_with_attachments
165 @request.session[:user_id] = 2
165 @request.session[:user_id] = 2
166 assert_difference 'WikiPage.count' do
166 assert_difference 'WikiPage.count' do
167 assert_difference 'Attachment.count' do
167 assert_difference 'Attachment.count' do
168 put :update, :project_id => 1,
168 put :update, :project_id => 1,
169 :id => 'New page',
169 :id => 'New page',
170 :content => {:comments => 'Created the page',
170 :content => {:comments => 'Created the page',
171 :text => "h1. New page\n\nThis is a new page",
171 :text => "h1. New page\n\nThis is a new page",
172 :version => 0},
172 :version => 0},
173 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
173 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
174 end
174 end
175 end
175 end
176 page = Project.find(1).wiki.find_page('New page')
176 page = Project.find(1).wiki.find_page('New page')
177 assert_equal 1, page.attachments.count
177 assert_equal 1, page.attachments.count
178 assert_equal 'testfile.txt', page.attachments.first.filename
178 assert_equal 'testfile.txt', page.attachments.first.filename
179 end
179 end
180
180
181 def test_create_page_with_parent
181 def test_create_page_with_parent
182 @request.session[:user_id] = 2
182 @request.session[:user_id] = 2
183 assert_difference 'WikiPage.count' do
183 assert_difference 'WikiPage.count' do
184 put :update, :project_id => 1, :id => 'New page',
184 put :update, :project_id => 1, :id => 'New page',
185 :content => {:text => "h1. New page\n\nThis is a new page", :version => 0},
185 :content => {:text => "h1. New page\n\nThis is a new page", :version => 0},
186 :page => {:parent_id => 2}
186 :wiki_page => {:parent_id => 2}
187 end
187 end
188 page = Project.find(1).wiki.find_page('New page')
188 page = Project.find(1).wiki.find_page('New page')
189 assert_equal WikiPage.find(2), page.parent
189 assert_equal WikiPage.find(2), page.parent
190 end
190 end
191
191
192 def test_edit_page
192 def test_edit_page
193 @request.session[:user_id] = 2
193 @request.session[:user_id] = 2
194 get :edit, :project_id => 'ecookbook', :id => 'Another_page'
194 get :edit, :project_id => 'ecookbook', :id => 'Another_page'
195
195
196 assert_response :success
196 assert_response :success
197 assert_template 'edit'
197 assert_template 'edit'
198
198
199 assert_tag 'textarea',
199 assert_tag 'textarea',
200 :attributes => { :name => 'content[text]' },
200 :attributes => { :name => 'content[text]' },
201 :content => WikiPage.find_by_title('Another_page').content.text
201 :content => WikiPage.find_by_title('Another_page').content.text
202 end
202 end
203
203
204 def test_edit_section
204 def test_edit_section
205 @request.session[:user_id] = 2
205 @request.session[:user_id] = 2
206 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2
206 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2
207
207
208 assert_response :success
208 assert_response :success
209 assert_template 'edit'
209 assert_template 'edit'
210
210
211 page = WikiPage.find_by_title('Page_with_sections')
211 page = WikiPage.find_by_title('Page_with_sections')
212 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
212 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
213
213
214 assert_tag 'textarea',
214 assert_tag 'textarea',
215 :attributes => { :name => 'content[text]' },
215 :attributes => { :name => 'content[text]' },
216 :content => section
216 :content => section
217 assert_tag 'input',
217 assert_tag 'input',
218 :attributes => { :name => 'section', :type => 'hidden', :value => '2' }
218 :attributes => { :name => 'section', :type => 'hidden', :value => '2' }
219 assert_tag 'input',
219 assert_tag 'input',
220 :attributes => { :name => 'section_hash', :type => 'hidden', :value => hash }
220 :attributes => { :name => 'section_hash', :type => 'hidden', :value => hash }
221 end
221 end
222
222
223 def test_edit_invalid_section_should_respond_with_404
223 def test_edit_invalid_section_should_respond_with_404
224 @request.session[:user_id] = 2
224 @request.session[:user_id] = 2
225 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10
225 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10
226
226
227 assert_response 404
227 assert_response 404
228 end
228 end
229
229
230 def test_update_page
230 def test_update_page
231 @request.session[:user_id] = 2
231 @request.session[:user_id] = 2
232 assert_no_difference 'WikiPage.count' do
232 assert_no_difference 'WikiPage.count' do
233 assert_no_difference 'WikiContent.count' do
233 assert_no_difference 'WikiContent.count' do
234 assert_difference 'WikiContent::Version.count' do
234 assert_difference 'WikiContent::Version.count' do
235 put :update, :project_id => 1,
235 put :update, :project_id => 1,
236 :id => 'Another_page',
236 :id => 'Another_page',
237 :content => {
237 :content => {
238 :comments => "my comments",
238 :comments => "my comments",
239 :text => "edited",
239 :text => "edited",
240 :version => 1
240 :version => 1
241 }
241 }
242 end
242 end
243 end
243 end
244 end
244 end
245 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
245 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
246
246
247 page = Wiki.find(1).pages.find_by_title('Another_page')
247 page = Wiki.find(1).pages.find_by_title('Another_page')
248 assert_equal "edited", page.content.text
248 assert_equal "edited", page.content.text
249 assert_equal 2, page.content.version
249 assert_equal 2, page.content.version
250 assert_equal "my comments", page.content.comments
250 assert_equal "my comments", page.content.comments
251 end
251 end
252
252
253 def test_update_page_with_parent
254 @request.session[:user_id] = 2
255 assert_no_difference 'WikiPage.count' do
256 assert_no_difference 'WikiContent.count' do
257 assert_difference 'WikiContent::Version.count' do
258 put :update, :project_id => 1,
259 :id => 'Another_page',
260 :content => {
261 :comments => "my comments",
262 :text => "edited",
263 :version => 1
264 },
265 :wiki_page => {:parent_id => '1'}
266 end
267 end
268 end
269 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
270
271 page = Wiki.find(1).pages.find_by_title('Another_page')
272 assert_equal "edited", page.content.text
273 assert_equal 2, page.content.version
274 assert_equal "my comments", page.content.comments
275 assert_equal WikiPage.find(1), page.parent
276 end
277
253 def test_update_page_with_failure
278 def test_update_page_with_failure
254 @request.session[:user_id] = 2
279 @request.session[:user_id] = 2
255 assert_no_difference 'WikiPage.count' do
280 assert_no_difference 'WikiPage.count' do
256 assert_no_difference 'WikiContent.count' do
281 assert_no_difference 'WikiContent.count' do
257 assert_no_difference 'WikiContent::Version.count' do
282 assert_no_difference 'WikiContent::Version.count' do
258 put :update, :project_id => 1,
283 put :update, :project_id => 1,
259 :id => 'Another_page',
284 :id => 'Another_page',
260 :content => {
285 :content => {
261 :comments => 'a' * 300, # failure here, comment is too long
286 :comments => 'a' * 300, # failure here, comment is too long
262 :text => 'edited',
287 :text => 'edited',
263 :version => 1
288 :version => 1
264 }
289 }
265 end
290 end
266 end
291 end
267 end
292 end
268 assert_response :success
293 assert_response :success
269 assert_template 'edit'
294 assert_template 'edit'
270
295
271 assert_error_tag :descendant => {:content => /Comment is too long/}
296 assert_error_tag :descendant => {:content => /Comment is too long/}
272 assert_tag :tag => 'textarea', :attributes => {:id => 'content_text'}, :content => 'edited'
297 assert_tag :tag => 'textarea', :attributes => {:id => 'content_text'}, :content => 'edited'
273 assert_tag :tag => 'input', :attributes => {:id => 'content_version', :value => '1'}
298 assert_tag :tag => 'input', :attributes => {:id => 'content_version', :value => '1'}
274 end
299 end
275
300
301 def test_update_page_with_parent_change_only_should_not_create_content_version
302 @request.session[:user_id] = 2
303 assert_no_difference 'WikiPage.count' do
304 assert_no_difference 'WikiContent.count' do
305 assert_no_difference 'WikiContent::Version.count' do
306 put :update, :project_id => 1,
307 :id => 'Another_page',
308 :content => {
309 :comments => '',
310 :text => Wiki.find(1).find_page('Another_page').content.text,
311 :version => 1
312 },
313 :wiki_page => {:parent_id => '1'}
314 end
315 end
316 end
317 page = Wiki.find(1).pages.find_by_title('Another_page')
318 assert_equal 1, page.content.version
319 assert_equal WikiPage.find(1), page.parent
320 end
321
276 def test_update_page_with_attachments_only_should_not_create_content_version
322 def test_update_page_with_attachments_only_should_not_create_content_version
277 @request.session[:user_id] = 2
323 @request.session[:user_id] = 2
278 assert_no_difference 'WikiPage.count' do
324 assert_no_difference 'WikiPage.count' do
279 assert_no_difference 'WikiContent.count' do
325 assert_no_difference 'WikiContent.count' do
280 assert_no_difference 'WikiContent::Version.count' do
326 assert_no_difference 'WikiContent::Version.count' do
281 assert_difference 'Attachment.count' do
327 assert_difference 'Attachment.count' do
282 put :update, :project_id => 1,
328 put :update, :project_id => 1,
283 :id => 'Another_page',
329 :id => 'Another_page',
284 :content => {
330 :content => {
285 :comments => '',
331 :comments => '',
286 :text => Wiki.find(1).find_page('Another_page').content.text,
332 :text => Wiki.find(1).find_page('Another_page').content.text,
287 :version => 1
333 :version => 1
288 },
334 },
289 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
335 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
290 end
336 end
291 end
337 end
292 end
338 end
293 end
339 end
340 page = Wiki.find(1).pages.find_by_title('Another_page')
341 assert_equal 1, page.content.version
294 end
342 end
295
343
296 def test_update_stale_page_should_not_raise_an_error
344 def test_update_stale_page_should_not_raise_an_error
297 @request.session[:user_id] = 2
345 @request.session[:user_id] = 2
298 c = Wiki.find(1).find_page('Another_page').content
346 c = Wiki.find(1).find_page('Another_page').content
299 c.text = 'Previous text'
347 c.text = 'Previous text'
300 c.save!
348 c.save!
301 assert_equal 2, c.version
349 assert_equal 2, c.version
302
350
303 assert_no_difference 'WikiPage.count' do
351 assert_no_difference 'WikiPage.count' do
304 assert_no_difference 'WikiContent.count' do
352 assert_no_difference 'WikiContent.count' do
305 assert_no_difference 'WikiContent::Version.count' do
353 assert_no_difference 'WikiContent::Version.count' do
306 put :update, :project_id => 1,
354 put :update, :project_id => 1,
307 :id => 'Another_page',
355 :id => 'Another_page',
308 :content => {
356 :content => {
309 :comments => 'My comments',
357 :comments => 'My comments',
310 :text => 'Text should not be lost',
358 :text => 'Text should not be lost',
311 :version => 1
359 :version => 1
312 }
360 }
313 end
361 end
314 end
362 end
315 end
363 end
316 assert_response :success
364 assert_response :success
317 assert_template 'edit'
365 assert_template 'edit'
318 assert_tag :div,
366 assert_tag :div,
319 :attributes => { :class => /error/ },
367 :attributes => { :class => /error/ },
320 :content => /Data has been updated by another user/
368 :content => /Data has been updated by another user/
321 assert_tag 'textarea',
369 assert_tag 'textarea',
322 :attributes => { :name => 'content[text]' },
370 :attributes => { :name => 'content[text]' },
323 :content => /Text should not be lost/
371 :content => /Text should not be lost/
324 assert_tag 'input',
372 assert_tag 'input',
325 :attributes => { :name => 'content[comments]', :value => 'My comments' }
373 :attributes => { :name => 'content[comments]', :value => 'My comments' }
326
374
327 c.reload
375 c.reload
328 assert_equal 'Previous text', c.text
376 assert_equal 'Previous text', c.text
329 assert_equal 2, c.version
377 assert_equal 2, c.version
330 end
378 end
331
379
332 def test_update_section
380 def test_update_section
333 @request.session[:user_id] = 2
381 @request.session[:user_id] = 2
334 page = WikiPage.find_by_title('Page_with_sections')
382 page = WikiPage.find_by_title('Page_with_sections')
335 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
383 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
336 text = page.content.text
384 text = page.content.text
337
385
338 assert_no_difference 'WikiPage.count' do
386 assert_no_difference 'WikiPage.count' do
339 assert_no_difference 'WikiContent.count' do
387 assert_no_difference 'WikiContent.count' do
340 assert_difference 'WikiContent::Version.count' do
388 assert_difference 'WikiContent::Version.count' do
341 put :update, :project_id => 1, :id => 'Page_with_sections',
389 put :update, :project_id => 1, :id => 'Page_with_sections',
342 :content => {
390 :content => {
343 :text => "New section content",
391 :text => "New section content",
344 :version => 3
392 :version => 3
345 },
393 },
346 :section => 2,
394 :section => 2,
347 :section_hash => hash
395 :section_hash => hash
348 end
396 end
349 end
397 end
350 end
398 end
351 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections'
399 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections'
352 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text
400 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text
353 end
401 end
354
402
355 def test_update_section_should_allow_stale_page_update
403 def test_update_section_should_allow_stale_page_update
356 @request.session[:user_id] = 2
404 @request.session[:user_id] = 2
357 page = WikiPage.find_by_title('Page_with_sections')
405 page = WikiPage.find_by_title('Page_with_sections')
358 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
406 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
359 text = page.content.text
407 text = page.content.text
360
408
361 assert_no_difference 'WikiPage.count' do
409 assert_no_difference 'WikiPage.count' do
362 assert_no_difference 'WikiContent.count' do
410 assert_no_difference 'WikiContent.count' do
363 assert_difference 'WikiContent::Version.count' do
411 assert_difference 'WikiContent::Version.count' do
364 put :update, :project_id => 1, :id => 'Page_with_sections',
412 put :update, :project_id => 1, :id => 'Page_with_sections',
365 :content => {
413 :content => {
366 :text => "New section content",
414 :text => "New section content",
367 :version => 2 # Current version is 3
415 :version => 2 # Current version is 3
368 },
416 },
369 :section => 2,
417 :section => 2,
370 :section_hash => hash
418 :section_hash => hash
371 end
419 end
372 end
420 end
373 end
421 end
374 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections'
422 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections'
375 page.reload
423 page.reload
376 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text
424 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text
377 assert_equal 4, page.content.version
425 assert_equal 4, page.content.version
378 end
426 end
379
427
380 def test_update_section_should_not_allow_stale_section_update
428 def test_update_section_should_not_allow_stale_section_update
381 @request.session[:user_id] = 2
429 @request.session[:user_id] = 2
382
430
383 assert_no_difference 'WikiPage.count' do
431 assert_no_difference 'WikiPage.count' do
384 assert_no_difference 'WikiContent.count' do
432 assert_no_difference 'WikiContent.count' do
385 assert_no_difference 'WikiContent::Version.count' do
433 assert_no_difference 'WikiContent::Version.count' do
386 put :update, :project_id => 1, :id => 'Page_with_sections',
434 put :update, :project_id => 1, :id => 'Page_with_sections',
387 :content => {
435 :content => {
388 :comments => 'My comments',
436 :comments => 'My comments',
389 :text => "Text should not be lost",
437 :text => "Text should not be lost",
390 :version => 3
438 :version => 3
391 },
439 },
392 :section => 2,
440 :section => 2,
393 :section_hash => Digest::MD5.hexdigest("wrong hash")
441 :section_hash => Digest::MD5.hexdigest("wrong hash")
394 end
442 end
395 end
443 end
396 end
444 end
397 assert_response :success
445 assert_response :success
398 assert_template 'edit'
446 assert_template 'edit'
399 assert_tag :div,
447 assert_tag :div,
400 :attributes => { :class => /error/ },
448 :attributes => { :class => /error/ },
401 :content => /Data has been updated by another user/
449 :content => /Data has been updated by another user/
402 assert_tag 'textarea',
450 assert_tag 'textarea',
403 :attributes => { :name => 'content[text]' },
451 :attributes => { :name => 'content[text]' },
404 :content => /Text should not be lost/
452 :content => /Text should not be lost/
405 assert_tag 'input',
453 assert_tag 'input',
406 :attributes => { :name => 'content[comments]', :value => 'My comments' }
454 :attributes => { :name => 'content[comments]', :value => 'My comments' }
407 end
455 end
408
456
409 def test_preview
457 def test_preview
410 @request.session[:user_id] = 2
458 @request.session[:user_id] = 2
411 xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation',
459 xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation',
412 :content => { :comments => '',
460 :content => { :comments => '',
413 :text => 'this is a *previewed text*',
461 :text => 'this is a *previewed text*',
414 :version => 3 }
462 :version => 3 }
415 assert_response :success
463 assert_response :success
416 assert_template 'common/_preview'
464 assert_template 'common/_preview'
417 assert_tag :tag => 'strong', :content => /previewed text/
465 assert_tag :tag => 'strong', :content => /previewed text/
418 end
466 end
419
467
420 def test_preview_new_page
468 def test_preview_new_page
421 @request.session[:user_id] = 2
469 @request.session[:user_id] = 2
422 xhr :post, :preview, :project_id => 1, :id => 'New page',
470 xhr :post, :preview, :project_id => 1, :id => 'New page',
423 :content => { :text => 'h1. New page',
471 :content => { :text => 'h1. New page',
424 :comments => '',
472 :comments => '',
425 :version => 0 }
473 :version => 0 }
426 assert_response :success
474 assert_response :success
427 assert_template 'common/_preview'
475 assert_template 'common/_preview'
428 assert_tag :tag => 'h1', :content => /New page/
476 assert_tag :tag => 'h1', :content => /New page/
429 end
477 end
430
478
431 def test_history
479 def test_history
432 get :history, :project_id => 1, :id => 'CookBook_documentation'
480 get :history, :project_id => 1, :id => 'CookBook_documentation'
433 assert_response :success
481 assert_response :success
434 assert_template 'history'
482 assert_template 'history'
435 assert_not_nil assigns(:versions)
483 assert_not_nil assigns(:versions)
436 assert_equal 3, assigns(:versions).size
484 assert_equal 3, assigns(:versions).size
437 assert_select "input[type=submit][name=commit]"
485 assert_select "input[type=submit][name=commit]"
438 end
486 end
439
487
440 def test_history_with_one_version
488 def test_history_with_one_version
441 get :history, :project_id => 1, :id => 'Another_page'
489 get :history, :project_id => 1, :id => 'Another_page'
442 assert_response :success
490 assert_response :success
443 assert_template 'history'
491 assert_template 'history'
444 assert_not_nil assigns(:versions)
492 assert_not_nil assigns(:versions)
445 assert_equal 1, assigns(:versions).size
493 assert_equal 1, assigns(:versions).size
446 assert_select "input[type=submit][name=commit]", false
494 assert_select "input[type=submit][name=commit]", false
447 end
495 end
448
496
449 def test_diff
497 def test_diff
450 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => 2, :version_from => 1
498 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => 2, :version_from => 1
451 assert_response :success
499 assert_response :success
452 assert_template 'diff'
500 assert_template 'diff'
453 assert_tag :tag => 'span', :attributes => { :class => 'diff_in'},
501 assert_tag :tag => 'span', :attributes => { :class => 'diff_in'},
454 :content => /updated/
502 :content => /updated/
455 end
503 end
456
504
457 def test_annotate
505 def test_annotate
458 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2
506 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2
459 assert_response :success
507 assert_response :success
460 assert_template 'annotate'
508 assert_template 'annotate'
461
509
462 # Line 1
510 # Line 1
463 assert_tag :tag => 'tr', :child => {
511 assert_tag :tag => 'tr', :child => {
464 :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1', :sibling => {
512 :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1', :sibling => {
465 :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/, :sibling => {
513 :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/, :sibling => {
466 :tag => 'td', :content => /h1\. CookBook documentation/
514 :tag => 'td', :content => /h1\. CookBook documentation/
467 }
515 }
468 }
516 }
469 }
517 }
470
518
471 # Line 5
519 # Line 5
472 assert_tag :tag => 'tr', :child => {
520 assert_tag :tag => 'tr', :child => {
473 :tag => 'th', :attributes => {:class => 'line-num'}, :content => '5', :sibling => {
521 :tag => 'th', :attributes => {:class => 'line-num'}, :content => '5', :sibling => {
474 :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/, :sibling => {
522 :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/, :sibling => {
475 :tag => 'td', :content => /Some updated \[\[documentation\]\] here/
523 :tag => 'td', :content => /Some updated \[\[documentation\]\] here/
476 }
524 }
477 }
525 }
478 }
526 }
479 end
527 end
480
528
481 def test_get_rename
529 def test_get_rename
482 @request.session[:user_id] = 2
530 @request.session[:user_id] = 2
483 get :rename, :project_id => 1, :id => 'Another_page'
531 get :rename, :project_id => 1, :id => 'Another_page'
484 assert_response :success
532 assert_response :success
485 assert_template 'rename'
533 assert_template 'rename'
486 assert_tag 'option',
534 assert_tag 'option',
487 :attributes => {:value => ''},
535 :attributes => {:value => ''},
488 :content => '',
536 :content => '',
489 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
537 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
490 assert_no_tag 'option',
538 assert_no_tag 'option',
491 :attributes => {:selected => 'selected'},
539 :attributes => {:selected => 'selected'},
492 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
540 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
493 end
541 end
494
542
495 def test_get_rename_child_page
543 def test_get_rename_child_page
496 @request.session[:user_id] = 2
544 @request.session[:user_id] = 2
497 get :rename, :project_id => 1, :id => 'Child_1'
545 get :rename, :project_id => 1, :id => 'Child_1'
498 assert_response :success
546 assert_response :success
499 assert_template 'rename'
547 assert_template 'rename'
500 assert_tag 'option',
548 assert_tag 'option',
501 :attributes => {:value => ''},
549 :attributes => {:value => ''},
502 :content => '',
550 :content => '',
503 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
551 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
504 assert_tag 'option',
552 assert_tag 'option',
505 :attributes => {:value => '2', :selected => 'selected'},
553 :attributes => {:value => '2', :selected => 'selected'},
506 :content => /Another page/,
554 :content => /Another page/,
507 :parent => {
555 :parent => {
508 :tag => 'select',
556 :tag => 'select',
509 :attributes => {:name => 'wiki_page[parent_id]'}
557 :attributes => {:name => 'wiki_page[parent_id]'}
510 }
558 }
511 end
559 end
512
560
513 def test_rename_with_redirect
561 def test_rename_with_redirect
514 @request.session[:user_id] = 2
562 @request.session[:user_id] = 2
515 post :rename, :project_id => 1, :id => 'Another_page',
563 post :rename, :project_id => 1, :id => 'Another_page',
516 :wiki_page => { :title => 'Another renamed page',
564 :wiki_page => { :title => 'Another renamed page',
517 :redirect_existing_links => 1 }
565 :redirect_existing_links => 1 }
518 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
566 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
519 wiki = Project.find(1).wiki
567 wiki = Project.find(1).wiki
520 # Check redirects
568 # Check redirects
521 assert_not_nil wiki.find_page('Another page')
569 assert_not_nil wiki.find_page('Another page')
522 assert_nil wiki.find_page('Another page', :with_redirect => false)
570 assert_nil wiki.find_page('Another page', :with_redirect => false)
523 end
571 end
524
572
525 def test_rename_without_redirect
573 def test_rename_without_redirect
526 @request.session[:user_id] = 2
574 @request.session[:user_id] = 2
527 post :rename, :project_id => 1, :id => 'Another_page',
575 post :rename, :project_id => 1, :id => 'Another_page',
528 :wiki_page => { :title => 'Another renamed page',
576 :wiki_page => { :title => 'Another renamed page',
529 :redirect_existing_links => "0" }
577 :redirect_existing_links => "0" }
530 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
578 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
531 wiki = Project.find(1).wiki
579 wiki = Project.find(1).wiki
532 # Check that there's no redirects
580 # Check that there's no redirects
533 assert_nil wiki.find_page('Another page')
581 assert_nil wiki.find_page('Another page')
534 end
582 end
535
583
536 def test_rename_with_parent_assignment
584 def test_rename_with_parent_assignment
537 @request.session[:user_id] = 2
585 @request.session[:user_id] = 2
538 post :rename, :project_id => 1, :id => 'Another_page',
586 post :rename, :project_id => 1, :id => 'Another_page',
539 :wiki_page => { :title => 'Another page', :redirect_existing_links => "0", :parent_id => '4' }
587 :wiki_page => { :title => 'Another page', :redirect_existing_links => "0", :parent_id => '4' }
540 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
588 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
541 assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
589 assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
542 end
590 end
543
591
544 def test_rename_with_parent_unassignment
592 def test_rename_with_parent_unassignment
545 @request.session[:user_id] = 2
593 @request.session[:user_id] = 2
546 post :rename, :project_id => 1, :id => 'Child_1',
594 post :rename, :project_id => 1, :id => 'Child_1',
547 :wiki_page => { :title => 'Child 1', :redirect_existing_links => "0", :parent_id => '' }
595 :wiki_page => { :title => 'Child 1', :redirect_existing_links => "0", :parent_id => '' }
548 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
596 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
549 assert_nil WikiPage.find_by_title('Child_1').parent
597 assert_nil WikiPage.find_by_title('Child_1').parent
550 end
598 end
551
599
552 def test_destroy_child
600 def test_destroy_child
553 @request.session[:user_id] = 2
601 @request.session[:user_id] = 2
554 delete :destroy, :project_id => 1, :id => 'Child_1'
602 delete :destroy, :project_id => 1, :id => 'Child_1'
555 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
603 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
556 end
604 end
557
605
558 def test_destroy_parent
606 def test_destroy_parent
559 @request.session[:user_id] = 2
607 @request.session[:user_id] = 2
560 assert_no_difference('WikiPage.count') do
608 assert_no_difference('WikiPage.count') do
561 delete :destroy, :project_id => 1, :id => 'Another_page'
609 delete :destroy, :project_id => 1, :id => 'Another_page'
562 end
610 end
563 assert_response :success
611 assert_response :success
564 assert_template 'destroy'
612 assert_template 'destroy'
565 end
613 end
566
614
567 def test_destroy_parent_with_nullify
615 def test_destroy_parent_with_nullify
568 @request.session[:user_id] = 2
616 @request.session[:user_id] = 2
569 assert_difference('WikiPage.count', -1) do
617 assert_difference('WikiPage.count', -1) do
570 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify'
618 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify'
571 end
619 end
572 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
620 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
573 assert_nil WikiPage.find_by_id(2)
621 assert_nil WikiPage.find_by_id(2)
574 end
622 end
575
623
576 def test_destroy_parent_with_cascade
624 def test_destroy_parent_with_cascade
577 @request.session[:user_id] = 2
625 @request.session[:user_id] = 2
578 assert_difference('WikiPage.count', -3) do
626 assert_difference('WikiPage.count', -3) do
579 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy'
627 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy'
580 end
628 end
581 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
629 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
582 assert_nil WikiPage.find_by_id(2)
630 assert_nil WikiPage.find_by_id(2)
583 assert_nil WikiPage.find_by_id(5)
631 assert_nil WikiPage.find_by_id(5)
584 end
632 end
585
633
586 def test_destroy_parent_with_reassign
634 def test_destroy_parent_with_reassign
587 @request.session[:user_id] = 2
635 @request.session[:user_id] = 2
588 assert_difference('WikiPage.count', -1) do
636 assert_difference('WikiPage.count', -1) do
589 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
637 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
590 end
638 end
591 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
639 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
592 assert_nil WikiPage.find_by_id(2)
640 assert_nil WikiPage.find_by_id(2)
593 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
641 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
594 end
642 end
595
643
596 def test_index
644 def test_index
597 get :index, :project_id => 'ecookbook'
645 get :index, :project_id => 'ecookbook'
598 assert_response :success
646 assert_response :success
599 assert_template 'index'
647 assert_template 'index'
600 pages = assigns(:pages)
648 pages = assigns(:pages)
601 assert_not_nil pages
649 assert_not_nil pages
602 assert_equal Project.find(1).wiki.pages.size, pages.size
650 assert_equal Project.find(1).wiki.pages.size, pages.size
603 assert_equal pages.first.content.updated_on, pages.first.updated_on
651 assert_equal pages.first.content.updated_on, pages.first.updated_on
604
652
605 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
653 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
606 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' },
654 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' },
607 :content => 'CookBook documentation' },
655 :content => 'CookBook documentation' },
608 :child => { :tag => 'ul',
656 :child => { :tag => 'ul',
609 :child => { :tag => 'li',
657 :child => { :tag => 'li',
610 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
658 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
611 :content => 'Page with an inline image' } } } },
659 :content => 'Page with an inline image' } } } },
612 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' },
660 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' },
613 :content => 'Another page' } }
661 :content => 'Another page' } }
614 end
662 end
615
663
616 def test_index_should_include_atom_link
664 def test_index_should_include_atom_link
617 get :index, :project_id => 'ecookbook'
665 get :index, :project_id => 'ecookbook'
618 assert_tag 'a', :attributes => { :href => '/projects/ecookbook/activity.atom?show_wiki_edits=1'}
666 assert_tag 'a', :attributes => { :href => '/projects/ecookbook/activity.atom?show_wiki_edits=1'}
619 end
667 end
620
668
621 def test_export_to_html
669 def test_export_to_html
622 @request.session[:user_id] = 2
670 @request.session[:user_id] = 2
623 get :export, :project_id => 'ecookbook'
671 get :export, :project_id => 'ecookbook'
624
672
625 assert_response :success
673 assert_response :success
626 assert_not_nil assigns(:pages)
674 assert_not_nil assigns(:pages)
627 assert assigns(:pages).any?
675 assert assigns(:pages).any?
628 assert_equal "text/html", @response.content_type
676 assert_equal "text/html", @response.content_type
629
677
630 assert_select "a[name=?]", "CookBook_documentation"
678 assert_select "a[name=?]", "CookBook_documentation"
631 assert_select "a[name=?]", "Another_page"
679 assert_select "a[name=?]", "Another_page"
632 assert_select "a[name=?]", "Page_with_an_inline_image"
680 assert_select "a[name=?]", "Page_with_an_inline_image"
633 end
681 end
634
682
635 def test_export_to_pdf
683 def test_export_to_pdf
636 @request.session[:user_id] = 2
684 @request.session[:user_id] = 2
637 get :export, :project_id => 'ecookbook', :format => 'pdf'
685 get :export, :project_id => 'ecookbook', :format => 'pdf'
638
686
639 assert_response :success
687 assert_response :success
640 assert_not_nil assigns(:pages)
688 assert_not_nil assigns(:pages)
641 assert assigns(:pages).any?
689 assert assigns(:pages).any?
642 assert_equal 'application/pdf', @response.content_type
690 assert_equal 'application/pdf', @response.content_type
643 assert_equal 'attachment; filename="ecookbook.pdf"', @response.headers['Content-Disposition']
691 assert_equal 'attachment; filename="ecookbook.pdf"', @response.headers['Content-Disposition']
644 assert @response.body.starts_with?('%PDF')
692 assert @response.body.starts_with?('%PDF')
645 end
693 end
646
694
647 def test_export_without_permission_should_be_denied
695 def test_export_without_permission_should_be_denied
648 @request.session[:user_id] = 2
696 @request.session[:user_id] = 2
649 Role.find_by_name('Manager').remove_permission! :export_wiki_pages
697 Role.find_by_name('Manager').remove_permission! :export_wiki_pages
650 get :export, :project_id => 'ecookbook'
698 get :export, :project_id => 'ecookbook'
651
699
652 assert_response 403
700 assert_response 403
653 end
701 end
654
702
655 def test_date_index
703 def test_date_index
656 get :date_index, :project_id => 'ecookbook'
704 get :date_index, :project_id => 'ecookbook'
657
705
658 assert_response :success
706 assert_response :success
659 assert_template 'date_index'
707 assert_template 'date_index'
660 assert_not_nil assigns(:pages)
708 assert_not_nil assigns(:pages)
661 assert_not_nil assigns(:pages_by_date)
709 assert_not_nil assigns(:pages_by_date)
662
710
663 assert_tag 'a', :attributes => { :href => '/projects/ecookbook/activity.atom?show_wiki_edits=1'}
711 assert_tag 'a', :attributes => { :href => '/projects/ecookbook/activity.atom?show_wiki_edits=1'}
664 end
712 end
665
713
666 def test_not_found
714 def test_not_found
667 get :show, :project_id => 999
715 get :show, :project_id => 999
668 assert_response 404
716 assert_response 404
669 end
717 end
670
718
671 def test_protect_page
719 def test_protect_page
672 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
720 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
673 assert !page.protected?
721 assert !page.protected?
674 @request.session[:user_id] = 2
722 @request.session[:user_id] = 2
675 post :protect, :project_id => 1, :id => page.title, :protected => '1'
723 post :protect, :project_id => 1, :id => page.title, :protected => '1'
676 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
724 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
677 assert page.reload.protected?
725 assert page.reload.protected?
678 end
726 end
679
727
680 def test_unprotect_page
728 def test_unprotect_page
681 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
729 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
682 assert page.protected?
730 assert page.protected?
683 @request.session[:user_id] = 2
731 @request.session[:user_id] = 2
684 post :protect, :project_id => 1, :id => page.title, :protected => '0'
732 post :protect, :project_id => 1, :id => page.title, :protected => '0'
685 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
733 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
686 assert !page.reload.protected?
734 assert !page.reload.protected?
687 end
735 end
688
736
689 def test_show_page_with_edit_link
737 def test_show_page_with_edit_link
690 @request.session[:user_id] = 2
738 @request.session[:user_id] = 2
691 get :show, :project_id => 1
739 get :show, :project_id => 1
692 assert_response :success
740 assert_response :success
693 assert_template 'show'
741 assert_template 'show'
694 assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
742 assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
695 end
743 end
696
744
697 def test_show_page_without_edit_link
745 def test_show_page_without_edit_link
698 @request.session[:user_id] = 4
746 @request.session[:user_id] = 4
699 get :show, :project_id => 1
747 get :show, :project_id => 1
700 assert_response :success
748 assert_response :success
701 assert_template 'show'
749 assert_template 'show'
702 assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
750 assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
703 end
751 end
704
752
705 def test_show_pdf
753 def test_show_pdf
706 @request.session[:user_id] = 2
754 @request.session[:user_id] = 2
707 get :show, :project_id => 1, :format => 'pdf'
755 get :show, :project_id => 1, :format => 'pdf'
708 assert_response :success
756 assert_response :success
709 assert_not_nil assigns(:page)
757 assert_not_nil assigns(:page)
710 assert_equal 'application/pdf', @response.content_type
758 assert_equal 'application/pdf', @response.content_type
711 assert_equal 'attachment; filename="CookBook_documentation.pdf"',
759 assert_equal 'attachment; filename="CookBook_documentation.pdf"',
712 @response.headers['Content-Disposition']
760 @response.headers['Content-Disposition']
713 end
761 end
714
762
715 def test_show_html
763 def test_show_html
716 @request.session[:user_id] = 2
764 @request.session[:user_id] = 2
717 get :show, :project_id => 1, :format => 'html'
765 get :show, :project_id => 1, :format => 'html'
718 assert_response :success
766 assert_response :success
719 assert_not_nil assigns(:page)
767 assert_not_nil assigns(:page)
720 assert_equal 'text/html', @response.content_type
768 assert_equal 'text/html', @response.content_type
721 assert_equal 'attachment; filename="CookBook_documentation.html"',
769 assert_equal 'attachment; filename="CookBook_documentation.html"',
722 @response.headers['Content-Disposition']
770 @response.headers['Content-Disposition']
723 end
771 end
724
772
725 def test_show_txt
773 def test_show_txt
726 @request.session[:user_id] = 2
774 @request.session[:user_id] = 2
727 get :show, :project_id => 1, :format => 'txt'
775 get :show, :project_id => 1, :format => 'txt'
728 assert_response :success
776 assert_response :success
729 assert_not_nil assigns(:page)
777 assert_not_nil assigns(:page)
730 assert_equal 'text/plain', @response.content_type
778 assert_equal 'text/plain', @response.content_type
731 assert_equal 'attachment; filename="CookBook_documentation.txt"',
779 assert_equal 'attachment; filename="CookBook_documentation.txt"',
732 @response.headers['Content-Disposition']
780 @response.headers['Content-Disposition']
733 end
781 end
734
782
735 def test_edit_unprotected_page
783 def test_edit_unprotected_page
736 # Non members can edit unprotected wiki pages
784 # Non members can edit unprotected wiki pages
737 @request.session[:user_id] = 4
785 @request.session[:user_id] = 4
738 get :edit, :project_id => 1, :id => 'Another_page'
786 get :edit, :project_id => 1, :id => 'Another_page'
739 assert_response :success
787 assert_response :success
740 assert_template 'edit'
788 assert_template 'edit'
741 end
789 end
742
790
743 def test_edit_protected_page_by_nonmember
791 def test_edit_protected_page_by_nonmember
744 # Non members can't edit protected wiki pages
792 # Non members can't edit protected wiki pages
745 @request.session[:user_id] = 4
793 @request.session[:user_id] = 4
746 get :edit, :project_id => 1, :id => 'CookBook_documentation'
794 get :edit, :project_id => 1, :id => 'CookBook_documentation'
747 assert_response 403
795 assert_response 403
748 end
796 end
749
797
750 def test_edit_protected_page_by_member
798 def test_edit_protected_page_by_member
751 @request.session[:user_id] = 2
799 @request.session[:user_id] = 2
752 get :edit, :project_id => 1, :id => 'CookBook_documentation'
800 get :edit, :project_id => 1, :id => 'CookBook_documentation'
753 assert_response :success
801 assert_response :success
754 assert_template 'edit'
802 assert_template 'edit'
755 end
803 end
756
804
757 def test_history_of_non_existing_page_should_return_404
805 def test_history_of_non_existing_page_should_return_404
758 get :history, :project_id => 1, :id => 'Unknown_page'
806 get :history, :project_id => 1, :id => 'Unknown_page'
759 assert_response 404
807 assert_response 404
760 end
808 end
761
809
762 def test_add_attachment
810 def test_add_attachment
763 @request.session[:user_id] = 2
811 @request.session[:user_id] = 2
764 assert_difference 'Attachment.count' do
812 assert_difference 'Attachment.count' do
765 post :add_attachment, :project_id => 1, :id => 'CookBook_documentation',
813 post :add_attachment, :project_id => 1, :id => 'CookBook_documentation',
766 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
814 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
767 end
815 end
768 attachment = Attachment.first(:order => 'id DESC')
816 attachment = Attachment.first(:order => 'id DESC')
769 assert_equal Wiki.find(1).find_page('CookBook_documentation'), attachment.container
817 assert_equal Wiki.find(1).find_page('CookBook_documentation'), attachment.container
770 end
818 end
771 end
819 end
General Comments 0
You need to be logged in to leave comments. Login now