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