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