##// END OF EJS Templates
Move wiki page to other project (#5450)....
Jean-Philippe Lang -
r13261:e0a034164f34
parent child
Show More
@@ -0,0 +1,11
1 class AddWikiRedirectsRedirectsToWikiId < ActiveRecord::Migration
2 def self.up
3 add_column :wiki_redirects, :redirects_to_wiki_id, :integer
4 WikiRedirect.update_all "redirects_to_wiki_id = wiki_id"
5 change_column :wiki_redirects, :redirects_to_wiki_id, :integer, :null => false
6 end
7
8 def self.down
9 remove_column :wiki_redirects, :redirects_to_wiki_id
10 end
11 end
@@ -1,369 +1,374
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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 # The WikiController follows the Rails REST controller pattern but with
18 # The WikiController follows the Rails REST controller pattern but with
19 # a few differences
19 # a few differences
20 #
20 #
21 # * index - shows a list of WikiPages grouped by page or date
21 # * index - shows a list of WikiPages grouped by page or date
22 # * new - not used
22 # * new - not used
23 # * create - not used
23 # * create - not used
24 # * show - will also show the form for creating a new wiki page
24 # * show - will also show the form for creating a new wiki page
25 # * edit - used to edit an existing or new page
25 # * edit - used to edit an existing or new page
26 # * update - used to save a wiki page update to the database, including new pages
26 # * update - used to save a wiki page update to the database, including new pages
27 # * destroy - normal
27 # * destroy - normal
28 #
28 #
29 # Other member and collection methods are also used
29 # Other member and collection methods are also used
30 #
30 #
31 # TODO: still being worked on
31 # TODO: still being worked on
32 class WikiController < ApplicationController
32 class WikiController < ApplicationController
33 default_search_scope :wiki_pages
33 default_search_scope :wiki_pages
34 before_filter :find_wiki, :authorize
34 before_filter :find_wiki, :authorize
35 before_filter :find_existing_or_new_page, :only => [:show, :edit, :update]
35 before_filter :find_existing_or_new_page, :only => [:show, :edit, :update]
36 before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version]
36 before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version]
37 accept_api_auth :index, :show, :update, :destroy
37 accept_api_auth :index, :show, :update, :destroy
38 before_filter :find_attachments, :only => [:preview]
38 before_filter :find_attachments, :only => [:preview]
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
48
49 respond_to do |format|
49 respond_to do |format|
50 format.html {
50 format.html {
51 @pages_by_parent_id = @pages.group_by(&:parent_id)
51 @pages_by_parent_id = @pages.group_by(&:parent_id)
52 }
52 }
53 format.api
53 format.api
54 end
54 end
55 end
55 end
56
56
57 # List of page, by last update
57 # List of page, by last update
58 def date_index
58 def date_index
59 load_pages_for_index
59 load_pages_for_index
60 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
60 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
61 end
61 end
62
62
63 # display a page (in editing mode if it doesn't exist)
63 # display a page (in editing mode if it doesn't exist)
64 def show
64 def show
65 if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
65 if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
66 deny_access
66 deny_access
67 return
67 return
68 end
68 end
69 @content = @page.content_for_version(params[:version])
69 @content = @page.content_for_version(params[:version])
70 if @content.nil?
70 if @content.nil?
71 if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? && !api_request?
71 if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? && !api_request?
72 edit
72 edit
73 render :action => 'edit'
73 render :action => 'edit'
74 else
74 else
75 render_404
75 render_404
76 end
76 end
77 return
77 return
78 end
78 end
79 if User.current.allowed_to?(:export_wiki_pages, @project)
79 if User.current.allowed_to?(:export_wiki_pages, @project)
80 if params[:format] == 'pdf'
80 if params[:format] == 'pdf'
81 send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
81 send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
82 return
82 return
83 elsif params[:format] == 'html'
83 elsif params[:format] == 'html'
84 export = render_to_string :action => 'export', :layout => false
84 export = render_to_string :action => 'export', :layout => false
85 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
85 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
86 return
86 return
87 elsif params[:format] == 'txt'
87 elsif params[:format] == 'txt'
88 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
88 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
89 return
89 return
90 end
90 end
91 end
91 end
92 @editable = editable?
92 @editable = editable?
93 @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) &&
93 @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) &&
94 @content.current_version? &&
94 @content.current_version? &&
95 Redmine::WikiFormatting.supports_section_edit?
95 Redmine::WikiFormatting.supports_section_edit?
96
96
97 respond_to do |format|
97 respond_to do |format|
98 format.html
98 format.html
99 format.api
99 format.api
100 end
100 end
101 end
101 end
102
102
103 # edit an existing page or a new one
103 # edit an existing page or a new one
104 def edit
104 def edit
105 return render_403 unless editable?
105 return render_403 unless editable?
106 if @page.new_record?
106 if @page.new_record?
107 if params[:parent].present?
107 if params[:parent].present?
108 @page.parent = @page.wiki.find_page(params[:parent].to_s)
108 @page.parent = @page.wiki.find_page(params[:parent].to_s)
109 end
109 end
110 end
110 end
111
111
112 @content = @page.content_for_version(params[:version])
112 @content = @page.content_for_version(params[:version])
113 @content ||= WikiContent.new(:page => @page)
113 @content ||= WikiContent.new(:page => @page)
114 @content.text = initial_page_content(@page) if @content.text.blank?
114 @content.text = initial_page_content(@page) if @content.text.blank?
115 # don't keep previous comment
115 # don't keep previous comment
116 @content.comments = nil
116 @content.comments = nil
117
117
118 # To prevent StaleObjectError exception when reverting to a previous version
118 # To prevent StaleObjectError exception when reverting to a previous version
119 @content.version = @page.content.version if @page.content
119 @content.version = @page.content.version if @page.content
120
120
121 @text = @content.text
121 @text = @content.text
122 if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
122 if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
123 @section = params[:section].to_i
123 @section = params[:section].to_i
124 @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section)
124 @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section)
125 render_404 if @text.blank?
125 render_404 if @text.blank?
126 end
126 end
127 end
127 end
128
128
129 # Creates a new page or updates an existing one
129 # Creates a new page or updates an existing one
130 def update
130 def update
131 return render_403 unless editable?
131 return render_403 unless editable?
132 was_new_page = @page.new_record?
132 was_new_page = @page.new_record?
133 @page.safe_attributes = params[:wiki_page]
133 @page.safe_attributes = params[:wiki_page]
134
134
135 @content = @page.content || WikiContent.new(:page => @page)
135 @content = @page.content || WikiContent.new(:page => @page)
136 content_params = params[:content]
136 content_params = params[:content]
137 if content_params.nil? && params[:wiki_page].is_a?(Hash)
137 if content_params.nil? && params[:wiki_page].is_a?(Hash)
138 content_params = params[:wiki_page].slice(:text, :comments, :version)
138 content_params = params[:wiki_page].slice(:text, :comments, :version)
139 end
139 end
140 content_params ||= {}
140 content_params ||= {}
141
141
142 @content.comments = content_params[:comments]
142 @content.comments = content_params[:comments]
143 @text = content_params[:text]
143 @text = content_params[:text]
144 if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
144 if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
145 @section = params[:section].to_i
145 @section = params[:section].to_i
146 @section_hash = params[:section_hash]
146 @section_hash = params[:section_hash]
147 @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(@section, @text, @section_hash)
147 @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(@section, @text, @section_hash)
148 else
148 else
149 @content.version = content_params[:version] if content_params[:version]
149 @content.version = content_params[:version] if content_params[:version]
150 @content.text = @text
150 @content.text = @text
151 end
151 end
152 @content.author = User.current
152 @content.author = User.current
153
153
154 if @page.save_with_content(@content)
154 if @page.save_with_content(@content)
155 attachments = Attachment.attach_files(@page, params[:attachments])
155 attachments = Attachment.attach_files(@page, params[:attachments])
156 render_attachment_warning_if_needed(@page)
156 render_attachment_warning_if_needed(@page)
157 call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
157 call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
158
158
159 respond_to do |format|
159 respond_to do |format|
160 format.html {
160 format.html {
161 anchor = @section ? "section-#{@section}" : nil
161 anchor = @section ? "section-#{@section}" : nil
162 redirect_to project_wiki_page_path(@project, @page.title, :anchor => anchor)
162 redirect_to project_wiki_page_path(@project, @page.title, :anchor => anchor)
163 }
163 }
164 format.api {
164 format.api {
165 if was_new_page
165 if was_new_page
166 render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title)
166 render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title)
167 else
167 else
168 render_api_ok
168 render_api_ok
169 end
169 end
170 }
170 }
171 end
171 end
172 else
172 else
173 respond_to do |format|
173 respond_to do |format|
174 format.html { render :action => 'edit' }
174 format.html { render :action => 'edit' }
175 format.api { render_validation_errors(@content) }
175 format.api { render_validation_errors(@content) }
176 end
176 end
177 end
177 end
178
178
179 rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError
179 rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError
180 # Optimistic locking exception
180 # Optimistic locking exception
181 respond_to do |format|
181 respond_to do |format|
182 format.html {
182 format.html {
183 flash.now[:error] = l(:notice_locking_conflict)
183 flash.now[:error] = l(:notice_locking_conflict)
184 render :action => 'edit'
184 render :action => 'edit'
185 }
185 }
186 format.api { render_api_head :conflict }
186 format.api { render_api_head :conflict }
187 end
187 end
188 rescue ActiveRecord::RecordNotSaved
188 rescue ActiveRecord::RecordNotSaved
189 respond_to do |format|
189 respond_to do |format|
190 format.html { render :action => 'edit' }
190 format.html { render :action => 'edit' }
191 format.api { render_validation_errors(@content) }
191 format.api { render_validation_errors(@content) }
192 end
192 end
193 end
193 end
194
194
195 # rename a page
195 # rename a page
196 def rename
196 def rename
197 return render_403 unless editable?
197 return render_403 unless editable?
198 @page.redirect_existing_links = true
198 @page.redirect_existing_links = true
199 # used to display the *original* title if some AR validation errors occur
199 # used to display the *original* title if some AR validation errors occur
200 @original_title = @page.pretty_title
200 @original_title = @page.pretty_title
201 if request.post? && @page.update_attributes(params[:wiki_page])
201 @page.safe_attributes = params[:wiki_page]
202 if request.post? && @page.save
202 flash[:notice] = l(:notice_successful_update)
203 flash[:notice] = l(:notice_successful_update)
203 redirect_to project_wiki_page_path(@project, @page.title)
204 redirect_to project_wiki_page_path(@page.project, @page.title)
204 end
205 end
205 end
206 end
206
207
207 def protect
208 def protect
208 @page.update_attribute :protected, params[:protected]
209 @page.update_attribute :protected, params[:protected]
209 redirect_to project_wiki_page_path(@project, @page.title)
210 redirect_to project_wiki_page_path(@project, @page.title)
210 end
211 end
211
212
212 # show page history
213 # show page history
213 def history
214 def history
214 @version_count = @page.content.versions.count
215 @version_count = @page.content.versions.count
215 @version_pages = Paginator.new @version_count, per_page_option, params['page']
216 @version_pages = Paginator.new @version_count, per_page_option, params['page']
216 # don't load text
217 # don't load text
217 @versions = @page.content.versions.
218 @versions = @page.content.versions.
218 select("id, author_id, comments, updated_on, version").
219 select("id, author_id, comments, updated_on, version").
219 reorder('version DESC').
220 reorder('version DESC').
220 limit(@version_pages.per_page + 1).
221 limit(@version_pages.per_page + 1).
221 offset(@version_pages.offset).
222 offset(@version_pages.offset).
222 to_a
223 to_a
223
224
224 render :layout => false if request.xhr?
225 render :layout => false if request.xhr?
225 end
226 end
226
227
227 def diff
228 def diff
228 @diff = @page.diff(params[:version], params[:version_from])
229 @diff = @page.diff(params[:version], params[:version_from])
229 render_404 unless @diff
230 render_404 unless @diff
230 end
231 end
231
232
232 def annotate
233 def annotate
233 @annotate = @page.annotate(params[:version])
234 @annotate = @page.annotate(params[:version])
234 render_404 unless @annotate
235 render_404 unless @annotate
235 end
236 end
236
237
237 # Removes a wiki page and its history
238 # Removes a wiki page and its history
238 # Children can be either set as root pages, removed or reassigned to another parent page
239 # Children can be either set as root pages, removed or reassigned to another parent page
239 def destroy
240 def destroy
240 return render_403 unless editable?
241 return render_403 unless editable?
241
242
242 @descendants_count = @page.descendants.size
243 @descendants_count = @page.descendants.size
243 if @descendants_count > 0
244 if @descendants_count > 0
244 case params[:todo]
245 case params[:todo]
245 when 'nullify'
246 when 'nullify'
246 # Nothing to do
247 # Nothing to do
247 when 'destroy'
248 when 'destroy'
248 # Removes all its descendants
249 # Removes all its descendants
249 @page.descendants.each(&:destroy)
250 @page.descendants.each(&:destroy)
250 when 'reassign'
251 when 'reassign'
251 # Reassign children to another parent page
252 # Reassign children to another parent page
252 reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
253 reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
253 return unless reassign_to
254 return unless reassign_to
254 @page.children.each do |child|
255 @page.children.each do |child|
255 child.update_attribute(:parent, reassign_to)
256 child.update_attribute(:parent, reassign_to)
256 end
257 end
257 else
258 else
258 @reassignable_to = @wiki.pages - @page.self_and_descendants
259 @reassignable_to = @wiki.pages - @page.self_and_descendants
259 # display the destroy form if it's a user request
260 # display the destroy form if it's a user request
260 return unless api_request?
261 return unless api_request?
261 end
262 end
262 end
263 end
263 @page.destroy
264 @page.destroy
264 respond_to do |format|
265 respond_to do |format|
265 format.html { redirect_to project_wiki_index_path(@project) }
266 format.html { redirect_to project_wiki_index_path(@project) }
266 format.api { render_api_ok }
267 format.api { render_api_ok }
267 end
268 end
268 end
269 end
269
270
270 def destroy_version
271 def destroy_version
271 return render_403 unless editable?
272 return render_403 unless editable?
272
273
273 @content = @page.content_for_version(params[:version])
274 @content = @page.content_for_version(params[:version])
274 @content.destroy
275 @content.destroy
275 redirect_to_referer_or history_project_wiki_page_path(@project, @page.title)
276 redirect_to_referer_or history_project_wiki_page_path(@project, @page.title)
276 end
277 end
277
278
278 # Export wiki to a single pdf or html file
279 # Export wiki to a single pdf or html file
279 def export
280 def export
280 @pages = @wiki.pages.
281 @pages = @wiki.pages.
281 order('title').
282 order('title').
282 includes([:content, {:attachments => :author}]).
283 includes([:content, {:attachments => :author}]).
283 to_a
284 to_a
284 respond_to do |format|
285 respond_to do |format|
285 format.html {
286 format.html {
286 export = render_to_string :action => 'export_multiple', :layout => false
287 export = render_to_string :action => 'export_multiple', :layout => false
287 send_data(export, :type => 'text/html', :filename => "wiki.html")
288 send_data(export, :type => 'text/html', :filename => "wiki.html")
288 }
289 }
289 format.pdf {
290 format.pdf {
290 send_data(wiki_pages_to_pdf(@pages, @project),
291 send_data(wiki_pages_to_pdf(@pages, @project),
291 :type => 'application/pdf',
292 :type => 'application/pdf',
292 :filename => "#{@project.identifier}.pdf")
293 :filename => "#{@project.identifier}.pdf")
293 }
294 }
294 end
295 end
295 end
296 end
296
297
297 def preview
298 def preview
298 page = @wiki.find_page(params[:id])
299 page = @wiki.find_page(params[:id])
299 # page is nil when previewing a new page
300 # page is nil when previewing a new page
300 return render_403 unless page.nil? || editable?(page)
301 return render_403 unless page.nil? || editable?(page)
301 if page
302 if page
302 @attachments += page.attachments
303 @attachments += page.attachments
303 @previewed = page.content
304 @previewed = page.content
304 end
305 end
305 @text = params[:content][:text]
306 @text = params[:content][:text]
306 render :partial => 'common/preview'
307 render :partial => 'common/preview'
307 end
308 end
308
309
309 def add_attachment
310 def add_attachment
310 return render_403 unless editable?
311 return render_403 unless editable?
311 attachments = Attachment.attach_files(@page, params[:attachments])
312 attachments = Attachment.attach_files(@page, params[:attachments])
312 render_attachment_warning_if_needed(@page)
313 render_attachment_warning_if_needed(@page)
313 redirect_to :action => 'show', :id => @page.title, :project_id => @project
314 redirect_to :action => 'show', :id => @page.title, :project_id => @project
314 end
315 end
315
316
316 private
317 private
317
318
318 def find_wiki
319 def find_wiki
319 @project = Project.find(params[:project_id])
320 @project = Project.find(params[:project_id])
320 @wiki = @project.wiki
321 @wiki = @project.wiki
321 render_404 unless @wiki
322 render_404 unless @wiki
322 rescue ActiveRecord::RecordNotFound
323 rescue ActiveRecord::RecordNotFound
323 render_404
324 render_404
324 end
325 end
325
326
326 # Finds the requested page or a new page if it doesn't exist
327 # Finds the requested page or a new page if it doesn't exist
327 def find_existing_or_new_page
328 def find_existing_or_new_page
328 @page = @wiki.find_or_new_page(params[:id])
329 @page = @wiki.find_or_new_page(params[:id])
329 if @wiki.page_found_with_redirect?
330 if @wiki.page_found_with_redirect?
330 redirect_to_page @page
331 redirect_to_page @page
331 end
332 end
332 end
333 end
333
334
334 # Finds the requested page and returns a 404 error if it doesn't exist
335 # Finds the requested page and returns a 404 error if it doesn't exist
335 def find_existing_page
336 def find_existing_page
336 @page = @wiki.find_page(params[:id])
337 @page = @wiki.find_page(params[:id])
337 if @page.nil?
338 if @page.nil?
338 render_404
339 render_404
339 return
340 return
340 end
341 end
341 if @wiki.page_found_with_redirect?
342 if @wiki.page_found_with_redirect?
342 redirect_to_page @page
343 redirect_to_page @page
343 end
344 end
344 end
345 end
345
346
346 def redirect_to_page(page)
347 def redirect_to_page(page)
347 redirect_to :action => action_name, :project_id => page.wiki.project, :id => page.title
348 if page.project && page.project.visible?
349 redirect_to :action => action_name, :project_id => page.project, :id => page.title
350 else
351 render_404
352 end
348 end
353 end
349
354
350 # Returns true if the current user is allowed to edit the page, otherwise false
355 # Returns true if the current user is allowed to edit the page, otherwise false
351 def editable?(page = @page)
356 def editable?(page = @page)
352 page.editable_by?(User.current)
357 page.editable_by?(User.current)
353 end
358 end
354
359
355 # Returns the default content of a new wiki page
360 # Returns the default content of a new wiki page
356 def initial_page_content(page)
361 def initial_page_content(page)
357 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
362 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
358 extend helper unless self.instance_of?(helper)
363 extend helper unless self.instance_of?(helper)
359 helper.instance_method(:initial_page_content).bind(self).call(page)
364 helper.instance_method(:initial_page_content).bind(self).call(page)
360 end
365 end
361
366
362 def load_pages_for_index
367 def load_pages_for_index
363 @pages = @wiki.pages.with_updated_on.
368 @pages = @wiki.pages.with_updated_on.
364 reorder("#{WikiPage.table_name}.title").
369 reorder("#{WikiPage.table_name}.title").
365 includes(:wiki => :project).
370 includes(:wiki => :project).
366 includes(:parent).
371 includes(:parent).
367 to_a
372 to_a
368 end
373 end
369 end
374 end
@@ -1,43 +1,53
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2014 Jean-Philippe Lang
4 # Copyright (C) 2006-2014 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 module WikiHelper
20 module WikiHelper
21
21
22 def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0)
22 def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0)
23 pages = pages.group_by(&:parent) unless pages.is_a?(Hash)
23 pages = pages.group_by(&:parent) unless pages.is_a?(Hash)
24 s = ''.html_safe
24 s = ''.html_safe
25 if pages.has_key?(parent)
25 if pages.has_key?(parent)
26 pages[parent].each do |page|
26 pages[parent].each do |page|
27 attrs = "value='#{page.id}'"
27 attrs = "value='#{page.id}'"
28 attrs << " selected='selected'" if selected == page
28 attrs << " selected='selected'" if selected == page
29 indent = (level > 0) ? ('&nbsp;' * level * 2 + '&#187; ') : ''
29 indent = (level > 0) ? ('&nbsp;' * level * 2 + '&#187; ') : ''
30
30
31 s << content_tag('option', (indent + h(page.pretty_title)).html_safe, :value => page.id.to_s, :selected => selected == page) +
31 s << content_tag('option', (indent + h(page.pretty_title)).html_safe, :value => page.id.to_s, :selected => selected == page) +
32 wiki_page_options_for_select(pages, selected, page, level + 1)
32 wiki_page_options_for_select(pages, selected, page, level + 1)
33 end
33 end
34 end
34 end
35 s
35 s
36 end
36 end
37
37
38 def wiki_page_wiki_options_for_select(page)
39 projects = Project.allowed_to(:rename_wiki_pages).joins(:wiki).preload(:wiki).to_a
40 projects << page.project unless projects.include?(page.project)
41
42 project_tree_options_for_select(projects, :selected => page.project) do |project|
43 wiki_id = project.wiki.try(:id)
44 {:value => wiki_id, :selected => wiki_id == page.wiki_id}
45 end
46 end
47
38 def wiki_page_breadcrumb(page)
48 def wiki_page_breadcrumb(page)
39 breadcrumb(page.ancestors.reverse.collect {|parent|
49 breadcrumb(page.ancestors.reverse.collect {|parent|
40 link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project, :version => nil})
50 link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project, :version => nil})
41 })
51 })
42 end
52 end
43 end
53 end
@@ -1,98 +1,106
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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 class Wiki < ActiveRecord::Base
18 class Wiki < ActiveRecord::Base
19 include Redmine::SafeAttributes
19 include Redmine::SafeAttributes
20 belongs_to :project
20 belongs_to :project
21 has_many :pages, lambda {order('title')}, :class_name => 'WikiPage', :dependent => :destroy
21 has_many :pages, lambda {order('title')}, :class_name => 'WikiPage', :dependent => :destroy
22 has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
22 has_many :redirects, :class_name => 'WikiRedirect'
23
23
24 acts_as_watchable
24 acts_as_watchable
25
25
26 validates_presence_of :start_page
26 validates_presence_of :start_page
27 validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/
27 validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/
28 attr_protected :id
28 attr_protected :id
29
29
30 before_destroy :delete_redirects
31
30 safe_attributes 'start_page'
32 safe_attributes 'start_page'
31
33
32 def visible?(user=User.current)
34 def visible?(user=User.current)
33 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
35 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
34 end
36 end
35
37
36 # Returns the wiki page that acts as the sidebar content
38 # Returns the wiki page that acts as the sidebar content
37 # or nil if no such page exists
39 # or nil if no such page exists
38 def sidebar
40 def sidebar
39 @sidebar ||= find_page('Sidebar', :with_redirect => false)
41 @sidebar ||= find_page('Sidebar', :with_redirect => false)
40 end
42 end
41
43
42 # find the page with the given title
44 # find the page with the given title
43 # if page doesn't exist, return a new page
45 # if page doesn't exist, return a new page
44 def find_or_new_page(title)
46 def find_or_new_page(title)
45 title = start_page if title.blank?
47 title = start_page if title.blank?
46 find_page(title) || WikiPage.new(:wiki => self, :title => Wiki.titleize(title))
48 find_page(title) || WikiPage.new(:wiki => self, :title => Wiki.titleize(title))
47 end
49 end
48
50
49 # find the page with the given title
51 # find the page with the given title
50 def find_page(title, options = {})
52 def find_page(title, options = {})
51 @page_found_with_redirect = false
53 @page_found_with_redirect = false
52 title = start_page if title.blank?
54 title = start_page if title.blank?
53 title = Wiki.titleize(title)
55 title = Wiki.titleize(title)
54 page = pages.where("LOWER(title) = LOWER(?)", title).first
56 page = pages.where("LOWER(title) = LOWER(?)", title).first
55 if !page && !(options[:with_redirect] == false)
57 if page.nil? && options[:with_redirect] != false
56 # search for a redirect
58 # search for a redirect
57 redirect = redirects.where("LOWER(title) = LOWER(?)", title).first
59 redirect = redirects.where("LOWER(title) = LOWER(?)", title).first
58 if redirect
60 if redirect
59 page = find_page(redirect.redirects_to, :with_redirect => false)
61 page = redirect.target_page
60 @page_found_with_redirect = true
62 @page_found_with_redirect = true
61 end
63 end
62 end
64 end
63 page
65 page
64 end
66 end
65
67
66 # Returns true if the last page was found with a redirect
68 # Returns true if the last page was found with a redirect
67 def page_found_with_redirect?
69 def page_found_with_redirect?
68 @page_found_with_redirect
70 @page_found_with_redirect
69 end
71 end
70
72
73 # Deletes all redirects from/to the wiki
74 def delete_redirects
75 WikiRedirect.where(:wiki_id => id).delete_all
76 WikiRedirect.where(:redirects_to_wiki_id => id).delete_all
77 end
78
71 # Finds a page by title
79 # Finds a page by title
72 # The given string can be of one of the forms: "title" or "project:title"
80 # The given string can be of one of the forms: "title" or "project:title"
73 # Examples:
81 # Examples:
74 # Wiki.find_page("bar", project => foo)
82 # Wiki.find_page("bar", project => foo)
75 # Wiki.find_page("foo:bar")
83 # Wiki.find_page("foo:bar")
76 def self.find_page(title, options = {})
84 def self.find_page(title, options = {})
77 project = options[:project]
85 project = options[:project]
78 if title.to_s =~ %r{^([^\:]+)\:(.*)$}
86 if title.to_s =~ %r{^([^\:]+)\:(.*)$}
79 project_identifier, title = $1, $2
87 project_identifier, title = $1, $2
80 project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)
88 project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)
81 end
89 end
82 if project && project.wiki
90 if project && project.wiki
83 page = project.wiki.find_page(title)
91 page = project.wiki.find_page(title)
84 if page && page.content
92 if page && page.content
85 page
93 page
86 end
94 end
87 end
95 end
88 end
96 end
89
97
90 # turn a string into a valid page title
98 # turn a string into a valid page title
91 def self.titleize(title)
99 def self.titleize(title)
92 # replace spaces with _ and remove unwanted caracters
100 # replace spaces with _ and remove unwanted caracters
93 title = title.gsub(/\s+/, '_').delete(',./?;|:') if title
101 title = title.gsub(/\s+/, '_').delete(',./?;|:') if title
94 # upcase the first letter
102 # upcase the first letter
95 title = (title.slice(0..0).upcase + (title.slice(1..-1) || '')) if title
103 title = (title.slice(0..0).upcase + (title.slice(1..-1) || '')) if title
96 title
104 title
97 end
105 end
98 end
106 end
@@ -1,253 +1,293
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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
22 include Redmine::SafeAttributes
23
23
24 belongs_to :wiki
24 belongs_to :wiki
25 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
26 acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
26 acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
27 acts_as_tree :dependent => :nullify, :order => 'title'
27 acts_as_tree :dependent => :nullify, :order => 'title'
28
28
29 acts_as_watchable
29 acts_as_watchable
30 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}"},
31 :description => :text,
31 :description => :text,
32 :datetime => :created_on,
32 :datetime => :created_on,
33 :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}}
34
34
35 acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
35 acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
36 :scope => preload(:wiki => :project).joins(:content, {:wiki => :project}),
36 :scope => preload(:wiki => :project).joins(:content, {:wiki => :project}),
37 :permission => :view_wiki_pages,
37 :permission => :view_wiki_pages,
38 :project_key => "#{Wiki.table_name}.project_id"
38 :project_key => "#{Wiki.table_name}.project_id"
39
39
40 attr_accessor :redirect_existing_links
40 attr_accessor :redirect_existing_links
41
41
42 validates_presence_of :title
42 validates_presence_of :title
43 validates_format_of :title, :with => /\A[^,\.\/\?\;\|\s]*\z/
43 validates_format_of :title, :with => /\A[^,\.\/\?\;\|\s]*\z/
44 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
44 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
45 validates_associated :content
45 validates_associated :content
46 attr_protected :id
46 attr_protected :id
47
47
48 validate :validate_parent_title
48 validate :validate_parent_title
49 before_destroy :remove_redirects
49 before_destroy :delete_redirects
50 before_save :handle_redirects
50 before_save :handle_rename_or_move
51 after_save :handle_children_move
51
52
52 # eager load information about last updates, without loading text
53 # eager load information about last updates, without loading text
53 scope :with_updated_on, lambda {
54 scope :with_updated_on, lambda {
54 select("#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on, #{WikiContent.table_name}.version").
55 select("#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on, #{WikiContent.table_name}.version").
55 joins("LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id")
56 joins("LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id")
56 }
57 }
57
58
58 # Wiki pages that are protected by default
59 # Wiki pages that are protected by default
59 DEFAULT_PROTECTED_PAGES = %w(sidebar)
60 DEFAULT_PROTECTED_PAGES = %w(sidebar)
60
61
61 safe_attributes 'parent_id', 'parent_title',
62 safe_attributes 'parent_id', 'parent_title', 'title', 'redirect_existing_links', 'wiki_id',
62 :if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)}
63 :if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)}
63
64
64 def initialize(attributes=nil, *args)
65 def initialize(attributes=nil, *args)
65 super
66 super
66 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
67 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
67 self.protected = true
68 self.protected = true
68 end
69 end
69 end
70 end
70
71
71 def visible?(user=User.current)
72 def visible?(user=User.current)
72 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
73 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
73 end
74 end
74
75
75 def title=(value)
76 def title=(value)
76 value = Wiki.titleize(value)
77 value = Wiki.titleize(value)
77 @previous_title = read_attribute(:title) if @previous_title.blank?
78 write_attribute(:title, value)
78 write_attribute(:title, value)
79 end
79 end
80
80
81 def handle_redirects
81 def safe_attributes=(attrs, user=User.current)
82 self.title = Wiki.titleize(title)
82 return unless attrs.is_a?(Hash)
83 # Manage redirects if the title has changed
83 attrs = attrs.deep_dup
84 if !@previous_title.blank? && (@previous_title != title) && !new_record?
84
85 # Project and Tracker must be set before since new_statuses_allowed_to depends on it.
86 if (w_id = attrs.delete('wiki_id')) && safe_attribute?('wiki_id')
87 if (w = Wiki.find_by_id(w_id)) && w.project && user.allowed_to?(:rename_wiki_pages, w.project)
88 self.wiki = w
89 end
90 end
91
92 super attrs, user
93 end
94
95 # Manages redirects if page is renamed or moved
96 def handle_rename_or_move
97 if !new_record? && (title_changed? || wiki_id_changed?)
85 # Update redirects that point to the old title
98 # Update redirects that point to the old title
86 wiki.redirects.where(:redirects_to => @previous_title).each do |r|
99 WikiRedirect.where(:redirects_to => title_was, :redirects_to_wiki_id => wiki_id_was).each do |r|
87 r.redirects_to = title
100 r.redirects_to = title
88 r.title == r.redirects_to ? r.destroy : r.save
101 r.redirects_to_wiki_id = wiki_id
102 (r.title == r.redirects_to && r.wiki_id == r.redirects_to_wiki_id) ? r.destroy : r.save
89 end
103 end
90 # Remove redirects for the new title
104 # Remove redirects for the new title
91 wiki.redirects.where(:title => title).each(&:destroy)
105 WikiRedirect.where(:wiki_id => wiki_id, :title => title).delete_all
92 # Create a redirect to the new title
106 # Create a redirect to the new title
93 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
107 unless redirect_existing_links == "0"
94 @previous_title = nil
108 WikiRedirect.create(
109 :wiki_id => wiki_id_was, :title => title_was,
110 :redirects_to_wiki_id => wiki_id, :redirects_to => title
111 )
112 end
113 end
114 if !new_record? && wiki_id_changed? && parent.present?
115 unless parent.wiki_id == wiki_id
116 self.parent_id = nil
117 end
95 end
118 end
96 end
119 end
120 private :handle_rename_or_move
121
122 # Moves child pages if page was moved
123 def handle_children_move
124 if !new_record? && wiki_id_changed?
125 children.each do |child|
126 child.wiki_id = wiki_id
127 child.redirect_existing_links = redirect_existing_links
128 unless child.save
129 WikiPage.where(:id => child.id).update_all :parent_nil => nil
130 end
131 end
132 end
133 end
134 private :handle_children_move
97
135
98 def remove_redirects
136 # Deletes redirects to this page
99 # Remove redirects to this page
137 def delete_redirects
100 wiki.redirects.where(:redirects_to => title).each(&:destroy)
138 WikiRedirect.where(:redirects_to_wiki_id => wiki_id, :redirects_to => title).delete_all
101 end
139 end
102
140
103 def pretty_title
141 def pretty_title
104 WikiPage.pretty_title(title)
142 WikiPage.pretty_title(title)
105 end
143 end
106
144
107 def content_for_version(version=nil)
145 def content_for_version(version=nil)
108 if content
146 if content
109 result = content.versions.find_by_version(version.to_i) if version
147 result = content.versions.find_by_version(version.to_i) if version
110 result ||= content
148 result ||= content
111 result
149 result
112 end
150 end
113 end
151 end
114
152
115 def diff(version_to=nil, version_from=nil)
153 def diff(version_to=nil, version_from=nil)
116 version_to = version_to ? version_to.to_i : self.content.version
154 version_to = version_to ? version_to.to_i : self.content.version
117 content_to = content.versions.find_by_version(version_to)
155 content_to = content.versions.find_by_version(version_to)
118 content_from = version_from ? content.versions.find_by_version(version_from.to_i) : content_to.try(:previous)
156 content_from = version_from ? content.versions.find_by_version(version_from.to_i) : content_to.try(:previous)
119 return nil unless content_to && content_from
157 return nil unless content_to && content_from
120
158
121 if content_from.version > content_to.version
159 if content_from.version > content_to.version
122 content_to, content_from = content_from, content_to
160 content_to, content_from = content_from, content_to
123 end
161 end
124
162
125 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
163 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
126 end
164 end
127
165
128 def annotate(version=nil)
166 def annotate(version=nil)
129 version = version ? version.to_i : self.content.version
167 version = version ? version.to_i : self.content.version
130 c = content.versions.find_by_version(version)
168 c = content.versions.find_by_version(version)
131 c ? WikiAnnotate.new(c) : nil
169 c ? WikiAnnotate.new(c) : nil
132 end
170 end
133
171
134 def self.pretty_title(str)
172 def self.pretty_title(str)
135 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
173 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
136 end
174 end
137
175
138 def project
176 def project
139 wiki.project
177 wiki.try(:project)
140 end
178 end
141
179
142 def text
180 def text
143 content.text if content
181 content.text if content
144 end
182 end
145
183
146 def updated_on
184 def updated_on
147 unless @updated_on
185 unless @updated_on
148 if time = read_attribute(:updated_on)
186 if time = read_attribute(:updated_on)
149 # content updated_on was eager loaded with the page
187 # content updated_on was eager loaded with the page
150 begin
188 begin
151 @updated_on = (self.class.default_timezone == :utc ? Time.parse(time.to_s).utc : Time.parse(time.to_s).localtime)
189 @updated_on = (self.class.default_timezone == :utc ? Time.parse(time.to_s).utc : Time.parse(time.to_s).localtime)
152 rescue
190 rescue
153 end
191 end
154 else
192 else
155 @updated_on = content && content.updated_on
193 @updated_on = content && content.updated_on
156 end
194 end
157 end
195 end
158 @updated_on
196 @updated_on
159 end
197 end
160
198
161 # Returns true if usr is allowed to edit the page, otherwise false
199 # Returns true if usr is allowed to edit the page, otherwise false
162 def editable_by?(usr)
200 def editable_by?(usr)
163 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
201 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
164 end
202 end
165
203
166 def attachments_deletable?(usr=User.current)
204 def attachments_deletable?(usr=User.current)
167 editable_by?(usr) && super(usr)
205 editable_by?(usr) && super(usr)
168 end
206 end
169
207
170 def parent_title
208 def parent_title
171 @parent_title || (self.parent && self.parent.pretty_title)
209 @parent_title || (self.parent && self.parent.pretty_title)
172 end
210 end
173
211
174 def parent_title=(t)
212 def parent_title=(t)
175 @parent_title = t
213 @parent_title = t
176 parent_page = t.blank? ? nil : self.wiki.find_page(t)
214 parent_page = t.blank? ? nil : self.wiki.find_page(t)
177 self.parent = parent_page
215 self.parent = parent_page
178 end
216 end
179
217
180 # Saves the page and its content if text was changed
218 # Saves the page and its content if text was changed
181 def save_with_content(content)
219 def save_with_content(content)
182 ret = nil
220 ret = nil
183 transaction do
221 transaction do
184 ret = save
222 ret = save
185 if content.text_changed?
223 if content.text_changed?
186 self.content = content
224 self.content = content
187 ret = ret && content.changed?
225 ret = ret && content.changed?
188 end
226 end
189 raise ActiveRecord::Rollback unless ret
227 raise ActiveRecord::Rollback unless ret
190 end
228 end
191 ret
229 ret
192 end
230 end
193
231
194 protected
232 protected
195
233
196 def validate_parent_title
234 def validate_parent_title
197 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
235 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
198 errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
236 errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
199 errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
237 if parent_id_changed? && parent && (parent.wiki_id != wiki_id)
238 errors.add(:parent_title, :not_same_project)
239 end
200 end
240 end
201 end
241 end
202
242
203 class WikiDiff < Redmine::Helpers::Diff
243 class WikiDiff < Redmine::Helpers::Diff
204 attr_reader :content_to, :content_from
244 attr_reader :content_to, :content_from
205
245
206 def initialize(content_to, content_from)
246 def initialize(content_to, content_from)
207 @content_to = content_to
247 @content_to = content_to
208 @content_from = content_from
248 @content_from = content_from
209 super(content_to.text, content_from.text)
249 super(content_to.text, content_from.text)
210 end
250 end
211 end
251 end
212
252
213 class WikiAnnotate
253 class WikiAnnotate
214 attr_reader :lines, :content
254 attr_reader :lines, :content
215
255
216 def initialize(content)
256 def initialize(content)
217 @content = content
257 @content = content
218 current = content
258 current = content
219 current_lines = current.text.split(/\r?\n/)
259 current_lines = current.text.split(/\r?\n/)
220 @lines = current_lines.collect {|t| [nil, nil, t]}
260 @lines = current_lines.collect {|t| [nil, nil, t]}
221 positions = []
261 positions = []
222 current_lines.size.times {|i| positions << i}
262 current_lines.size.times {|i| positions << i}
223 while (current.previous)
263 while (current.previous)
224 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
264 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
225 d.each_slice(3) do |s|
265 d.each_slice(3) do |s|
226 sign, line = s[0], s[1]
266 sign, line = s[0], s[1]
227 if sign == '+' && positions[line] && positions[line] != -1
267 if sign == '+' && positions[line] && positions[line] != -1
228 if @lines[positions[line]][0].nil?
268 if @lines[positions[line]][0].nil?
229 @lines[positions[line]][0] = current.version
269 @lines[positions[line]][0] = current.version
230 @lines[positions[line]][1] = current.author
270 @lines[positions[line]][1] = current.author
231 end
271 end
232 end
272 end
233 end
273 end
234 d.each_slice(3) do |s|
274 d.each_slice(3) do |s|
235 sign, line = s[0], s[1]
275 sign, line = s[0], s[1]
236 if sign == '-'
276 if sign == '-'
237 positions.insert(line, -1)
277 positions.insert(line, -1)
238 else
278 else
239 positions[line] = nil
279 positions[line] = nil
240 end
280 end
241 end
281 end
242 positions.compact!
282 positions.compact!
243 # Stop if every line is annotated
283 # Stop if every line is annotated
244 break unless @lines.detect { |line| line[0].nil? }
284 break unless @lines.detect { |line| line[0].nil? }
245 current = current.previous
285 current = current.previous
246 end
286 end
247 @lines.each { |line|
287 @lines.each { |line|
248 line[0] ||= current.version
288 line[0] ||= current.version
249 # if the last known version is > 1 (eg. history was cleared), we don't know the author
289 # if the last known version is > 1 (eg. history was cleared), we don't know the author
250 line[1] ||= current.author if current.version == 1
290 line[1] ||= current.author if current.version == 1
251 }
291 }
252 end
292 end
253 end
293 end
@@ -1,24 +1,39
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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 class WikiRedirect < ActiveRecord::Base
18 class WikiRedirect < ActiveRecord::Base
19 belongs_to :wiki
19 belongs_to :wiki
20
20
21 validates_presence_of :title, :redirects_to
21 validates_presence_of :wiki_id, :title, :redirects_to
22 validates_length_of :title, :redirects_to, :maximum => 255
22 validates_length_of :title, :redirects_to, :maximum => 255
23 attr_protected :id
23 attr_protected :id
24
25 before_save :set_redirects_to_wiki_id
26
27 def target_page
28 wiki = Wiki.find_by_id(redirects_to_wiki_id)
29 if wiki
30 wiki.find_page(redirects_to, :with_redirect => false)
31 end
32 end
33
34 private
35
36 def set_redirects_to_wiki_id
37 self.redirects_to_wiki_id ||= wiki_id
38 end
24 end
39 end
@@ -1,21 +1,26
1 <%= wiki_page_breadcrumb(@page) %>
1 <%= wiki_page_breadcrumb(@page) %>
2
2
3 <h2><%= h @original_title %></h2>
3 <h2><%= h @original_title %></h2>
4
4
5 <%= error_messages_for 'page' %>
5 <%= error_messages_for 'page' %>
6
6
7 <%= labelled_form_for :wiki_page, @page,
7 <%= labelled_form_for :wiki_page, @page,
8 :url => { :action => 'rename' },
8 :url => { :action => 'rename' },
9 :html => { :method => :post } do |f| %>
9 :html => { :method => :post } do |f| %>
10 <div class="box tabular">
10 <div class="box tabular">
11 <p><%= f.text_field :title, :required => true, :size => 100 %></p>
11 <p><%= f.text_field :title, :required => true, :size => 100 %></p>
12 <p><%= f.check_box :redirect_existing_links %></p>
12 <p><%= f.check_box :redirect_existing_links %></p>
13 <p><%= f.select :parent_id,
13 <p><%= f.select :parent_id,
14 content_tag('option', '', :value => '') +
14 content_tag('option', '', :value => '') +
15 wiki_page_options_for_select(
15 wiki_page_options_for_select(
16 @wiki.pages.includes(:parent).to_a - @page.self_and_descendants,
16 @wiki.pages.includes(:parent).to_a - @page.self_and_descendants,
17 @page.parent),
17 @page.parent),
18 :label => :field_parent_title %></p>
18 :label => :field_parent_title %></p>
19
20 <% if @page.safe_attribute? 'wiki_id' %>
21 <p><%= f.select :wiki_id, wiki_page_wiki_options_for_select(@page), :label => :label_project %></p>
22 <% end %>
23
19 </div>
24 </div>
20 <%= submit_tag l(:button_rename) %>
25 <%= submit_tag l(:button_rename) %>
21 <% end %>
26 <% end %>
@@ -1,926 +1,959
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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
19
20 class WikiControllerTest < ActionController::TestCase
20 class WikiControllerTest < ActionController::TestCase
21 fixtures :projects, :users, :roles, :members, :member_roles,
21 fixtures :projects, :users, :roles, :members, :member_roles,
22 :enabled_modules, :wikis, :wiki_pages, :wiki_contents,
22 :enabled_modules, :wikis, :wiki_pages, :wiki_contents,
23 :wiki_content_versions, :attachments,
23 :wiki_content_versions, :attachments,
24 :issues, :issue_statuses
24 :issues, :issue_statuses
25
25
26 def setup
26 def setup
27 User.current = nil
27 User.current = nil
28 end
28 end
29
29
30 def test_show_start_page
30 def test_show_start_page
31 get :show, :project_id => 'ecookbook'
31 get :show, :project_id => 'ecookbook'
32 assert_response :success
32 assert_response :success
33 assert_template 'show'
33 assert_template 'show'
34 assert_select 'h1', :text => /CookBook documentation/
34 assert_select 'h1', :text => /CookBook documentation/
35
35
36 # child_pages macro
36 # child_pages macro
37 assert_select 'ul.pages-hierarchy>li>a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image',
37 assert_select 'ul.pages-hierarchy>li>a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image',
38 :text => 'Page with an inline image'
38 :text => 'Page with an inline image'
39 end
39 end
40
40
41 def test_export_link
41 def test_export_link
42 Role.anonymous.add_permission! :export_wiki_pages
42 Role.anonymous.add_permission! :export_wiki_pages
43 get :show, :project_id => 'ecookbook'
43 get :show, :project_id => 'ecookbook'
44 assert_response :success
44 assert_response :success
45 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation.txt'
45 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation.txt'
46 end
46 end
47
47
48 def test_show_page_with_name
48 def test_show_page_with_name
49 get :show, :project_id => 1, :id => 'Another_page'
49 get :show, :project_id => 1, :id => 'Another_page'
50 assert_response :success
50 assert_response :success
51 assert_template 'show'
51 assert_template 'show'
52 assert_select 'h1', :text => /Another page/
52 assert_select 'h1', :text => /Another page/
53 # Included page with an inline image
53 # Included page with an inline image
54 assert_select 'p', :text => /This is an inline image/
54 assert_select 'p', :text => /This is an inline image/
55 assert_select 'img[src=?][alt=?]', '/attachments/download/3/logo.gif', 'This is a logo'
55 assert_select 'img[src=?][alt=?]', '/attachments/download/3/logo.gif', 'This is a logo'
56 end
56 end
57
57
58 def test_show_old_version
58 def test_show_old_version
59 with_settings :default_language => 'en' do
59 with_settings :default_language => 'en' do
60 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'
60 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'
61 end
61 end
62 assert_response :success
62 assert_response :success
63 assert_template 'show'
63 assert_template 'show'
64
64
65 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/1', :text => /Previous/
65 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/1', :text => /Previous/
66 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/diff', :text => /diff/
66 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/diff', :text => /diff/
67 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/3', :text => /Next/
67 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/3', :text => /Next/
68 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
68 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
69 end
69 end
70
70
71 def test_show_old_version_with_attachments
71 def test_show_old_version_with_attachments
72 page = WikiPage.find(4)
72 page = WikiPage.find(4)
73 assert page.attachments.any?
73 assert page.attachments.any?
74 content = page.content
74 content = page.content
75 content.text = "update"
75 content.text = "update"
76 content.save!
76 content.save!
77
77
78 get :show, :project_id => 'ecookbook', :id => page.title, :version => '1'
78 get :show, :project_id => 'ecookbook', :id => page.title, :version => '1'
79 assert_kind_of WikiContent::Version, assigns(:content)
79 assert_kind_of WikiContent::Version, assigns(:content)
80 assert_response :success
80 assert_response :success
81 assert_template 'show'
81 assert_template 'show'
82 end
82 end
83
83
84 def test_show_old_version_without_permission_should_be_denied
84 def test_show_old_version_without_permission_should_be_denied
85 Role.anonymous.remove_permission! :view_wiki_edits
85 Role.anonymous.remove_permission! :view_wiki_edits
86
86
87 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'
87 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'
88 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fprojects%2Fecookbook%2Fwiki%2FCookBook_documentation%2F2'
88 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fprojects%2Fecookbook%2Fwiki%2FCookBook_documentation%2F2'
89 end
89 end
90
90
91 def test_show_first_version
91 def test_show_first_version
92 with_settings :default_language => 'en' do
92 with_settings :default_language => 'en' do
93 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '1'
93 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '1'
94 end
94 end
95 assert_response :success
95 assert_response :success
96 assert_template 'show'
96 assert_template 'show'
97
97
98 assert_select 'a', :text => /Previous/, :count => 0
98 assert_select 'a', :text => /Previous/, :count => 0
99 assert_select 'a', :text => /diff/, :count => 0
99 assert_select 'a', :text => /diff/, :count => 0
100 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => /Next/
100 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => /Next/
101 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
101 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
102 end
102 end
103
103
104 def test_show_redirected_page
104 def test_show_redirected_page
105 WikiRedirect.create!(:wiki_id => 1, :title => 'Old_title', :redirects_to => 'Another_page')
105 WikiRedirect.create!(:wiki_id => 1, :title => 'Old_title', :redirects_to => 'Another_page')
106
106
107 get :show, :project_id => 'ecookbook', :id => 'Old_title'
107 get :show, :project_id => 'ecookbook', :id => 'Old_title'
108 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
108 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
109 end
109 end
110
110
111 def test_show_with_sidebar
111 def test_show_with_sidebar
112 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
112 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
113 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
113 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
114 page.save!
114 page.save!
115
115
116 get :show, :project_id => 1, :id => 'Another_page'
116 get :show, :project_id => 1, :id => 'Another_page'
117 assert_response :success
117 assert_response :success
118 assert_select 'div#sidebar', :text => /Side bar content for test_show_with_sidebar/
118 assert_select 'div#sidebar', :text => /Side bar content for test_show_with_sidebar/
119 end
119 end
120
120
121 def test_show_should_display_section_edit_links
121 def test_show_should_display_section_edit_links
122 @request.session[:user_id] = 2
122 @request.session[:user_id] = 2
123 get :show, :project_id => 1, :id => 'Page with sections'
123 get :show, :project_id => 1, :id => 'Page with sections'
124
124
125 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=1', 0
125 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=1', 0
126 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
126 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
127 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=3'
127 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=3'
128 end
128 end
129
129
130 def test_show_current_version_should_display_section_edit_links
130 def test_show_current_version_should_display_section_edit_links
131 @request.session[:user_id] = 2
131 @request.session[:user_id] = 2
132 get :show, :project_id => 1, :id => 'Page with sections', :version => 3
132 get :show, :project_id => 1, :id => 'Page with sections', :version => 3
133
133
134 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
134 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
135 end
135 end
136
136
137 def test_show_old_version_should_not_display_section_edit_links
137 def test_show_old_version_should_not_display_section_edit_links
138 @request.session[:user_id] = 2
138 @request.session[:user_id] = 2
139 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
139 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
140
140
141 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2', 0
141 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2', 0
142 end
142 end
143
143
144 def test_show_unexistent_page_without_edit_right
144 def test_show_unexistent_page_without_edit_right
145 get :show, :project_id => 1, :id => 'Unexistent page'
145 get :show, :project_id => 1, :id => 'Unexistent page'
146 assert_response 404
146 assert_response 404
147 end
147 end
148
148
149 def test_show_unexistent_page_with_edit_right
149 def test_show_unexistent_page_with_edit_right
150 @request.session[:user_id] = 2
150 @request.session[:user_id] = 2
151 get :show, :project_id => 1, :id => 'Unexistent page'
151 get :show, :project_id => 1, :id => 'Unexistent page'
152 assert_response :success
152 assert_response :success
153 assert_template 'edit'
153 assert_template 'edit'
154 end
154 end
155
155
156 def test_show_specific_version_of_an_unexistent_page_without_edit_right
156 def test_show_specific_version_of_an_unexistent_page_without_edit_right
157 get :show, :project_id => 1, :id => 'Unexistent page', :version => 1
157 get :show, :project_id => 1, :id => 'Unexistent page', :version => 1
158 assert_response 404
158 assert_response 404
159 end
159 end
160
160
161 def test_show_unexistent_page_with_parent_should_preselect_parent
161 def test_show_unexistent_page_with_parent_should_preselect_parent
162 @request.session[:user_id] = 2
162 @request.session[:user_id] = 2
163 get :show, :project_id => 1, :id => 'Unexistent page', :parent => 'Another_page'
163 get :show, :project_id => 1, :id => 'Unexistent page', :parent => 'Another_page'
164 assert_response :success
164 assert_response :success
165 assert_template 'edit'
165 assert_template 'edit'
166 assert_select 'select[name=?] option[value="2"][selected=selected]', 'wiki_page[parent_id]'
166 assert_select 'select[name=?] option[value="2"][selected=selected]', 'wiki_page[parent_id]'
167 end
167 end
168
168
169 def test_show_should_not_show_history_without_permission
169 def test_show_should_not_show_history_without_permission
170 Role.anonymous.remove_permission! :view_wiki_edits
170 Role.anonymous.remove_permission! :view_wiki_edits
171 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
171 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
172
172
173 assert_response 302
173 assert_response 302
174 end
174 end
175
175
176 def test_show_page_without_content_should_display_the_edit_form
176 def test_show_page_without_content_should_display_the_edit_form
177 @request.session[:user_id] = 2
177 @request.session[:user_id] = 2
178 WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
178 WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
179
179
180 get :show, :project_id => 1, :id => 'NoContent'
180 get :show, :project_id => 1, :id => 'NoContent'
181 assert_response :success
181 assert_response :success
182 assert_template 'edit'
182 assert_template 'edit'
183 assert_select 'textarea[name=?]', 'content[text]'
183 assert_select 'textarea[name=?]', 'content[text]'
184 end
184 end
185
185
186 def test_create_page
186 def test_create_page
187 @request.session[:user_id] = 2
187 @request.session[:user_id] = 2
188 assert_difference 'WikiPage.count' do
188 assert_difference 'WikiPage.count' do
189 assert_difference 'WikiContent.count' do
189 assert_difference 'WikiContent.count' do
190 put :update, :project_id => 1,
190 put :update, :project_id => 1,
191 :id => 'New page',
191 :id => 'New page',
192 :content => {:comments => 'Created the page',
192 :content => {:comments => 'Created the page',
193 :text => "h1. New page\n\nThis is a new page",
193 :text => "h1. New page\n\nThis is a new page",
194 :version => 0}
194 :version => 0}
195 end
195 end
196 end
196 end
197 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
197 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
198 page = Project.find(1).wiki.find_page('New page')
198 page = Project.find(1).wiki.find_page('New page')
199 assert !page.new_record?
199 assert !page.new_record?
200 assert_not_nil page.content
200 assert_not_nil page.content
201 assert_nil page.parent
201 assert_nil page.parent
202 assert_equal 'Created the page', page.content.comments
202 assert_equal 'Created the page', page.content.comments
203 end
203 end
204
204
205 def test_create_page_with_attachments
205 def test_create_page_with_attachments
206 @request.session[:user_id] = 2
206 @request.session[:user_id] = 2
207 assert_difference 'WikiPage.count' do
207 assert_difference 'WikiPage.count' do
208 assert_difference 'Attachment.count' do
208 assert_difference 'Attachment.count' do
209 put :update, :project_id => 1,
209 put :update, :project_id => 1,
210 :id => 'New page',
210 :id => 'New page',
211 :content => {:comments => 'Created the page',
211 :content => {:comments => 'Created the page',
212 :text => "h1. New page\n\nThis is a new page",
212 :text => "h1. New page\n\nThis is a new page",
213 :version => 0},
213 :version => 0},
214 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
214 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
215 end
215 end
216 end
216 end
217 page = Project.find(1).wiki.find_page('New page')
217 page = Project.find(1).wiki.find_page('New page')
218 assert_equal 1, page.attachments.count
218 assert_equal 1, page.attachments.count
219 assert_equal 'testfile.txt', page.attachments.first.filename
219 assert_equal 'testfile.txt', page.attachments.first.filename
220 end
220 end
221
221
222 def test_create_page_with_parent
222 def test_create_page_with_parent
223 @request.session[:user_id] = 2
223 @request.session[:user_id] = 2
224 assert_difference 'WikiPage.count' do
224 assert_difference 'WikiPage.count' do
225 put :update, :project_id => 1, :id => 'New page',
225 put :update, :project_id => 1, :id => 'New page',
226 :content => {:text => "h1. New page\n\nThis is a new page", :version => 0},
226 :content => {:text => "h1. New page\n\nThis is a new page", :version => 0},
227 :wiki_page => {:parent_id => 2}
227 :wiki_page => {:parent_id => 2}
228 end
228 end
229 page = Project.find(1).wiki.find_page('New page')
229 page = Project.find(1).wiki.find_page('New page')
230 assert_equal WikiPage.find(2), page.parent
230 assert_equal WikiPage.find(2), page.parent
231 end
231 end
232
232
233 def test_edit_page
233 def test_edit_page
234 @request.session[:user_id] = 2
234 @request.session[:user_id] = 2
235 get :edit, :project_id => 'ecookbook', :id => 'Another_page'
235 get :edit, :project_id => 'ecookbook', :id => 'Another_page'
236
236
237 assert_response :success
237 assert_response :success
238 assert_template 'edit'
238 assert_template 'edit'
239
239
240 assert_select 'textarea[name=?]', 'content[text]',
240 assert_select 'textarea[name=?]', 'content[text]',
241 :text => WikiPage.find_by_title('Another_page').content.text
241 :text => WikiPage.find_by_title('Another_page').content.text
242 end
242 end
243
243
244 def test_edit_section
244 def test_edit_section
245 @request.session[:user_id] = 2
245 @request.session[:user_id] = 2
246 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2
246 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2
247
247
248 assert_response :success
248 assert_response :success
249 assert_template 'edit'
249 assert_template 'edit'
250
250
251 page = WikiPage.find_by_title('Page_with_sections')
251 page = WikiPage.find_by_title('Page_with_sections')
252 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
252 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
253
253
254 assert_select 'textarea[name=?]', 'content[text]', :text => section
254 assert_select 'textarea[name=?]', 'content[text]', :text => section
255 assert_select 'input[name=section][type=hidden][value="2"]'
255 assert_select 'input[name=section][type=hidden][value="2"]'
256 assert_select 'input[name=section_hash][type=hidden][value=?]', hash
256 assert_select 'input[name=section_hash][type=hidden][value=?]', hash
257 end
257 end
258
258
259 def test_edit_invalid_section_should_respond_with_404
259 def test_edit_invalid_section_should_respond_with_404
260 @request.session[:user_id] = 2
260 @request.session[:user_id] = 2
261 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10
261 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10
262
262
263 assert_response 404
263 assert_response 404
264 end
264 end
265
265
266 def test_update_page
266 def test_update_page
267 @request.session[:user_id] = 2
267 @request.session[:user_id] = 2
268 assert_no_difference 'WikiPage.count' do
268 assert_no_difference 'WikiPage.count' do
269 assert_no_difference 'WikiContent.count' do
269 assert_no_difference 'WikiContent.count' do
270 assert_difference 'WikiContent::Version.count' do
270 assert_difference 'WikiContent::Version.count' do
271 put :update, :project_id => 1,
271 put :update, :project_id => 1,
272 :id => 'Another_page',
272 :id => 'Another_page',
273 :content => {
273 :content => {
274 :comments => "my comments",
274 :comments => "my comments",
275 :text => "edited",
275 :text => "edited",
276 :version => 1
276 :version => 1
277 }
277 }
278 end
278 end
279 end
279 end
280 end
280 end
281 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
281 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
282
282
283 page = Wiki.find(1).pages.find_by_title('Another_page')
283 page = Wiki.find(1).pages.find_by_title('Another_page')
284 assert_equal "edited", page.content.text
284 assert_equal "edited", page.content.text
285 assert_equal 2, page.content.version
285 assert_equal 2, page.content.version
286 assert_equal "my comments", page.content.comments
286 assert_equal "my comments", page.content.comments
287 end
287 end
288
288
289 def test_update_page_with_parent
289 def test_update_page_with_parent
290 @request.session[:user_id] = 2
290 @request.session[:user_id] = 2
291 assert_no_difference 'WikiPage.count' do
291 assert_no_difference 'WikiPage.count' do
292 assert_no_difference 'WikiContent.count' do
292 assert_no_difference 'WikiContent.count' do
293 assert_difference 'WikiContent::Version.count' do
293 assert_difference 'WikiContent::Version.count' do
294 put :update, :project_id => 1,
294 put :update, :project_id => 1,
295 :id => 'Another_page',
295 :id => 'Another_page',
296 :content => {
296 :content => {
297 :comments => "my comments",
297 :comments => "my comments",
298 :text => "edited",
298 :text => "edited",
299 :version => 1
299 :version => 1
300 },
300 },
301 :wiki_page => {:parent_id => '1'}
301 :wiki_page => {:parent_id => '1'}
302 end
302 end
303 end
303 end
304 end
304 end
305 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
305 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
306
306
307 page = Wiki.find(1).pages.find_by_title('Another_page')
307 page = Wiki.find(1).pages.find_by_title('Another_page')
308 assert_equal "edited", page.content.text
308 assert_equal "edited", page.content.text
309 assert_equal 2, page.content.version
309 assert_equal 2, page.content.version
310 assert_equal "my comments", page.content.comments
310 assert_equal "my comments", page.content.comments
311 assert_equal WikiPage.find(1), page.parent
311 assert_equal WikiPage.find(1), page.parent
312 end
312 end
313
313
314 def test_update_page_with_failure
314 def test_update_page_with_failure
315 @request.session[:user_id] = 2
315 @request.session[:user_id] = 2
316 assert_no_difference 'WikiPage.count' do
316 assert_no_difference 'WikiPage.count' do
317 assert_no_difference 'WikiContent.count' do
317 assert_no_difference 'WikiContent.count' do
318 assert_no_difference 'WikiContent::Version.count' do
318 assert_no_difference 'WikiContent::Version.count' do
319 put :update, :project_id => 1,
319 put :update, :project_id => 1,
320 :id => 'Another_page',
320 :id => 'Another_page',
321 :content => {
321 :content => {
322 :comments => 'a' * 300, # failure here, comment is too long
322 :comments => 'a' * 300, # failure here, comment is too long
323 :text => 'edited',
323 :text => 'edited',
324 :version => 1
324 :version => 1
325 }
325 }
326 end
326 end
327 end
327 end
328 end
328 end
329 assert_response :success
329 assert_response :success
330 assert_template 'edit'
330 assert_template 'edit'
331
331
332 assert_select_error /Comment is too long/
332 assert_select_error /Comment is too long/
333 assert_select 'textarea#content_text', :text => "edited"
333 assert_select 'textarea#content_text', :text => "edited"
334 assert_select 'input#content_version[value="1"]'
334 assert_select 'input#content_version[value="1"]'
335 end
335 end
336
336
337 def test_update_page_with_parent_change_only_should_not_create_content_version
337 def test_update_page_with_parent_change_only_should_not_create_content_version
338 @request.session[:user_id] = 2
338 @request.session[:user_id] = 2
339 assert_no_difference 'WikiPage.count' do
339 assert_no_difference 'WikiPage.count' do
340 assert_no_difference 'WikiContent.count' do
340 assert_no_difference 'WikiContent.count' do
341 assert_no_difference 'WikiContent::Version.count' do
341 assert_no_difference 'WikiContent::Version.count' do
342 put :update, :project_id => 1,
342 put :update, :project_id => 1,
343 :id => 'Another_page',
343 :id => 'Another_page',
344 :content => {
344 :content => {
345 :comments => '',
345 :comments => '',
346 :text => Wiki.find(1).find_page('Another_page').content.text,
346 :text => Wiki.find(1).find_page('Another_page').content.text,
347 :version => 1
347 :version => 1
348 },
348 },
349 :wiki_page => {:parent_id => '1'}
349 :wiki_page => {:parent_id => '1'}
350 end
350 end
351 end
351 end
352 end
352 end
353 page = Wiki.find(1).pages.find_by_title('Another_page')
353 page = Wiki.find(1).pages.find_by_title('Another_page')
354 assert_equal 1, page.content.version
354 assert_equal 1, page.content.version
355 assert_equal WikiPage.find(1), page.parent
355 assert_equal WikiPage.find(1), page.parent
356 end
356 end
357
357
358 def test_update_page_with_attachments_only_should_not_create_content_version
358 def test_update_page_with_attachments_only_should_not_create_content_version
359 @request.session[:user_id] = 2
359 @request.session[:user_id] = 2
360 assert_no_difference 'WikiPage.count' do
360 assert_no_difference 'WikiPage.count' do
361 assert_no_difference 'WikiContent.count' do
361 assert_no_difference 'WikiContent.count' do
362 assert_no_difference 'WikiContent::Version.count' do
362 assert_no_difference 'WikiContent::Version.count' do
363 assert_difference 'Attachment.count' do
363 assert_difference 'Attachment.count' do
364 put :update, :project_id => 1,
364 put :update, :project_id => 1,
365 :id => 'Another_page',
365 :id => 'Another_page',
366 :content => {
366 :content => {
367 :comments => '',
367 :comments => '',
368 :text => Wiki.find(1).find_page('Another_page').content.text,
368 :text => Wiki.find(1).find_page('Another_page').content.text,
369 :version => 1
369 :version => 1
370 },
370 },
371 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
371 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
372 end
372 end
373 end
373 end
374 end
374 end
375 end
375 end
376 page = Wiki.find(1).pages.find_by_title('Another_page')
376 page = Wiki.find(1).pages.find_by_title('Another_page')
377 assert_equal 1, page.content.version
377 assert_equal 1, page.content.version
378 end
378 end
379
379
380 def test_update_stale_page_should_not_raise_an_error
380 def test_update_stale_page_should_not_raise_an_error
381 @request.session[:user_id] = 2
381 @request.session[:user_id] = 2
382 c = Wiki.find(1).find_page('Another_page').content
382 c = Wiki.find(1).find_page('Another_page').content
383 c.text = 'Previous text'
383 c.text = 'Previous text'
384 c.save!
384 c.save!
385 assert_equal 2, c.version
385 assert_equal 2, c.version
386
386
387 assert_no_difference 'WikiPage.count' do
387 assert_no_difference 'WikiPage.count' do
388 assert_no_difference 'WikiContent.count' do
388 assert_no_difference 'WikiContent.count' do
389 assert_no_difference 'WikiContent::Version.count' do
389 assert_no_difference 'WikiContent::Version.count' do
390 put :update, :project_id => 1,
390 put :update, :project_id => 1,
391 :id => 'Another_page',
391 :id => 'Another_page',
392 :content => {
392 :content => {
393 :comments => 'My comments',
393 :comments => 'My comments',
394 :text => 'Text should not be lost',
394 :text => 'Text should not be lost',
395 :version => 1
395 :version => 1
396 }
396 }
397 end
397 end
398 end
398 end
399 end
399 end
400 assert_response :success
400 assert_response :success
401 assert_template 'edit'
401 assert_template 'edit'
402 assert_select 'div.error', :text => /Data has been updated by another user/
402 assert_select 'div.error', :text => /Data has been updated by another user/
403 assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
403 assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
404 assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
404 assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
405
405
406 c.reload
406 c.reload
407 assert_equal 'Previous text', c.text
407 assert_equal 'Previous text', c.text
408 assert_equal 2, c.version
408 assert_equal 2, c.version
409 end
409 end
410
410
411 def test_update_page_without_content_should_create_content
411 def test_update_page_without_content_should_create_content
412 @request.session[:user_id] = 2
412 @request.session[:user_id] = 2
413 page = WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
413 page = WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
414
414
415 assert_no_difference 'WikiPage.count' do
415 assert_no_difference 'WikiPage.count' do
416 assert_difference 'WikiContent.count' do
416 assert_difference 'WikiContent.count' do
417 put :update, :project_id => 1, :id => 'NoContent', :content => {:text => 'Some content'}
417 put :update, :project_id => 1, :id => 'NoContent', :content => {:text => 'Some content'}
418 assert_response 302
418 assert_response 302
419 end
419 end
420 end
420 end
421 assert_equal 'Some content', page.reload.content.text
421 assert_equal 'Some content', page.reload.content.text
422 end
422 end
423
423
424 def test_update_section
424 def test_update_section
425 @request.session[:user_id] = 2
425 @request.session[:user_id] = 2
426 page = WikiPage.find_by_title('Page_with_sections')
426 page = WikiPage.find_by_title('Page_with_sections')
427 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
427 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
428 text = page.content.text
428 text = page.content.text
429
429
430 assert_no_difference 'WikiPage.count' do
430 assert_no_difference 'WikiPage.count' do
431 assert_no_difference 'WikiContent.count' do
431 assert_no_difference 'WikiContent.count' do
432 assert_difference 'WikiContent::Version.count' do
432 assert_difference 'WikiContent::Version.count' do
433 put :update, :project_id => 1, :id => 'Page_with_sections',
433 put :update, :project_id => 1, :id => 'Page_with_sections',
434 :content => {
434 :content => {
435 :text => "New section content",
435 :text => "New section content",
436 :version => 3
436 :version => 3
437 },
437 },
438 :section => 2,
438 :section => 2,
439 :section_hash => hash
439 :section_hash => hash
440 end
440 end
441 end
441 end
442 end
442 end
443 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
443 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
444 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text
444 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text
445 end
445 end
446
446
447 def test_update_section_should_allow_stale_page_update
447 def test_update_section_should_allow_stale_page_update
448 @request.session[:user_id] = 2
448 @request.session[:user_id] = 2
449 page = WikiPage.find_by_title('Page_with_sections')
449 page = WikiPage.find_by_title('Page_with_sections')
450 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
450 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
451 text = page.content.text
451 text = page.content.text
452
452
453 assert_no_difference 'WikiPage.count' do
453 assert_no_difference 'WikiPage.count' do
454 assert_no_difference 'WikiContent.count' do
454 assert_no_difference 'WikiContent.count' do
455 assert_difference 'WikiContent::Version.count' do
455 assert_difference 'WikiContent::Version.count' do
456 put :update, :project_id => 1, :id => 'Page_with_sections',
456 put :update, :project_id => 1, :id => 'Page_with_sections',
457 :content => {
457 :content => {
458 :text => "New section content",
458 :text => "New section content",
459 :version => 2 # Current version is 3
459 :version => 2 # Current version is 3
460 },
460 },
461 :section => 2,
461 :section => 2,
462 :section_hash => hash
462 :section_hash => hash
463 end
463 end
464 end
464 end
465 end
465 end
466 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
466 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
467 page.reload
467 page.reload
468 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text
468 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text
469 assert_equal 4, page.content.version
469 assert_equal 4, page.content.version
470 end
470 end
471
471
472 def test_update_section_should_not_allow_stale_section_update
472 def test_update_section_should_not_allow_stale_section_update
473 @request.session[:user_id] = 2
473 @request.session[:user_id] = 2
474
474
475 assert_no_difference 'WikiPage.count' do
475 assert_no_difference 'WikiPage.count' do
476 assert_no_difference 'WikiContent.count' do
476 assert_no_difference 'WikiContent.count' do
477 assert_no_difference 'WikiContent::Version.count' do
477 assert_no_difference 'WikiContent::Version.count' do
478 put :update, :project_id => 1, :id => 'Page_with_sections',
478 put :update, :project_id => 1, :id => 'Page_with_sections',
479 :content => {
479 :content => {
480 :comments => 'My comments',
480 :comments => 'My comments',
481 :text => "Text should not be lost",
481 :text => "Text should not be lost",
482 :version => 3
482 :version => 3
483 },
483 },
484 :section => 2,
484 :section => 2,
485 :section_hash => Digest::MD5.hexdigest("wrong hash")
485 :section_hash => Digest::MD5.hexdigest("wrong hash")
486 end
486 end
487 end
487 end
488 end
488 end
489 assert_response :success
489 assert_response :success
490 assert_template 'edit'
490 assert_template 'edit'
491 assert_select 'div.error', :text => /Data has been updated by another user/
491 assert_select 'div.error', :text => /Data has been updated by another user/
492 assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
492 assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
493 assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
493 assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
494 end
494 end
495
495
496 def test_preview
496 def test_preview
497 @request.session[:user_id] = 2
497 @request.session[:user_id] = 2
498 xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation',
498 xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation',
499 :content => { :comments => '',
499 :content => { :comments => '',
500 :text => 'this is a *previewed text*',
500 :text => 'this is a *previewed text*',
501 :version => 3 }
501 :version => 3 }
502 assert_response :success
502 assert_response :success
503 assert_template 'common/_preview'
503 assert_template 'common/_preview'
504 assert_select 'strong', :text => /previewed text/
504 assert_select 'strong', :text => /previewed text/
505 end
505 end
506
506
507 def test_preview_new_page
507 def test_preview_new_page
508 @request.session[:user_id] = 2
508 @request.session[:user_id] = 2
509 xhr :post, :preview, :project_id => 1, :id => 'New page',
509 xhr :post, :preview, :project_id => 1, :id => 'New page',
510 :content => { :text => 'h1. New page',
510 :content => { :text => 'h1. New page',
511 :comments => '',
511 :comments => '',
512 :version => 0 }
512 :version => 0 }
513 assert_response :success
513 assert_response :success
514 assert_template 'common/_preview'
514 assert_template 'common/_preview'
515 assert_select 'h1', :text => /New page/
515 assert_select 'h1', :text => /New page/
516 end
516 end
517
517
518 def test_history
518 def test_history
519 @request.session[:user_id] = 2
519 @request.session[:user_id] = 2
520 get :history, :project_id => 'ecookbook', :id => 'CookBook_documentation'
520 get :history, :project_id => 'ecookbook', :id => 'CookBook_documentation'
521 assert_response :success
521 assert_response :success
522 assert_template 'history'
522 assert_template 'history'
523 assert_not_nil assigns(:versions)
523 assert_not_nil assigns(:versions)
524 assert_equal 3, assigns(:versions).size
524 assert_equal 3, assigns(:versions).size
525
525
526 assert_select "input[type=submit][name=commit]"
526 assert_select "input[type=submit][name=commit]"
527 assert_select 'td' do
527 assert_select 'td' do
528 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => '2'
528 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => '2'
529 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/annotate', :text => 'Annotate'
529 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/annotate', :text => 'Annotate'
530 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => 'Delete'
530 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => 'Delete'
531 end
531 end
532 end
532 end
533
533
534 def test_history_with_one_version
534 def test_history_with_one_version
535 @request.session[:user_id] = 2
535 @request.session[:user_id] = 2
536 get :history, :project_id => 'ecookbook', :id => 'Another_page'
536 get :history, :project_id => 'ecookbook', :id => 'Another_page'
537 assert_response :success
537 assert_response :success
538 assert_template 'history'
538 assert_template 'history'
539 assert_not_nil assigns(:versions)
539 assert_not_nil assigns(:versions)
540 assert_equal 1, assigns(:versions).size
540 assert_equal 1, assigns(:versions).size
541 assert_select "input[type=submit][name=commit]", false
541 assert_select "input[type=submit][name=commit]", false
542 assert_select 'td' do
542 assert_select 'td' do
543 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => '1'
543 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => '1'
544 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1/annotate', :text => 'Annotate'
544 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1/annotate', :text => 'Annotate'
545 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => 'Delete', :count => 0
545 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => 'Delete', :count => 0
546 end
546 end
547 end
547 end
548
548
549 def test_diff
549 def test_diff
550 content = WikiPage.find(1).content
550 content = WikiPage.find(1).content
551 assert_difference 'WikiContent::Version.count', 2 do
551 assert_difference 'WikiContent::Version.count', 2 do
552 content.text = "Line removed\nThis is a sample text for testing diffs"
552 content.text = "Line removed\nThis is a sample text for testing diffs"
553 content.save!
553 content.save!
554 content.text = "This is a sample text for testing diffs\nLine added"
554 content.text = "This is a sample text for testing diffs\nLine added"
555 content.save!
555 content.save!
556 end
556 end
557
557
558 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => content.version, :version_from => (content.version - 1)
558 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => content.version, :version_from => (content.version - 1)
559 assert_response :success
559 assert_response :success
560 assert_template 'diff'
560 assert_template 'diff'
561 assert_select 'span.diff_out', :text => 'Line removed'
561 assert_select 'span.diff_out', :text => 'Line removed'
562 assert_select 'span.diff_in', :text => 'Line added'
562 assert_select 'span.diff_in', :text => 'Line added'
563 end
563 end
564
564
565 def test_diff_with_invalid_version_should_respond_with_404
565 def test_diff_with_invalid_version_should_respond_with_404
566 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => '99'
566 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => '99'
567 assert_response 404
567 assert_response 404
568 end
568 end
569
569
570 def test_diff_with_invalid_version_from_should_respond_with_404
570 def test_diff_with_invalid_version_from_should_respond_with_404
571 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => '99', :version_from => '98'
571 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => '99', :version_from => '98'
572 assert_response 404
572 assert_response 404
573 end
573 end
574
574
575 def test_annotate
575 def test_annotate
576 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2
576 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2
577 assert_response :success
577 assert_response :success
578 assert_template 'annotate'
578 assert_template 'annotate'
579
579
580 # Line 1
580 # Line 1
581 assert_select 'table.annotate tr:nth-child(1)' do
581 assert_select 'table.annotate tr:nth-child(1)' do
582 assert_select 'th.line-num', :text => '1'
582 assert_select 'th.line-num', :text => '1'
583 assert_select 'td.author', :text => /John Smith/
583 assert_select 'td.author', :text => /John Smith/
584 assert_select 'td', :text => /h1\. CookBook documentation/
584 assert_select 'td', :text => /h1\. CookBook documentation/
585 end
585 end
586
586
587 # Line 5
587 # Line 5
588 assert_select 'table.annotate tr:nth-child(5)' do
588 assert_select 'table.annotate tr:nth-child(5)' do
589 assert_select 'th.line-num', :text => '5'
589 assert_select 'th.line-num', :text => '5'
590 assert_select 'td.author', :text => /Redmine Admin/
590 assert_select 'td.author', :text => /Redmine Admin/
591 assert_select 'td', :text => /Some updated \[\[documentation\]\] here/
591 assert_select 'td', :text => /Some updated \[\[documentation\]\] here/
592 end
592 end
593 end
593 end
594
594
595 def test_annotate_with_invalid_version_should_respond_with_404
595 def test_annotate_with_invalid_version_should_respond_with_404
596 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => '99'
596 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => '99'
597 assert_response 404
597 assert_response 404
598 end
598 end
599
599
600 def test_get_rename
600 def test_get_rename
601 @request.session[:user_id] = 2
601 @request.session[:user_id] = 2
602 get :rename, :project_id => 1, :id => 'Another_page'
602 get :rename, :project_id => 1, :id => 'Another_page'
603 assert_response :success
603 assert_response :success
604 assert_template 'rename'
604 assert_template 'rename'
605
605
606 assert_select 'select[name=?]', 'wiki_page[parent_id]' do
606 assert_select 'select[name=?]', 'wiki_page[parent_id]' do
607 assert_select 'option[value=""]', :text => ''
607 assert_select 'option[value=""]', :text => ''
608 assert_select 'option[selected=selected]', 0
608 assert_select 'option[selected=selected]', 0
609 end
609 end
610 end
610 end
611
611
612 def test_get_rename_child_page
612 def test_get_rename_child_page
613 @request.session[:user_id] = 2
613 @request.session[:user_id] = 2
614 get :rename, :project_id => 1, :id => 'Child_1'
614 get :rename, :project_id => 1, :id => 'Child_1'
615 assert_response :success
615 assert_response :success
616 assert_template 'rename'
616 assert_template 'rename'
617
617
618 assert_select 'select[name=?]', 'wiki_page[parent_id]' do
618 assert_select 'select[name=?]', 'wiki_page[parent_id]' do
619 assert_select 'option[value=""]', :text => ''
619 assert_select 'option[value=""]', :text => ''
620 assert_select 'option[value="2"][selected=selected]', :text => /Another page/
620 assert_select 'option[value="2"][selected=selected]', :text => /Another page/
621 end
621 end
622 end
622 end
623
623
624 def test_rename_with_redirect
624 def test_rename_with_redirect
625 @request.session[:user_id] = 2
625 @request.session[:user_id] = 2
626 post :rename, :project_id => 1, :id => 'Another_page',
626 post :rename, :project_id => 1, :id => 'Another_page',
627 :wiki_page => { :title => 'Another renamed page',
627 :wiki_page => { :title => 'Another renamed page',
628 :redirect_existing_links => 1 }
628 :redirect_existing_links => 1 }
629 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
629 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
630 wiki = Project.find(1).wiki
630 wiki = Project.find(1).wiki
631 # Check redirects
631 # Check redirects
632 assert_not_nil wiki.find_page('Another page')
632 assert_not_nil wiki.find_page('Another page')
633 assert_nil wiki.find_page('Another page', :with_redirect => false)
633 assert_nil wiki.find_page('Another page', :with_redirect => false)
634 end
634 end
635
635
636 def test_rename_without_redirect
636 def test_rename_without_redirect
637 @request.session[:user_id] = 2
637 @request.session[:user_id] = 2
638 post :rename, :project_id => 1, :id => 'Another_page',
638 post :rename, :project_id => 1, :id => 'Another_page',
639 :wiki_page => { :title => 'Another renamed page',
639 :wiki_page => { :title => 'Another renamed page',
640 :redirect_existing_links => "0" }
640 :redirect_existing_links => "0" }
641 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
641 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
642 wiki = Project.find(1).wiki
642 wiki = Project.find(1).wiki
643 # Check that there's no redirects
643 # Check that there's no redirects
644 assert_nil wiki.find_page('Another page')
644 assert_nil wiki.find_page('Another page')
645 end
645 end
646
646
647 def test_rename_with_parent_assignment
647 def test_rename_with_parent_assignment
648 @request.session[:user_id] = 2
648 @request.session[:user_id] = 2
649 post :rename, :project_id => 1, :id => 'Another_page',
649 post :rename, :project_id => 1, :id => 'Another_page',
650 :wiki_page => { :title => 'Another page', :redirect_existing_links => "0", :parent_id => '4' }
650 :wiki_page => { :title => 'Another page', :redirect_existing_links => "0", :parent_id => '4' }
651 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
651 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
652 assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
652 assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
653 end
653 end
654
654
655 def test_rename_with_parent_unassignment
655 def test_rename_with_parent_unassignment
656 @request.session[:user_id] = 2
656 @request.session[:user_id] = 2
657 post :rename, :project_id => 1, :id => 'Child_1',
657 post :rename, :project_id => 1, :id => 'Child_1',
658 :wiki_page => { :title => 'Child 1', :redirect_existing_links => "0", :parent_id => '' }
658 :wiki_page => { :title => 'Child 1', :redirect_existing_links => "0", :parent_id => '' }
659 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
659 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
660 assert_nil WikiPage.find_by_title('Child_1').parent
660 assert_nil WikiPage.find_by_title('Child_1').parent
661 end
661 end
662
662
663 def test_get_rename_should_show_target_projects_list
664 @request.session[:user_id] = 2
665 project = Project.find(5)
666 project.enable_module! :wiki
667
668 get :rename, :project_id => 1, :id => 'Another_page'
669 assert_response :success
670 assert_template 'rename'
671
672 assert_select 'select[name=?]', 'wiki_page[wiki_id]' do
673 assert_select 'option', 2
674 assert_select 'option[value=?][selected=selected]', '1', :text => /eCookbook/
675 assert_select 'option[value=?]', project.wiki.id.to_s, :text => /#{project.name}/
676 end
677 end
678
679 def test_rename_with_move
680 @request.session[:user_id] = 2
681 project = Project.find(5)
682 project.enable_module! :wiki
683
684 post :rename, :project_id => 1, :id => 'Another_page',
685 :wiki_page => {
686 :wiki_id => project.wiki.id.to_s,
687 :title => 'Another renamed page',
688 :redirect_existing_links => 1
689 }
690 assert_redirected_to '/projects/private-child/wiki/Another_renamed_page'
691
692 page = WikiPage.find(2)
693 assert_equal project.wiki.id, page.wiki_id
694 end
695
663 def test_destroy_a_page_without_children_should_not_ask_confirmation
696 def test_destroy_a_page_without_children_should_not_ask_confirmation
664 @request.session[:user_id] = 2
697 @request.session[:user_id] = 2
665 delete :destroy, :project_id => 1, :id => 'Child_2'
698 delete :destroy, :project_id => 1, :id => 'Child_2'
666 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
699 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
667 end
700 end
668
701
669 def test_destroy_parent_should_ask_confirmation
702 def test_destroy_parent_should_ask_confirmation
670 @request.session[:user_id] = 2
703 @request.session[:user_id] = 2
671 assert_no_difference('WikiPage.count') do
704 assert_no_difference('WikiPage.count') do
672 delete :destroy, :project_id => 1, :id => 'Another_page'
705 delete :destroy, :project_id => 1, :id => 'Another_page'
673 end
706 end
674 assert_response :success
707 assert_response :success
675 assert_template 'destroy'
708 assert_template 'destroy'
676 assert_select 'form' do
709 assert_select 'form' do
677 assert_select 'input[name=todo][value=nullify]'
710 assert_select 'input[name=todo][value=nullify]'
678 assert_select 'input[name=todo][value=destroy]'
711 assert_select 'input[name=todo][value=destroy]'
679 assert_select 'input[name=todo][value=reassign]'
712 assert_select 'input[name=todo][value=reassign]'
680 end
713 end
681 end
714 end
682
715
683 def test_destroy_parent_with_nullify_should_delete_parent_only
716 def test_destroy_parent_with_nullify_should_delete_parent_only
684 @request.session[:user_id] = 2
717 @request.session[:user_id] = 2
685 assert_difference('WikiPage.count', -1) do
718 assert_difference('WikiPage.count', -1) do
686 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify'
719 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify'
687 end
720 end
688 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
721 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
689 assert_nil WikiPage.find_by_id(2)
722 assert_nil WikiPage.find_by_id(2)
690 end
723 end
691
724
692 def test_destroy_parent_with_cascade_should_delete_descendants
725 def test_destroy_parent_with_cascade_should_delete_descendants
693 @request.session[:user_id] = 2
726 @request.session[:user_id] = 2
694 assert_difference('WikiPage.count', -4) do
727 assert_difference('WikiPage.count', -4) do
695 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy'
728 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy'
696 end
729 end
697 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
730 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
698 assert_nil WikiPage.find_by_id(2)
731 assert_nil WikiPage.find_by_id(2)
699 assert_nil WikiPage.find_by_id(5)
732 assert_nil WikiPage.find_by_id(5)
700 end
733 end
701
734
702 def test_destroy_parent_with_reassign
735 def test_destroy_parent_with_reassign
703 @request.session[:user_id] = 2
736 @request.session[:user_id] = 2
704 assert_difference('WikiPage.count', -1) do
737 assert_difference('WikiPage.count', -1) do
705 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
738 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
706 end
739 end
707 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
740 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
708 assert_nil WikiPage.find_by_id(2)
741 assert_nil WikiPage.find_by_id(2)
709 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
742 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
710 end
743 end
711
744
712 def test_destroy_version
745 def test_destroy_version
713 @request.session[:user_id] = 2
746 @request.session[:user_id] = 2
714 assert_difference 'WikiContent::Version.count', -1 do
747 assert_difference 'WikiContent::Version.count', -1 do
715 assert_no_difference 'WikiContent.count' do
748 assert_no_difference 'WikiContent.count' do
716 assert_no_difference 'WikiPage.count' do
749 assert_no_difference 'WikiPage.count' do
717 delete :destroy_version, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 2
750 delete :destroy_version, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 2
718 assert_redirected_to '/projects/ecookbook/wiki/CookBook_documentation/history'
751 assert_redirected_to '/projects/ecookbook/wiki/CookBook_documentation/history'
719 end
752 end
720 end
753 end
721 end
754 end
722 end
755 end
723
756
724 def test_index
757 def test_index
725 get :index, :project_id => 'ecookbook'
758 get :index, :project_id => 'ecookbook'
726 assert_response :success
759 assert_response :success
727 assert_template 'index'
760 assert_template 'index'
728 pages = assigns(:pages)
761 pages = assigns(:pages)
729 assert_not_nil pages
762 assert_not_nil pages
730 assert_equal Project.find(1).wiki.pages.size, pages.size
763 assert_equal Project.find(1).wiki.pages.size, pages.size
731 assert_equal pages.first.content.updated_on, pages.first.updated_on
764 assert_equal pages.first.content.updated_on, pages.first.updated_on
732
765
733 assert_select 'ul.pages-hierarchy' do
766 assert_select 'ul.pages-hierarchy' do
734 assert_select 'li' do
767 assert_select 'li' do
735 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => 'CookBook documentation'
768 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => 'CookBook documentation'
736 assert_select 'ul li a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image', :text => 'Page with an inline image'
769 assert_select 'ul li a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image', :text => 'Page with an inline image'
737 end
770 end
738 assert_select 'li a[href=?]', '/projects/ecookbook/wiki/Another_page', :text => 'Another page'
771 assert_select 'li a[href=?]', '/projects/ecookbook/wiki/Another_page', :text => 'Another page'
739 end
772 end
740 end
773 end
741
774
742 def test_index_should_include_atom_link
775 def test_index_should_include_atom_link
743 get :index, :project_id => 'ecookbook'
776 get :index, :project_id => 'ecookbook'
744 assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
777 assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
745 end
778 end
746
779
747 def test_export_to_html
780 def test_export_to_html
748 @request.session[:user_id] = 2
781 @request.session[:user_id] = 2
749 get :export, :project_id => 'ecookbook'
782 get :export, :project_id => 'ecookbook'
750
783
751 assert_response :success
784 assert_response :success
752 assert_not_nil assigns(:pages)
785 assert_not_nil assigns(:pages)
753 assert assigns(:pages).any?
786 assert assigns(:pages).any?
754 assert_equal "text/html", @response.content_type
787 assert_equal "text/html", @response.content_type
755
788
756 assert_select "a[name=?]", "CookBook_documentation"
789 assert_select "a[name=?]", "CookBook_documentation"
757 assert_select "a[name=?]", "Another_page"
790 assert_select "a[name=?]", "Another_page"
758 assert_select "a[name=?]", "Page_with_an_inline_image"
791 assert_select "a[name=?]", "Page_with_an_inline_image"
759 end
792 end
760
793
761 def test_export_to_pdf
794 def test_export_to_pdf
762 @request.session[:user_id] = 2
795 @request.session[:user_id] = 2
763 get :export, :project_id => 'ecookbook', :format => 'pdf'
796 get :export, :project_id => 'ecookbook', :format => 'pdf'
764
797
765 assert_response :success
798 assert_response :success
766 assert_not_nil assigns(:pages)
799 assert_not_nil assigns(:pages)
767 assert assigns(:pages).any?
800 assert assigns(:pages).any?
768 assert_equal 'application/pdf', @response.content_type
801 assert_equal 'application/pdf', @response.content_type
769 assert_equal 'attachment; filename="ecookbook.pdf"', @response.headers['Content-Disposition']
802 assert_equal 'attachment; filename="ecookbook.pdf"', @response.headers['Content-Disposition']
770 assert @response.body.starts_with?('%PDF')
803 assert @response.body.starts_with?('%PDF')
771 end
804 end
772
805
773 def test_export_without_permission_should_be_denied
806 def test_export_without_permission_should_be_denied
774 @request.session[:user_id] = 2
807 @request.session[:user_id] = 2
775 Role.find_by_name('Manager').remove_permission! :export_wiki_pages
808 Role.find_by_name('Manager').remove_permission! :export_wiki_pages
776 get :export, :project_id => 'ecookbook'
809 get :export, :project_id => 'ecookbook'
777
810
778 assert_response 403
811 assert_response 403
779 end
812 end
780
813
781 def test_date_index
814 def test_date_index
782 get :date_index, :project_id => 'ecookbook'
815 get :date_index, :project_id => 'ecookbook'
783
816
784 assert_response :success
817 assert_response :success
785 assert_template 'date_index'
818 assert_template 'date_index'
786 assert_not_nil assigns(:pages)
819 assert_not_nil assigns(:pages)
787 assert_not_nil assigns(:pages_by_date)
820 assert_not_nil assigns(:pages_by_date)
788
821
789 assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
822 assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
790 end
823 end
791
824
792 def test_not_found
825 def test_not_found
793 get :show, :project_id => 999
826 get :show, :project_id => 999
794 assert_response 404
827 assert_response 404
795 end
828 end
796
829
797 def test_protect_page
830 def test_protect_page
798 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
831 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
799 assert !page.protected?
832 assert !page.protected?
800 @request.session[:user_id] = 2
833 @request.session[:user_id] = 2
801 post :protect, :project_id => 1, :id => page.title, :protected => '1'
834 post :protect, :project_id => 1, :id => page.title, :protected => '1'
802 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
835 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
803 assert page.reload.protected?
836 assert page.reload.protected?
804 end
837 end
805
838
806 def test_unprotect_page
839 def test_unprotect_page
807 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
840 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
808 assert page.protected?
841 assert page.protected?
809 @request.session[:user_id] = 2
842 @request.session[:user_id] = 2
810 post :protect, :project_id => 1, :id => page.title, :protected => '0'
843 post :protect, :project_id => 1, :id => page.title, :protected => '0'
811 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
844 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
812 assert !page.reload.protected?
845 assert !page.reload.protected?
813 end
846 end
814
847
815 def test_show_page_with_edit_link
848 def test_show_page_with_edit_link
816 @request.session[:user_id] = 2
849 @request.session[:user_id] = 2
817 get :show, :project_id => 1
850 get :show, :project_id => 1
818 assert_response :success
851 assert_response :success
819 assert_template 'show'
852 assert_template 'show'
820 assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit'
853 assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit'
821 end
854 end
822
855
823 def test_show_page_without_edit_link
856 def test_show_page_without_edit_link
824 @request.session[:user_id] = 4
857 @request.session[:user_id] = 4
825 get :show, :project_id => 1
858 get :show, :project_id => 1
826 assert_response :success
859 assert_response :success
827 assert_template 'show'
860 assert_template 'show'
828 assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit', 0
861 assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit', 0
829 end
862 end
830
863
831 def test_show_pdf
864 def test_show_pdf
832 @request.session[:user_id] = 2
865 @request.session[:user_id] = 2
833 get :show, :project_id => 1, :format => 'pdf'
866 get :show, :project_id => 1, :format => 'pdf'
834 assert_response :success
867 assert_response :success
835 assert_not_nil assigns(:page)
868 assert_not_nil assigns(:page)
836 assert_equal 'application/pdf', @response.content_type
869 assert_equal 'application/pdf', @response.content_type
837 assert_equal 'attachment; filename="CookBook_documentation.pdf"',
870 assert_equal 'attachment; filename="CookBook_documentation.pdf"',
838 @response.headers['Content-Disposition']
871 @response.headers['Content-Disposition']
839 end
872 end
840
873
841 def test_show_html
874 def test_show_html
842 @request.session[:user_id] = 2
875 @request.session[:user_id] = 2
843 get :show, :project_id => 1, :format => 'html'
876 get :show, :project_id => 1, :format => 'html'
844 assert_response :success
877 assert_response :success
845 assert_not_nil assigns(:page)
878 assert_not_nil assigns(:page)
846 assert_equal 'text/html', @response.content_type
879 assert_equal 'text/html', @response.content_type
847 assert_equal 'attachment; filename="CookBook_documentation.html"',
880 assert_equal 'attachment; filename="CookBook_documentation.html"',
848 @response.headers['Content-Disposition']
881 @response.headers['Content-Disposition']
849 assert_select 'h1', :text => /CookBook documentation/
882 assert_select 'h1', :text => /CookBook documentation/
850 end
883 end
851
884
852 def test_show_versioned_html
885 def test_show_versioned_html
853 @request.session[:user_id] = 2
886 @request.session[:user_id] = 2
854 get :show, :project_id => 1, :format => 'html', :version => 2
887 get :show, :project_id => 1, :format => 'html', :version => 2
855 assert_response :success
888 assert_response :success
856 assert_not_nil assigns(:content)
889 assert_not_nil assigns(:content)
857 assert_equal 2, assigns(:content).version
890 assert_equal 2, assigns(:content).version
858 assert_equal 'text/html', @response.content_type
891 assert_equal 'text/html', @response.content_type
859 assert_equal 'attachment; filename="CookBook_documentation.html"',
892 assert_equal 'attachment; filename="CookBook_documentation.html"',
860 @response.headers['Content-Disposition']
893 @response.headers['Content-Disposition']
861 assert_select 'h1', :text => /CookBook documentation/
894 assert_select 'h1', :text => /CookBook documentation/
862 end
895 end
863
896
864 def test_show_txt
897 def test_show_txt
865 @request.session[:user_id] = 2
898 @request.session[:user_id] = 2
866 get :show, :project_id => 1, :format => 'txt'
899 get :show, :project_id => 1, :format => 'txt'
867 assert_response :success
900 assert_response :success
868 assert_not_nil assigns(:page)
901 assert_not_nil assigns(:page)
869 assert_equal 'text/plain', @response.content_type
902 assert_equal 'text/plain', @response.content_type
870 assert_equal 'attachment; filename="CookBook_documentation.txt"',
903 assert_equal 'attachment; filename="CookBook_documentation.txt"',
871 @response.headers['Content-Disposition']
904 @response.headers['Content-Disposition']
872 assert_include 'h1. CookBook documentation', @response.body
905 assert_include 'h1. CookBook documentation', @response.body
873 end
906 end
874
907
875 def test_show_versioned_txt
908 def test_show_versioned_txt
876 @request.session[:user_id] = 2
909 @request.session[:user_id] = 2
877 get :show, :project_id => 1, :format => 'txt', :version => 2
910 get :show, :project_id => 1, :format => 'txt', :version => 2
878 assert_response :success
911 assert_response :success
879 assert_not_nil assigns(:content)
912 assert_not_nil assigns(:content)
880 assert_equal 2, assigns(:content).version
913 assert_equal 2, assigns(:content).version
881 assert_equal 'text/plain', @response.content_type
914 assert_equal 'text/plain', @response.content_type
882 assert_equal 'attachment; filename="CookBook_documentation.txt"',
915 assert_equal 'attachment; filename="CookBook_documentation.txt"',
883 @response.headers['Content-Disposition']
916 @response.headers['Content-Disposition']
884 assert_include 'h1. CookBook documentation', @response.body
917 assert_include 'h1. CookBook documentation', @response.body
885 end
918 end
886
919
887 def test_edit_unprotected_page
920 def test_edit_unprotected_page
888 # Non members can edit unprotected wiki pages
921 # Non members can edit unprotected wiki pages
889 @request.session[:user_id] = 4
922 @request.session[:user_id] = 4
890 get :edit, :project_id => 1, :id => 'Another_page'
923 get :edit, :project_id => 1, :id => 'Another_page'
891 assert_response :success
924 assert_response :success
892 assert_template 'edit'
925 assert_template 'edit'
893 end
926 end
894
927
895 def test_edit_protected_page_by_nonmember
928 def test_edit_protected_page_by_nonmember
896 # Non members can't edit protected wiki pages
929 # Non members can't edit protected wiki pages
897 @request.session[:user_id] = 4
930 @request.session[:user_id] = 4
898 get :edit, :project_id => 1, :id => 'CookBook_documentation'
931 get :edit, :project_id => 1, :id => 'CookBook_documentation'
899 assert_response 403
932 assert_response 403
900 end
933 end
901
934
902 def test_edit_protected_page_by_member
935 def test_edit_protected_page_by_member
903 @request.session[:user_id] = 2
936 @request.session[:user_id] = 2
904 get :edit, :project_id => 1, :id => 'CookBook_documentation'
937 get :edit, :project_id => 1, :id => 'CookBook_documentation'
905 assert_response :success
938 assert_response :success
906 assert_template 'edit'
939 assert_template 'edit'
907 end
940 end
908
941
909 def test_history_of_non_existing_page_should_return_404
942 def test_history_of_non_existing_page_should_return_404
910 get :history, :project_id => 1, :id => 'Unknown_page'
943 get :history, :project_id => 1, :id => 'Unknown_page'
911 assert_response 404
944 assert_response 404
912 end
945 end
913
946
914 def test_add_attachment
947 def test_add_attachment
915 @request.session[:user_id] = 2
948 @request.session[:user_id] = 2
916 assert_difference 'Attachment.count' do
949 assert_difference 'Attachment.count' do
917 post :add_attachment, :project_id => 1, :id => 'CookBook_documentation',
950 post :add_attachment, :project_id => 1, :id => 'CookBook_documentation',
918 :attachments => {
951 :attachments => {
919 '1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'),
952 '1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'),
920 'description' => 'test file'}
953 'description' => 'test file'}
921 }
954 }
922 end
955 end
923 attachment = Attachment.order('id DESC').first
956 attachment = Attachment.order('id DESC').first
924 assert_equal Wiki.find(1).find_page('CookBook_documentation'), attachment.container
957 assert_equal Wiki.find(1).find_page('CookBook_documentation'), attachment.container
925 end
958 end
926 end
959 end
@@ -1,163 +1,183
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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
19
20 class WikiPageTest < ActiveSupport::TestCase
20 class WikiPageTest < ActiveSupport::TestCase
21 fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
21 fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
22
22
23 def setup
23 def setup
24 @wiki = Wiki.find(1)
24 @wiki = Wiki.find(1)
25 @page = @wiki.pages.first
25 @page = @wiki.pages.first
26 end
26 end
27
27
28 def test_create
28 def test_create
29 page = WikiPage.new(:wiki => @wiki)
29 page = WikiPage.new(:wiki => @wiki)
30 assert !page.save
30 assert !page.save
31 assert_equal 1, page.errors.count
31 assert_equal 1, page.errors.count
32
32
33 page.title = "Page"
33 page.title = "Page"
34 assert page.save
34 assert page.save
35 page.reload
35 page.reload
36 assert !page.protected?
36 assert !page.protected?
37
37
38 @wiki.reload
38 @wiki.reload
39 assert @wiki.pages.include?(page)
39 assert @wiki.pages.include?(page)
40 end
40 end
41
41
42 def test_sidebar_should_be_protected_by_default
42 def test_sidebar_should_be_protected_by_default
43 page = @wiki.find_or_new_page('sidebar')
43 page = @wiki.find_or_new_page('sidebar')
44 assert page.new_record?
44 assert page.new_record?
45 assert page.protected?
45 assert page.protected?
46 end
46 end
47
47
48 def test_find_or_new_page
48 def test_find_or_new_page
49 page = @wiki.find_or_new_page("CookBook documentation")
49 page = @wiki.find_or_new_page("CookBook documentation")
50 assert_kind_of WikiPage, page
50 assert_kind_of WikiPage, page
51 assert !page.new_record?
51 assert !page.new_record?
52
52
53 page = @wiki.find_or_new_page("Non existing page")
53 page = @wiki.find_or_new_page("Non existing page")
54 assert_kind_of WikiPage, page
54 assert_kind_of WikiPage, page
55 assert page.new_record?
55 assert page.new_record?
56 end
56 end
57
57
58 def test_parent_title
58 def test_parent_title
59 page = WikiPage.find_by_title('Another_page')
59 page = WikiPage.find_by_title('Another_page')
60 assert_nil page.parent_title
60 assert_nil page.parent_title
61
61
62 page = WikiPage.find_by_title('Page_with_an_inline_image')
62 page = WikiPage.find_by_title('Page_with_an_inline_image')
63 assert_equal 'CookBook documentation', page.parent_title
63 assert_equal 'CookBook documentation', page.parent_title
64 end
64 end
65
65
66 def test_assign_parent
66 def test_assign_parent
67 page = WikiPage.find_by_title('Another_page')
67 page = WikiPage.find_by_title('Another_page')
68 page.parent_title = 'CookBook documentation'
68 page.parent_title = 'CookBook documentation'
69 assert page.save
69 assert page.save
70 page.reload
70 page.reload
71 assert_equal WikiPage.find_by_title('CookBook_documentation'), page.parent
71 assert_equal WikiPage.find_by_title('CookBook_documentation'), page.parent
72 end
72 end
73
73
74 def test_unassign_parent
74 def test_unassign_parent
75 page = WikiPage.find_by_title('Page_with_an_inline_image')
75 page = WikiPage.find_by_title('Page_with_an_inline_image')
76 page.parent_title = ''
76 page.parent_title = ''
77 assert page.save
77 assert page.save
78 page.reload
78 page.reload
79 assert_nil page.parent
79 assert_nil page.parent
80 end
80 end
81
81
82 def test_parent_validation
82 def test_parent_validation
83 page = WikiPage.find_by_title('CookBook_documentation')
83 page = WikiPage.find_by_title('CookBook_documentation')
84
84
85 # A page that doesn't exist
85 # A page that doesn't exist
86 page.parent_title = 'Unknown title'
86 page.parent_title = 'Unknown title'
87 assert !page.save
87 assert !page.save
88 assert_include I18n.translate('activerecord.errors.messages.invalid'),
88 assert_include I18n.translate('activerecord.errors.messages.invalid'),
89 page.errors[:parent_title]
89 page.errors[:parent_title]
90 # A child page
90 # A child page
91 page.parent_title = 'Page_with_an_inline_image'
91 page.parent_title = 'Page_with_an_inline_image'
92 assert !page.save
92 assert !page.save
93 assert_include I18n.translate('activerecord.errors.messages.circular_dependency'),
93 assert_include I18n.translate('activerecord.errors.messages.circular_dependency'),
94 page.errors[:parent_title]
94 page.errors[:parent_title]
95 # The page itself
95 # The page itself
96 page.parent_title = 'CookBook_documentation'
96 page.parent_title = 'CookBook_documentation'
97 assert !page.save
97 assert !page.save
98 assert_include I18n.translate('activerecord.errors.messages.circular_dependency'),
98 assert_include I18n.translate('activerecord.errors.messages.circular_dependency'),
99 page.errors[:parent_title]
99 page.errors[:parent_title]
100 page.parent_title = 'Another_page'
100 page.parent_title = 'Another_page'
101 assert page.save
101 assert page.save
102 end
102 end
103
103
104 def test_move_child_should_clear_parent
105 parent = WikiPage.create!(:wiki_id => 1, :title => 'Parent')
106 child = WikiPage.create!(:wiki_id => 1, :title => 'Child', :parent => parent)
107
108 child.wiki_id = 2
109 child.save!
110 assert_equal nil, child.reload.parent_id
111 end
112
113 def test_move_parent_should_move_child_page
114 parent = WikiPage.create!(:wiki_id => 1, :title => 'Parent')
115 child = WikiPage.create!(:wiki_id => 1, :title => 'Child', :parent => parent)
116 parent.reload
117
118 parent.wiki_id = 2
119 parent.save!
120 assert_equal 2, child.reload.wiki_id
121 assert_equal parent, child.parent
122 end
123
104 def test_destroy
124 def test_destroy
105 page = WikiPage.find(1)
125 page = WikiPage.find(1)
106 page.destroy
126 page.destroy
107 assert_nil WikiPage.find_by_id(1)
127 assert_nil WikiPage.find_by_id(1)
108 # make sure that page content and its history are deleted
128 # make sure that page content and its history are deleted
109 assert_equal 0, WikiContent.where(:page_id => 1).count
129 assert_equal 0, WikiContent.where(:page_id => 1).count
110 assert_equal 0, WikiContent.versioned_class.where(:page_id => 1).count
130 assert_equal 0, WikiContent.versioned_class.where(:page_id => 1).count
111 end
131 end
112
132
113 def test_destroy_should_not_nullify_children
133 def test_destroy_should_not_nullify_children
114 page = WikiPage.find(2)
134 page = WikiPage.find(2)
115 child_ids = page.child_ids
135 child_ids = page.child_ids
116 assert child_ids.any?
136 assert child_ids.any?
117 page.destroy
137 page.destroy
118 assert_nil WikiPage.find_by_id(2)
138 assert_nil WikiPage.find_by_id(2)
119
139
120 children = WikiPage.where(:id => child_ids)
140 children = WikiPage.where(:id => child_ids)
121 assert_equal child_ids.size, children.count
141 assert_equal child_ids.size, children.count
122 children.each do |child|
142 children.each do |child|
123 assert_nil child.parent_id
143 assert_nil child.parent_id
124 end
144 end
125 end
145 end
126
146
127 def test_updated_on_eager_load
147 def test_updated_on_eager_load
128 page = WikiPage.with_updated_on.order('id').first
148 page = WikiPage.with_updated_on.order('id').first
129 assert page.is_a?(WikiPage)
149 assert page.is_a?(WikiPage)
130 assert_not_nil page.read_attribute(:updated_on)
150 assert_not_nil page.read_attribute(:updated_on)
131 assert_equal Time.gm(2007, 3, 6, 23, 10, 51), page.content.updated_on
151 assert_equal Time.gm(2007, 3, 6, 23, 10, 51), page.content.updated_on
132 assert_equal page.content.updated_on, page.updated_on
152 assert_equal page.content.updated_on, page.updated_on
133 assert_not_nil page.read_attribute(:version)
153 assert_not_nil page.read_attribute(:version)
134 end
154 end
135
155
136 def test_descendants
156 def test_descendants
137 page = WikiPage.create!(:wiki => @wiki, :title => 'Parent')
157 page = WikiPage.create!(:wiki => @wiki, :title => 'Parent')
138 child1 = WikiPage.create!(:wiki => @wiki, :title => 'Child1', :parent => page)
158 child1 = WikiPage.create!(:wiki => @wiki, :title => 'Child1', :parent => page)
139 child11 = WikiPage.create!(:wiki => @wiki, :title => 'Child11', :parent => child1)
159 child11 = WikiPage.create!(:wiki => @wiki, :title => 'Child11', :parent => child1)
140 child111 = WikiPage.create!(:wiki => @wiki, :title => 'Child111', :parent => child11)
160 child111 = WikiPage.create!(:wiki => @wiki, :title => 'Child111', :parent => child11)
141 child2 = WikiPage.create!(:wiki => @wiki, :title => 'Child2', :parent => page)
161 child2 = WikiPage.create!(:wiki => @wiki, :title => 'Child2', :parent => page)
142
162
143 assert_equal %w(Child1 Child11 Child111 Child2), page.descendants.map(&:title).sort
163 assert_equal %w(Child1 Child11 Child111 Child2), page.descendants.map(&:title).sort
144 assert_equal %w(Child1 Child11 Child111 Child2), page.descendants(nil).map(&:title).sort
164 assert_equal %w(Child1 Child11 Child111 Child2), page.descendants(nil).map(&:title).sort
145 assert_equal %w(Child1 Child11 Child2), page.descendants(2).map(&:title).sort
165 assert_equal %w(Child1 Child11 Child2), page.descendants(2).map(&:title).sort
146 assert_equal %w(Child1 Child2), page.descendants(1).map(&:title).sort
166 assert_equal %w(Child1 Child2), page.descendants(1).map(&:title).sort
147
167
148 assert_equal %w(Child1 Child11 Child111 Child2 Parent), page.self_and_descendants.map(&:title).sort
168 assert_equal %w(Child1 Child11 Child111 Child2 Parent), page.self_and_descendants.map(&:title).sort
149 assert_equal %w(Child1 Child11 Child111 Child2 Parent), page.self_and_descendants(nil).map(&:title).sort
169 assert_equal %w(Child1 Child11 Child111 Child2 Parent), page.self_and_descendants(nil).map(&:title).sort
150 assert_equal %w(Child1 Child11 Child2 Parent), page.self_and_descendants(2).map(&:title).sort
170 assert_equal %w(Child1 Child11 Child2 Parent), page.self_and_descendants(2).map(&:title).sort
151 assert_equal %w(Child1 Child2 Parent), page.self_and_descendants(1).map(&:title).sort
171 assert_equal %w(Child1 Child2 Parent), page.self_and_descendants(1).map(&:title).sort
152 end
172 end
153
173
154 def test_diff_for_page_with_deleted_version_should_pick_the_previous_available_version
174 def test_diff_for_page_with_deleted_version_should_pick_the_previous_available_version
155 WikiContent::Version.find_by_page_id_and_version(1, 2).destroy
175 WikiContent::Version.find_by_page_id_and_version(1, 2).destroy
156
176
157 page = WikiPage.find(1)
177 page = WikiPage.find(1)
158 diff = page.diff(3)
178 diff = page.diff(3)
159 assert_not_nil diff
179 assert_not_nil diff
160 assert_equal 3, diff.content_to.version
180 assert_equal 3, diff.content_to.version
161 assert_equal 1, diff.content_from.version
181 assert_equal 1, diff.content_from.version
162 end
182 end
163 end
183 end
@@ -1,74 +1,97
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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
19
20 class WikiRedirectTest < ActiveSupport::TestCase
20 class WikiRedirectTest < ActiveSupport::TestCase
21 fixtures :projects, :wikis, :wiki_pages
21 fixtures :projects, :wikis, :wiki_pages
22
22
23 def setup
23 def setup
24 @wiki = Wiki.find(1)
24 @wiki = Wiki.find(1)
25 @original = WikiPage.create(:wiki => @wiki, :title => 'Original title')
25 @original = WikiPage.create(:wiki => @wiki, :title => 'Original title')
26 end
26 end
27
27
28 def test_create_redirect
28 def test_create_redirect_on_rename
29 @original.title = 'New title'
29 @original.title = 'New title'
30 assert @original.save
30 @original.save!
31 @original.reload
32
31
33 assert_equal 'New_title', @original.title
32 redirect = @wiki.redirects.find_by_title('Original_title')
34 assert @wiki.redirects.find_by_title('Original_title')
33 assert_not_nil redirect
35 assert @wiki.find_page('Original title')
34 assert_equal 1, redirect.redirects_to_wiki_id
36 assert @wiki.find_page('ORIGINAL title')
35 assert_equal 'New_title', redirect.redirects_to
36 assert_equal @original, redirect.target_page
37 end
38
39 def test_create_redirect_on_move
40 @original.wiki_id = 2
41 @original.save!
42
43 redirect = @wiki.redirects.find_by_title('Original_title')
44 assert_not_nil redirect
45 assert_equal 2, redirect.redirects_to_wiki_id
46 assert_equal 'Original_title', redirect.redirects_to
47 assert_equal @original, redirect.target_page
48 end
49
50 def test_create_redirect_on_rename_and_move
51 @original.title = 'New title'
52 @original.wiki_id = 2
53 @original.save!
54
55 redirect = @wiki.redirects.find_by_title('Original_title')
56 assert_not_nil redirect
57 assert_equal 2, redirect.redirects_to_wiki_id
58 assert_equal 'New_title', redirect.redirects_to
59 assert_equal @original, redirect.target_page
37 end
60 end
38
61
39 def test_update_redirect
62 def test_update_redirect
40 # create a redirect that point to this page
63 # create a redirect that point to this page
41 assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title')
64 assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title')
42
65
43 @original.title = 'New title'
66 @original.title = 'New title'
44 @original.save
67 @original.save
45 # make sure the old page now points to the new page
68 # make sure the old page now points to the new page
46 assert_equal 'New_title', @wiki.find_page('An old page').title
69 assert_equal 'New_title', @wiki.find_page('An old page').title
47 end
70 end
48
71
49 def test_reverse_rename
72 def test_reverse_rename
50 # create a redirect that point to this page
73 # create a redirect that point to this page
51 assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title')
74 assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title')
52
75
53 @original.title = 'An old page'
76 @original.title = 'An old page'
54 @original.save
77 @original.save
55 assert !@wiki.redirects.find_by_title_and_redirects_to('An_old_page', 'An_old_page')
78 assert !@wiki.redirects.find_by_title_and_redirects_to('An_old_page', 'An_old_page')
56 assert @wiki.redirects.find_by_title_and_redirects_to('Original_title', 'An_old_page')
79 assert @wiki.redirects.find_by_title_and_redirects_to('Original_title', 'An_old_page')
57 end
80 end
58
81
59 def test_rename_to_already_redirected
82 def test_rename_to_already_redirected
60 assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Other_page')
83 assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Other_page')
61
84
62 @original.title = 'An old page'
85 @original.title = 'An old page'
63 @original.save
86 @original.save
64 # this redirect have to be removed since 'An old page' page now exists
87 # this redirect have to be removed since 'An old page' page now exists
65 assert !@wiki.redirects.find_by_title_and_redirects_to('An_old_page', 'Other_page')
88 assert !@wiki.redirects.find_by_title_and_redirects_to('An_old_page', 'Other_page')
66 end
89 end
67
90
68 def test_redirects_removed_when_deleting_page
91 def test_redirects_removed_when_deleting_page
69 assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title')
92 assert WikiRedirect.create(:wiki => @wiki, :title => 'An_old_page', :redirects_to => 'Original_title')
70
93
71 @original.destroy
94 @original.destroy
72 assert_nil @wiki.redirects.first
95 assert_nil @wiki.redirects.first
73 end
96 end
74 end
97 end
@@ -1,100 +1,114
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2014 Jean-Philippe Lang
4 # Copyright (C) 2006-2014 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 require File.expand_path('../../test_helper', __FILE__)
20 require File.expand_path('../../test_helper', __FILE__)
21
21
22 class WikiTest < ActiveSupport::TestCase
22 class WikiTest < ActiveSupport::TestCase
23 fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
23 fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
24
24
25 def test_create
25 def test_create
26 wiki = Wiki.new(:project => Project.find(3))
26 wiki = Wiki.new(:project => Project.find(3))
27 assert !wiki.save
27 assert !wiki.save
28 assert_equal 1, wiki.errors.count
28 assert_equal 1, wiki.errors.count
29
29
30 wiki.start_page = "Start page"
30 wiki.start_page = "Start page"
31 assert wiki.save
31 assert wiki.save
32 end
32 end
33
33
34 def test_update
34 def test_update
35 @wiki = Wiki.find(1)
35 @wiki = Wiki.find(1)
36 @wiki.start_page = "Another start page"
36 @wiki.start_page = "Another start page"
37 assert @wiki.save
37 assert @wiki.save
38 @wiki.reload
38 @wiki.reload
39 assert_equal "Another start page", @wiki.start_page
39 assert_equal "Another start page", @wiki.start_page
40 end
40 end
41
41
42 def test_find_page_should_not_be_case_sensitive
42 def test_find_page_should_not_be_case_sensitive
43 wiki = Wiki.find(1)
43 wiki = Wiki.find(1)
44 page = WikiPage.find(2)
44 page = WikiPage.find(2)
45
45
46 assert_equal page, wiki.find_page('Another_page')
46 assert_equal page, wiki.find_page('Another_page')
47 assert_equal page, wiki.find_page('Another page')
47 assert_equal page, wiki.find_page('Another page')
48 assert_equal page, wiki.find_page('ANOTHER page')
48 assert_equal page, wiki.find_page('ANOTHER page')
49 end
49 end
50
50
51 def test_find_page_with_cyrillic_characters
51 def test_find_page_with_cyrillic_characters
52 wiki = Wiki.find(1)
52 wiki = Wiki.find(1)
53 page = WikiPage.find(10)
53 page = WikiPage.find(10)
54 assert_equal page, wiki.find_page('Π­Ρ‚ΠΈΠΊΠ°_ΠΌΠ΅Π½Π΅Π΄ΠΆΠΌΠ΅Π½Ρ‚Π°')
54 assert_equal page, wiki.find_page('Π­Ρ‚ΠΈΠΊΠ°_ΠΌΠ΅Π½Π΅Π΄ΠΆΠΌΠ΅Π½Ρ‚Π°')
55 end
55 end
56
56
57 def test_find_page_with_backslashes
57 def test_find_page_with_backslashes
58 wiki = Wiki.find(1)
58 wiki = Wiki.find(1)
59 page = WikiPage.create!(:wiki => wiki, :title => '2009\\02\\09')
59 page = WikiPage.create!(:wiki => wiki, :title => '2009\\02\\09')
60 assert_equal page, wiki.find_page('2009\\02\\09')
60 assert_equal page, wiki.find_page('2009\\02\\09')
61 end
61 end
62
62
63 def test_find_page_without_redirect
63 def test_find_page_without_redirect
64 wiki = Wiki.find(1)
64 wiki = Wiki.find(1)
65 page = wiki.find_page('Another_page')
65 page = wiki.find_page('Another_page')
66 assert_not_nil page
66 assert_not_nil page
67 assert_equal 'Another_page', page.title
67 assert_equal 'Another_page', page.title
68 assert_equal false, wiki.page_found_with_redirect?
68 assert_equal false, wiki.page_found_with_redirect?
69 end
69 end
70
70
71 def test_find_page_with_redirect
71 def test_find_page_with_redirect
72 wiki = Wiki.find(1)
72 wiki = Wiki.find(1)
73 WikiRedirect.create!(:wiki => wiki, :title => 'Old_title', :redirects_to => 'Another_page')
73 WikiRedirect.create!(:wiki => wiki, :title => 'Old_title', :redirects_to => 'Another_page')
74 page = wiki.find_page('Old_title')
74 page = wiki.find_page('Old_title')
75 assert_not_nil page
75 assert_not_nil page
76 assert_equal 'Another_page', page.title
76 assert_equal 'Another_page', page.title
77 assert_equal true, wiki.page_found_with_redirect?
77 assert_equal true, wiki.page_found_with_redirect?
78 end
78 end
79
79
80 def test_titleize
80 def test_titleize
81 ja_test = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
81 ja_test = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
82 assert_equal 'Page_title_with_CAPITALES', Wiki.titleize('page title with CAPITALES')
82 assert_equal 'Page_title_with_CAPITALES', Wiki.titleize('page title with CAPITALES')
83 assert_equal ja_test, Wiki.titleize(ja_test)
83 assert_equal ja_test, Wiki.titleize(ja_test)
84 end
84 end
85
85
86 def test_sidebar_should_return_nil_if_undefined
86 def test_sidebar_should_return_nil_if_undefined
87 @wiki = Wiki.find(1)
87 @wiki = Wiki.find(1)
88 assert_nil @wiki.sidebar
88 assert_nil @wiki.sidebar
89 end
89 end
90
90
91 def test_sidebar_should_return_a_wiki_page_if_defined
91 def test_sidebar_should_return_a_wiki_page_if_defined
92 @wiki = Wiki.find(1)
92 @wiki = Wiki.find(1)
93 page = @wiki.pages.new(:title => 'Sidebar')
93 page = @wiki.pages.new(:title => 'Sidebar')
94 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
94 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
95 page.save!
95 page.save!
96
96
97 assert_kind_of WikiPage, @wiki.sidebar
97 assert_kind_of WikiPage, @wiki.sidebar
98 assert_equal 'Sidebar', @wiki.sidebar.title
98 assert_equal 'Sidebar', @wiki.sidebar.title
99 end
99 end
100
101 def test_destroy_should_remove_redirects_from_the_wiki
102 WikiRedirect.create!(:wiki_id => 1, :title => 'Foo', :redirects_to_wiki_id => 2, :redirects_to => 'Bar')
103
104 Wiki.find(1).destroy
105 assert_equal 0, WikiRedirect.where(:wiki_id => 1).count
106 end
107
108 def test_destroy_should_remove_redirects_to_the_wiki
109 WikiRedirect.create!(:wiki_id => 2, :title => 'Foo', :redirects_to_wiki_id => 1, :redirects_to => 'Bar')
110
111 Wiki.find(1).destroy
112 assert_equal 0, WikiRedirect.where(:redirects_to_wiki_id => 1).count
113 end
100 end
114 end
General Comments 0
You need to be logged in to leave comments. Login now