##// END OF EJS Templates
Removed the "New issue" menu item (#6204)....
Jean-Philippe Lang -
r14962:dcc569fa34f7
parent child
Show More
@@ -1,539 +1,538
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class IssuesController < ApplicationController
18 class IssuesController < ApplicationController
19 menu_item :new_issue, :only => [:new, :create]
20 default_search_scope :issues
19 default_search_scope :issues
21
20
22 before_filter :find_issue, :only => [:show, :edit, :update]
21 before_filter :find_issue, :only => [:show, :edit, :update]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
22 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
24 before_filter :authorize, :except => [:index, :new, :create]
23 before_filter :authorize, :except => [:index, :new, :create]
25 before_filter :find_optional_project, :only => [:index, :new, :create]
24 before_filter :find_optional_project, :only => [:index, :new, :create]
26 before_filter :build_new_issue_from_params, :only => [:new, :create]
25 before_filter :build_new_issue_from_params, :only => [:new, :create]
27 accept_rss_auth :index, :show
26 accept_rss_auth :index, :show
28 accept_api_auth :index, :show, :create, :update, :destroy
27 accept_api_auth :index, :show, :create, :update, :destroy
29
28
30 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
29 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
31
30
32 helper :journals
31 helper :journals
33 helper :projects
32 helper :projects
34 helper :custom_fields
33 helper :custom_fields
35 helper :issue_relations
34 helper :issue_relations
36 helper :watchers
35 helper :watchers
37 helper :attachments
36 helper :attachments
38 helper :queries
37 helper :queries
39 include QueriesHelper
38 include QueriesHelper
40 helper :repositories
39 helper :repositories
41 helper :sort
40 helper :sort
42 include SortHelper
41 include SortHelper
43 helper :timelog
42 helper :timelog
44
43
45 def index
44 def index
46 retrieve_query
45 retrieve_query
47 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
46 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
48 sort_update(@query.sortable_columns)
47 sort_update(@query.sortable_columns)
49 @query.sort_criteria = sort_criteria.to_a
48 @query.sort_criteria = sort_criteria.to_a
50
49
51 if @query.valid?
50 if @query.valid?
52 case params[:format]
51 case params[:format]
53 when 'csv', 'pdf'
52 when 'csv', 'pdf'
54 @limit = Setting.issues_export_limit.to_i
53 @limit = Setting.issues_export_limit.to_i
55 if params[:columns] == 'all'
54 if params[:columns] == 'all'
56 @query.column_names = @query.available_inline_columns.map(&:name)
55 @query.column_names = @query.available_inline_columns.map(&:name)
57 end
56 end
58 when 'atom'
57 when 'atom'
59 @limit = Setting.feeds_limit.to_i
58 @limit = Setting.feeds_limit.to_i
60 when 'xml', 'json'
59 when 'xml', 'json'
61 @offset, @limit = api_offset_and_limit
60 @offset, @limit = api_offset_and_limit
62 @query.column_names = %w(author)
61 @query.column_names = %w(author)
63 else
62 else
64 @limit = per_page_option
63 @limit = per_page_option
65 end
64 end
66
65
67 @issue_count = @query.issue_count
66 @issue_count = @query.issue_count
68 @issue_pages = Paginator.new @issue_count, @limit, params['page']
67 @issue_pages = Paginator.new @issue_count, @limit, params['page']
69 @offset ||= @issue_pages.offset
68 @offset ||= @issue_pages.offset
70 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
69 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
71 :order => sort_clause,
70 :order => sort_clause,
72 :offset => @offset,
71 :offset => @offset,
73 :limit => @limit)
72 :limit => @limit)
74 @issue_count_by_group = @query.issue_count_by_group
73 @issue_count_by_group = @query.issue_count_by_group
75
74
76 respond_to do |format|
75 respond_to do |format|
77 format.html { render :template => 'issues/index', :layout => !request.xhr? }
76 format.html { render :template => 'issues/index', :layout => !request.xhr? }
78 format.api {
77 format.api {
79 Issue.load_visible_relations(@issues) if include_in_api_response?('relations')
78 Issue.load_visible_relations(@issues) if include_in_api_response?('relations')
80 }
79 }
81 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
80 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
82 format.csv { send_data(query_to_csv(@issues, @query, params[:csv]), :type => 'text/csv; header=present', :filename => 'issues.csv') }
81 format.csv { send_data(query_to_csv(@issues, @query, params[:csv]), :type => 'text/csv; header=present', :filename => 'issues.csv') }
83 format.pdf { send_file_headers! :type => 'application/pdf', :filename => 'issues.pdf' }
82 format.pdf { send_file_headers! :type => 'application/pdf', :filename => 'issues.pdf' }
84 end
83 end
85 else
84 else
86 respond_to do |format|
85 respond_to do |format|
87 format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
86 format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
88 format.any(:atom, :csv, :pdf) { render(:nothing => true) }
87 format.any(:atom, :csv, :pdf) { render(:nothing => true) }
89 format.api { render_validation_errors(@query) }
88 format.api { render_validation_errors(@query) }
90 end
89 end
91 end
90 end
92 rescue ActiveRecord::RecordNotFound
91 rescue ActiveRecord::RecordNotFound
93 render_404
92 render_404
94 end
93 end
95
94
96 def show
95 def show
97 @journals = @issue.journals.includes(:user, :details).
96 @journals = @issue.journals.includes(:user, :details).
98 references(:user, :details).
97 references(:user, :details).
99 reorder(:created_on, :id).to_a
98 reorder(:created_on, :id).to_a
100 @journals.each_with_index {|j,i| j.indice = i+1}
99 @journals.each_with_index {|j,i| j.indice = i+1}
101 @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
100 @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
102 Journal.preload_journals_details_custom_fields(@journals)
101 Journal.preload_journals_details_custom_fields(@journals)
103 @journals.select! {|journal| journal.notes? || journal.visible_details.any?}
102 @journals.select! {|journal| journal.notes? || journal.visible_details.any?}
104 @journals.reverse! if User.current.wants_comments_in_reverse_order?
103 @journals.reverse! if User.current.wants_comments_in_reverse_order?
105
104
106 @changesets = @issue.changesets.visible.preload(:repository, :user).to_a
105 @changesets = @issue.changesets.visible.preload(:repository, :user).to_a
107 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
106 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
108
107
109 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
108 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
110 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
109 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
111 @priorities = IssuePriority.active
110 @priorities = IssuePriority.active
112 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
111 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
113 @relation = IssueRelation.new
112 @relation = IssueRelation.new
114
113
115 respond_to do |format|
114 respond_to do |format|
116 format.html {
115 format.html {
117 retrieve_previous_and_next_issue_ids
116 retrieve_previous_and_next_issue_ids
118 render :template => 'issues/show'
117 render :template => 'issues/show'
119 }
118 }
120 format.api
119 format.api
121 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
120 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
122 format.pdf {
121 format.pdf {
123 send_file_headers! :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf"
122 send_file_headers! :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf"
124 }
123 }
125 end
124 end
126 end
125 end
127
126
128 def new
127 def new
129 respond_to do |format|
128 respond_to do |format|
130 format.html { render :action => 'new', :layout => !request.xhr? }
129 format.html { render :action => 'new', :layout => !request.xhr? }
131 format.js
130 format.js
132 end
131 end
133 end
132 end
134
133
135 def create
134 def create
136 unless User.current.allowed_to?(:add_issues, @issue.project, :global => true)
135 unless User.current.allowed_to?(:add_issues, @issue.project, :global => true)
137 raise ::Unauthorized
136 raise ::Unauthorized
138 end
137 end
139 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
138 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
140 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
139 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
141 if @issue.save
140 if @issue.save
142 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
141 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
143 respond_to do |format|
142 respond_to do |format|
144 format.html {
143 format.html {
145 render_attachment_warning_if_needed(@issue)
144 render_attachment_warning_if_needed(@issue)
146 flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject))
145 flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject))
147 redirect_after_create
146 redirect_after_create
148 }
147 }
149 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
148 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
150 end
149 end
151 return
150 return
152 else
151 else
153 respond_to do |format|
152 respond_to do |format|
154 format.html {
153 format.html {
155 if @issue.project.nil?
154 if @issue.project.nil?
156 render_error :status => 422
155 render_error :status => 422
157 else
156 else
158 render :action => 'new'
157 render :action => 'new'
159 end
158 end
160 }
159 }
161 format.api { render_validation_errors(@issue) }
160 format.api { render_validation_errors(@issue) }
162 end
161 end
163 end
162 end
164 end
163 end
165
164
166 def edit
165 def edit
167 return unless update_issue_from_params
166 return unless update_issue_from_params
168
167
169 respond_to do |format|
168 respond_to do |format|
170 format.html { }
169 format.html { }
171 format.js
170 format.js
172 end
171 end
173 end
172 end
174
173
175 def update
174 def update
176 return unless update_issue_from_params
175 return unless update_issue_from_params
177 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
176 @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
178 saved = false
177 saved = false
179 begin
178 begin
180 saved = save_issue_with_child_records
179 saved = save_issue_with_child_records
181 rescue ActiveRecord::StaleObjectError
180 rescue ActiveRecord::StaleObjectError
182 @conflict = true
181 @conflict = true
183 if params[:last_journal_id]
182 if params[:last_journal_id]
184 @conflict_journals = @issue.journals_after(params[:last_journal_id]).to_a
183 @conflict_journals = @issue.journals_after(params[:last_journal_id]).to_a
185 @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
184 @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
186 end
185 end
187 end
186 end
188
187
189 if saved
188 if saved
190 render_attachment_warning_if_needed(@issue)
189 render_attachment_warning_if_needed(@issue)
191 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
190 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
192
191
193 respond_to do |format|
192 respond_to do |format|
194 format.html { redirect_back_or_default issue_path(@issue, previous_and_next_issue_ids_params) }
193 format.html { redirect_back_or_default issue_path(@issue, previous_and_next_issue_ids_params) }
195 format.api { render_api_ok }
194 format.api { render_api_ok }
196 end
195 end
197 else
196 else
198 respond_to do |format|
197 respond_to do |format|
199 format.html { render :action => 'edit' }
198 format.html { render :action => 'edit' }
200 format.api { render_validation_errors(@issue) }
199 format.api { render_validation_errors(@issue) }
201 end
200 end
202 end
201 end
203 end
202 end
204
203
205 # Bulk edit/copy a set of issues
204 # Bulk edit/copy a set of issues
206 def bulk_edit
205 def bulk_edit
207 @issues.sort!
206 @issues.sort!
208 @copy = params[:copy].present?
207 @copy = params[:copy].present?
209 @notes = params[:notes]
208 @notes = params[:notes]
210
209
211 if @copy
210 if @copy
212 unless User.current.allowed_to?(:copy_issues, @projects)
211 unless User.current.allowed_to?(:copy_issues, @projects)
213 raise ::Unauthorized
212 raise ::Unauthorized
214 end
213 end
215 end
214 end
216
215
217 @allowed_projects = Issue.allowed_target_projects
216 @allowed_projects = Issue.allowed_target_projects
218 if params[:issue]
217 if params[:issue]
219 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s}
218 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s}
220 if @target_project
219 if @target_project
221 target_projects = [@target_project]
220 target_projects = [@target_project]
222 end
221 end
223 end
222 end
224 target_projects ||= @projects
223 target_projects ||= @projects
225
224
226 if @copy
225 if @copy
227 # Copied issues will get their default statuses
226 # Copied issues will get their default statuses
228 @available_statuses = []
227 @available_statuses = []
229 else
228 else
230 @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
229 @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
231 end
230 end
232 @custom_fields = @issues.map{|i|i.editable_custom_fields}.reduce(:&)
231 @custom_fields = @issues.map{|i|i.editable_custom_fields}.reduce(:&)
233 @assignables = target_projects.map(&:assignable_users).reduce(:&)
232 @assignables = target_projects.map(&:assignable_users).reduce(:&)
234 @trackers = target_projects.map(&:trackers).reduce(:&)
233 @trackers = target_projects.map(&:trackers).reduce(:&)
235 @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&)
234 @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&)
236 @categories = target_projects.map {|p| p.issue_categories}.reduce(:&)
235 @categories = target_projects.map {|p| p.issue_categories}.reduce(:&)
237 if @copy
236 if @copy
238 @attachments_present = @issues.detect {|i| i.attachments.any?}.present?
237 @attachments_present = @issues.detect {|i| i.attachments.any?}.present?
239 @subtasks_present = @issues.detect {|i| !i.leaf?}.present?
238 @subtasks_present = @issues.detect {|i| !i.leaf?}.present?
240 end
239 end
241
240
242 @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&)
241 @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&)
243
242
244 @issue_params = params[:issue] || {}
243 @issue_params = params[:issue] || {}
245 @issue_params[:custom_field_values] ||= {}
244 @issue_params[:custom_field_values] ||= {}
246 end
245 end
247
246
248 def bulk_update
247 def bulk_update
249 @issues.sort!
248 @issues.sort!
250 @copy = params[:copy].present?
249 @copy = params[:copy].present?
251
250
252 attributes = parse_params_for_bulk_issue_attributes(params)
251 attributes = parse_params_for_bulk_issue_attributes(params)
253 copy_subtasks = (params[:copy_subtasks] == '1')
252 copy_subtasks = (params[:copy_subtasks] == '1')
254 copy_attachments = (params[:copy_attachments] == '1')
253 copy_attachments = (params[:copy_attachments] == '1')
255
254
256 if @copy
255 if @copy
257 unless User.current.allowed_to?(:copy_issues, @projects)
256 unless User.current.allowed_to?(:copy_issues, @projects)
258 raise ::Unauthorized
257 raise ::Unauthorized
259 end
258 end
260 target_projects = @projects
259 target_projects = @projects
261 if attributes['project_id'].present?
260 if attributes['project_id'].present?
262 target_projects = Project.where(:id => attributes['project_id']).to_a
261 target_projects = Project.where(:id => attributes['project_id']).to_a
263 end
262 end
264 unless User.current.allowed_to?(:add_issues, target_projects)
263 unless User.current.allowed_to?(:add_issues, target_projects)
265 raise ::Unauthorized
264 raise ::Unauthorized
266 end
265 end
267 end
266 end
268
267
269 unsaved_issues = []
268 unsaved_issues = []
270 saved_issues = []
269 saved_issues = []
271
270
272 if @copy && copy_subtasks
271 if @copy && copy_subtasks
273 # Descendant issues will be copied with the parent task
272 # Descendant issues will be copied with the parent task
274 # Don't copy them twice
273 # Don't copy them twice
275 @issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}}
274 @issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}}
276 end
275 end
277
276
278 @issues.each do |orig_issue|
277 @issues.each do |orig_issue|
279 orig_issue.reload
278 orig_issue.reload
280 if @copy
279 if @copy
281 issue = orig_issue.copy({},
280 issue = orig_issue.copy({},
282 :attachments => copy_attachments,
281 :attachments => copy_attachments,
283 :subtasks => copy_subtasks,
282 :subtasks => copy_subtasks,
284 :link => link_copy?(params[:link_copy])
283 :link => link_copy?(params[:link_copy])
285 )
284 )
286 else
285 else
287 issue = orig_issue
286 issue = orig_issue
288 end
287 end
289 journal = issue.init_journal(User.current, params[:notes])
288 journal = issue.init_journal(User.current, params[:notes])
290 issue.safe_attributes = attributes
289 issue.safe_attributes = attributes
291 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
290 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
292 if issue.save
291 if issue.save
293 saved_issues << issue
292 saved_issues << issue
294 else
293 else
295 unsaved_issues << orig_issue
294 unsaved_issues << orig_issue
296 end
295 end
297 end
296 end
298
297
299 if unsaved_issues.empty?
298 if unsaved_issues.empty?
300 flash[:notice] = l(:notice_successful_update) unless saved_issues.empty?
299 flash[:notice] = l(:notice_successful_update) unless saved_issues.empty?
301 if params[:follow]
300 if params[:follow]
302 if @issues.size == 1 && saved_issues.size == 1
301 if @issues.size == 1 && saved_issues.size == 1
303 redirect_to issue_path(saved_issues.first)
302 redirect_to issue_path(saved_issues.first)
304 elsif saved_issues.map(&:project).uniq.size == 1
303 elsif saved_issues.map(&:project).uniq.size == 1
305 redirect_to project_issues_path(saved_issues.map(&:project).first)
304 redirect_to project_issues_path(saved_issues.map(&:project).first)
306 end
305 end
307 else
306 else
308 redirect_back_or_default _project_issues_path(@project)
307 redirect_back_or_default _project_issues_path(@project)
309 end
308 end
310 else
309 else
311 @saved_issues = @issues
310 @saved_issues = @issues
312 @unsaved_issues = unsaved_issues
311 @unsaved_issues = unsaved_issues
313 @issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).to_a
312 @issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).to_a
314 bulk_edit
313 bulk_edit
315 render :action => 'bulk_edit'
314 render :action => 'bulk_edit'
316 end
315 end
317 end
316 end
318
317
319 def destroy
318 def destroy
320 @hours = TimeEntry.where(:issue_id => @issues.map(&:id)).sum(:hours).to_f
319 @hours = TimeEntry.where(:issue_id => @issues.map(&:id)).sum(:hours).to_f
321 if @hours > 0
320 if @hours > 0
322 case params[:todo]
321 case params[:todo]
323 when 'destroy'
322 when 'destroy'
324 # nothing to do
323 # nothing to do
325 when 'nullify'
324 when 'nullify'
326 TimeEntry.where(['issue_id IN (?)', @issues]).update_all('issue_id = NULL')
325 TimeEntry.where(['issue_id IN (?)', @issues]).update_all('issue_id = NULL')
327 when 'reassign'
326 when 'reassign'
328 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
327 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
329 if reassign_to.nil?
328 if reassign_to.nil?
330 flash.now[:error] = l(:error_issue_not_found_in_project)
329 flash.now[:error] = l(:error_issue_not_found_in_project)
331 return
330 return
332 else
331 else
333 TimeEntry.where(['issue_id IN (?)', @issues]).
332 TimeEntry.where(['issue_id IN (?)', @issues]).
334 update_all("issue_id = #{reassign_to.id}")
333 update_all("issue_id = #{reassign_to.id}")
335 end
334 end
336 else
335 else
337 # display the destroy form if it's a user request
336 # display the destroy form if it's a user request
338 return unless api_request?
337 return unless api_request?
339 end
338 end
340 end
339 end
341 @issues.each do |issue|
340 @issues.each do |issue|
342 begin
341 begin
343 issue.reload.destroy
342 issue.reload.destroy
344 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
343 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
345 # nothing to do, issue was already deleted (eg. by a parent)
344 # nothing to do, issue was already deleted (eg. by a parent)
346 end
345 end
347 end
346 end
348 respond_to do |format|
347 respond_to do |format|
349 format.html { redirect_back_or_default _project_issues_path(@project) }
348 format.html { redirect_back_or_default _project_issues_path(@project) }
350 format.api { render_api_ok }
349 format.api { render_api_ok }
351 end
350 end
352 end
351 end
353
352
354 private
353 private
355
354
356 def retrieve_previous_and_next_issue_ids
355 def retrieve_previous_and_next_issue_ids
357 if params[:prev_issue_id].present? || params[:next_issue_id].present?
356 if params[:prev_issue_id].present? || params[:next_issue_id].present?
358 @prev_issue_id = params[:prev_issue_id].presence.try(:to_i)
357 @prev_issue_id = params[:prev_issue_id].presence.try(:to_i)
359 @next_issue_id = params[:next_issue_id].presence.try(:to_i)
358 @next_issue_id = params[:next_issue_id].presence.try(:to_i)
360 @issue_position = params[:issue_position].presence.try(:to_i)
359 @issue_position = params[:issue_position].presence.try(:to_i)
361 @issue_count = params[:issue_count].presence.try(:to_i)
360 @issue_count = params[:issue_count].presence.try(:to_i)
362 else
361 else
363 retrieve_query_from_session
362 retrieve_query_from_session
364 if @query
363 if @query
365 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
364 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
366 sort_update(@query.sortable_columns, 'issues_index_sort')
365 sort_update(@query.sortable_columns, 'issues_index_sort')
367 limit = 500
366 limit = 500
368 issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version])
367 issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version])
369 if (idx = issue_ids.index(@issue.id)) && idx < limit
368 if (idx = issue_ids.index(@issue.id)) && idx < limit
370 if issue_ids.size < 500
369 if issue_ids.size < 500
371 @issue_position = idx + 1
370 @issue_position = idx + 1
372 @issue_count = issue_ids.size
371 @issue_count = issue_ids.size
373 end
372 end
374 @prev_issue_id = issue_ids[idx - 1] if idx > 0
373 @prev_issue_id = issue_ids[idx - 1] if idx > 0
375 @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1)
374 @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1)
376 end
375 end
377 end
376 end
378 end
377 end
379 end
378 end
380
379
381 def previous_and_next_issue_ids_params
380 def previous_and_next_issue_ids_params
382 {
381 {
383 :prev_issue_id => params[:prev_issue_id],
382 :prev_issue_id => params[:prev_issue_id],
384 :next_issue_id => params[:next_issue_id],
383 :next_issue_id => params[:next_issue_id],
385 :issue_position => params[:issue_position],
384 :issue_position => params[:issue_position],
386 :issue_count => params[:issue_count]
385 :issue_count => params[:issue_count]
387 }.reject {|k,v| k.blank?}
386 }.reject {|k,v| k.blank?}
388 end
387 end
389
388
390 # Used by #edit and #update to set some common instance variables
389 # Used by #edit and #update to set some common instance variables
391 # from the params
390 # from the params
392 def update_issue_from_params
391 def update_issue_from_params
393 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
392 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
394 if params[:time_entry]
393 if params[:time_entry]
395 @time_entry.safe_attributes = params[:time_entry]
394 @time_entry.safe_attributes = params[:time_entry]
396 end
395 end
397
396
398 @issue.init_journal(User.current)
397 @issue.init_journal(User.current)
399
398
400 issue_attributes = params[:issue]
399 issue_attributes = params[:issue]
401 if issue_attributes && params[:conflict_resolution]
400 if issue_attributes && params[:conflict_resolution]
402 case params[:conflict_resolution]
401 case params[:conflict_resolution]
403 when 'overwrite'
402 when 'overwrite'
404 issue_attributes = issue_attributes.dup
403 issue_attributes = issue_attributes.dup
405 issue_attributes.delete(:lock_version)
404 issue_attributes.delete(:lock_version)
406 when 'add_notes'
405 when 'add_notes'
407 issue_attributes = issue_attributes.slice(:notes, :private_notes)
406 issue_attributes = issue_attributes.slice(:notes, :private_notes)
408 when 'cancel'
407 when 'cancel'
409 redirect_to issue_path(@issue)
408 redirect_to issue_path(@issue)
410 return false
409 return false
411 end
410 end
412 end
411 end
413 @issue.safe_attributes = issue_attributes
412 @issue.safe_attributes = issue_attributes
414 @priorities = IssuePriority.active
413 @priorities = IssuePriority.active
415 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
414 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
416 true
415 true
417 end
416 end
418
417
419 # Used by #new and #create to build a new issue from the params
418 # Used by #new and #create to build a new issue from the params
420 # The new issue will be copied from an existing one if copy_from parameter is given
419 # The new issue will be copied from an existing one if copy_from parameter is given
421 def build_new_issue_from_params
420 def build_new_issue_from_params
422 @issue = Issue.new
421 @issue = Issue.new
423 if params[:copy_from]
422 if params[:copy_from]
424 begin
423 begin
425 @issue.init_journal(User.current)
424 @issue.init_journal(User.current)
426 @copy_from = Issue.visible.find(params[:copy_from])
425 @copy_from = Issue.visible.find(params[:copy_from])
427 unless User.current.allowed_to?(:copy_issues, @copy_from.project)
426 unless User.current.allowed_to?(:copy_issues, @copy_from.project)
428 raise ::Unauthorized
427 raise ::Unauthorized
429 end
428 end
430 @link_copy = link_copy?(params[:link_copy]) || request.get?
429 @link_copy = link_copy?(params[:link_copy]) || request.get?
431 @copy_attachments = params[:copy_attachments].present? || request.get?
430 @copy_attachments = params[:copy_attachments].present? || request.get?
432 @copy_subtasks = params[:copy_subtasks].present? || request.get?
431 @copy_subtasks = params[:copy_subtasks].present? || request.get?
433 @issue.copy_from(@copy_from, :attachments => @copy_attachments, :subtasks => @copy_subtasks, :link => @link_copy)
432 @issue.copy_from(@copy_from, :attachments => @copy_attachments, :subtasks => @copy_subtasks, :link => @link_copy)
434 @issue.parent_issue_id = @copy_from.parent_id
433 @issue.parent_issue_id = @copy_from.parent_id
435 rescue ActiveRecord::RecordNotFound
434 rescue ActiveRecord::RecordNotFound
436 render_404
435 render_404
437 return
436 return
438 end
437 end
439 end
438 end
440 @issue.project = @project
439 @issue.project = @project
441 if request.get?
440 if request.get?
442 @issue.project ||= @issue.allowed_target_projects.first
441 @issue.project ||= @issue.allowed_target_projects.first
443 end
442 end
444 @issue.author ||= User.current
443 @issue.author ||= User.current
445 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
444 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
446
445
447 attrs = (params[:issue] || {}).deep_dup
446 attrs = (params[:issue] || {}).deep_dup
448 if action_name == 'new' && params[:was_default_status] == attrs[:status_id]
447 if action_name == 'new' && params[:was_default_status] == attrs[:status_id]
449 attrs.delete(:status_id)
448 attrs.delete(:status_id)
450 end
449 end
451 if action_name == 'new' && params[:form_update_triggered_by] == 'issue_project_id'
450 if action_name == 'new' && params[:form_update_triggered_by] == 'issue_project_id'
452 # Discard submitted version when changing the project on the issue form
451 # Discard submitted version when changing the project on the issue form
453 # so we can use the default version for the new project
452 # so we can use the default version for the new project
454 attrs.delete(:fixed_version_id)
453 attrs.delete(:fixed_version_id)
455 end
454 end
456 @issue.safe_attributes = attrs
455 @issue.safe_attributes = attrs
457
456
458 if @issue.project
457 if @issue.project
459 @issue.tracker ||= @issue.project.trackers.first
458 @issue.tracker ||= @issue.project.trackers.first
460 if @issue.tracker.nil?
459 if @issue.tracker.nil?
461 render_error l(:error_no_tracker_in_project)
460 render_error l(:error_no_tracker_in_project)
462 return false
461 return false
463 end
462 end
464 if @issue.status.nil?
463 if @issue.status.nil?
465 render_error l(:error_no_default_issue_status)
464 render_error l(:error_no_default_issue_status)
466 return false
465 return false
467 end
466 end
468 end
467 end
469
468
470 @priorities = IssuePriority.active
469 @priorities = IssuePriority.active
471 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
470 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
472 end
471 end
473
472
474 def parse_params_for_bulk_issue_attributes(params)
473 def parse_params_for_bulk_issue_attributes(params)
475 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
474 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
476 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
475 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
477 if custom = attributes[:custom_field_values]
476 if custom = attributes[:custom_field_values]
478 custom.reject! {|k,v| v.blank?}
477 custom.reject! {|k,v| v.blank?}
479 custom.keys.each do |k|
478 custom.keys.each do |k|
480 if custom[k].is_a?(Array)
479 if custom[k].is_a?(Array)
481 custom[k] << '' if custom[k].delete('__none__')
480 custom[k] << '' if custom[k].delete('__none__')
482 else
481 else
483 custom[k] = '' if custom[k] == '__none__'
482 custom[k] = '' if custom[k] == '__none__'
484 end
483 end
485 end
484 end
486 end
485 end
487 attributes
486 attributes
488 end
487 end
489
488
490 # Saves @issue and a time_entry from the parameters
489 # Saves @issue and a time_entry from the parameters
491 def save_issue_with_child_records
490 def save_issue_with_child_records
492 Issue.transaction do
491 Issue.transaction do
493 if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, @issue.project)
492 if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, @issue.project)
494 time_entry = @time_entry || TimeEntry.new
493 time_entry = @time_entry || TimeEntry.new
495 time_entry.project = @issue.project
494 time_entry.project = @issue.project
496 time_entry.issue = @issue
495 time_entry.issue = @issue
497 time_entry.user = User.current
496 time_entry.user = User.current
498 time_entry.spent_on = User.current.today
497 time_entry.spent_on = User.current.today
499 time_entry.attributes = params[:time_entry]
498 time_entry.attributes = params[:time_entry]
500 @issue.time_entries << time_entry
499 @issue.time_entries << time_entry
501 end
500 end
502
501
503 call_hook(:controller_issues_edit_before_save, { :params => params, :issue => @issue, :time_entry => time_entry, :journal => @issue.current_journal})
502 call_hook(:controller_issues_edit_before_save, { :params => params, :issue => @issue, :time_entry => time_entry, :journal => @issue.current_journal})
504 if @issue.save
503 if @issue.save
505 call_hook(:controller_issues_edit_after_save, { :params => params, :issue => @issue, :time_entry => time_entry, :journal => @issue.current_journal})
504 call_hook(:controller_issues_edit_after_save, { :params => params, :issue => @issue, :time_entry => time_entry, :journal => @issue.current_journal})
506 else
505 else
507 raise ActiveRecord::Rollback
506 raise ActiveRecord::Rollback
508 end
507 end
509 end
508 end
510 end
509 end
511
510
512 # Returns true if the issue copy should be linked
511 # Returns true if the issue copy should be linked
513 # to the original issue
512 # to the original issue
514 def link_copy?(param)
513 def link_copy?(param)
515 case Setting.link_copied_issue
514 case Setting.link_copied_issue
516 when 'yes'
515 when 'yes'
517 true
516 true
518 when 'no'
517 when 'no'
519 false
518 false
520 when 'ask'
519 when 'ask'
521 param == '1'
520 param == '1'
522 end
521 end
523 end
522 end
524
523
525 # Redirects user after a successful issue creation
524 # Redirects user after a successful issue creation
526 def redirect_after_create
525 def redirect_after_create
527 if params[:continue]
526 if params[:continue]
528 attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?}
527 attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?}
529 if params[:project_id]
528 if params[:project_id]
530 redirect_to new_project_issue_path(@issue.project, :issue => attrs)
529 redirect_to new_project_issue_path(@issue.project, :issue => attrs)
531 else
530 else
532 attrs.merge! :project_id => @issue.project_id
531 attrs.merge! :project_id => @issue.project_id
533 redirect_to new_issue_path(:issue => attrs)
532 redirect_to new_issue_path(:issue => attrs)
534 end
533 end
535 else
534 else
536 redirect_to issue_path(@issue)
535 redirect_to issue_path(@issue)
537 end
536 end
538 end
537 end
539 end
538 end
@@ -1,121 +1,127
1 <div class="contextual">
1 <div class="contextual">
2 <% if !@query.new_record? && @query.editable_by?(User.current) %>
2 <% if @project && User.current.allowed_to?(:add_issues, @project) && @project.trackers.any? %>
3 <%= link_to l(:button_edit), edit_query_path(@query), :class => 'icon icon-edit' %>
3 <%= link_to l(:label_issue_new), new_project_issue_path(@project), :class => 'icon icon-add new-issue' %>
4 <%= delete_link query_path(@query) %>
4 <% end %>
5 <% end %>
6 </div>
5 </div>
7
6
8 <h2><%= @query.new_record? ? l(:label_issue_plural) : @query.name %></h2>
7 <h2><%= @query.new_record? ? l(:label_issue_plural) : @query.name %></h2>
9 <% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %>
8 <% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %>
10
9
11 <%= form_tag({ :controller => 'issues', :action => 'index', :project_id => @project },
10 <%= form_tag({ :controller => 'issues', :action => 'index', :project_id => @project },
12 :method => :get, :id => 'query_form') do %>
11 :method => :get, :id => 'query_form') do %>
13 <div id="query_form_with_buttons" class="hide-when-print">
12 <div id="query_form_with_buttons" class="hide-when-print">
14 <%= hidden_field_tag 'set_filter', '1' %>
13 <%= hidden_field_tag 'set_filter', '1' %>
15 <div id="query_form_content">
14 <div id="query_form_content">
16 <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
15 <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
17 <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
16 <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
18 <div style="<%= @query.new_record? ? "" : "display: none;" %>">
17 <div style="<%= @query.new_record? ? "" : "display: none;" %>">
19 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
18 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
20 </div>
19 </div>
21 </fieldset>
20 </fieldset>
22 <fieldset id="options" class="collapsible collapsed">
21 <fieldset id="options" class="collapsible collapsed">
23 <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
22 <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
24 <div style="display: none;">
23 <div style="display: none;">
25 <table>
24 <table>
26 <tr>
25 <tr>
27 <td class="field"><%= l(:field_column_names) %></td>
26 <td class="field"><%= l(:field_column_names) %></td>
28 <td><%= render_query_columns_selection(@query) %></td>
27 <td><%= render_query_columns_selection(@query) %></td>
29 </tr>
28 </tr>
30 <tr>
29 <tr>
31 <td class="field"><label for='group_by'><%= l(:field_group_by) %></label></td>
30 <td class="field"><label for='group_by'><%= l(:field_group_by) %></label></td>
32 <td><%= select_tag('group_by',
31 <td><%= select_tag('group_by',
33 options_for_select(
32 options_for_select(
34 [[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]},
33 [[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]},
35 @query.group_by)
34 @query.group_by)
36 ) %></td>
35 ) %></td>
37 </tr>
36 </tr>
38 <tr>
37 <tr>
39 <td class="field"><%= l(:button_show) %></td>
38 <td class="field"><%= l(:button_show) %></td>
40 <td><%= available_block_columns_tags(@query) %></td>
39 <td><%= available_block_columns_tags(@query) %></td>
41 </tr>
40 </tr>
42 <tr>
41 <tr>
43 <td><%= l(:label_total_plural) %></td>
42 <td><%= l(:label_total_plural) %></td>
44 <td><%= available_totalable_columns_tags(@query) %></td>
43 <td><%= available_totalable_columns_tags(@query) %></td>
45 </tr>
44 </tr>
46 </table>
45 </table>
47 </div>
46 </div>
48 </fieldset>
47 </fieldset>
49 </div>
48 </div>
50 <p class="buttons">
49 <p class="buttons">
51 <%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %>
50 <%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %>
52 <%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %>
51 <%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %>
53 <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>
52 <% if @query.new_record? %>
53 <% if User.current.allowed_to?(:save_queries, @project, :global => true) %>
54 <%= link_to_function l(:button_save),
54 <%= link_to_function l(:button_save),
55 "$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }').submit()",
55 "$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }').submit()",
56 :class => 'icon icon-save' %>
56 :class => 'icon icon-save' %>
57 <% end %>
58 <% else %>
59 <% if @query.editable_by?(User.current) %>
60 <%= link_to l(:button_edit), edit_query_path(@query), :class => 'icon icon-edit' %>
61 <%= delete_link query_path(@query) %>
62 <% end %>
57 <% end %>
63 <% end %>
58 </p>
64 </p>
59 </div>
65 </div>
60 <% end %>
66 <% end %>
61
67
62 <%= error_messages_for 'query' %>
68 <%= error_messages_for 'query' %>
63 <% if @query.valid? %>
69 <% if @query.valid? %>
64 <% if @issues.empty? %>
70 <% if @issues.empty? %>
65 <p class="nodata"><%= l(:label_no_data) %></p>
71 <p class="nodata"><%= l(:label_no_data) %></p>
66 <% else %>
72 <% else %>
67 <%= render_query_totals(@query) %>
73 <%= render_query_totals(@query) %>
68 <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
74 <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
69 <span class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></span>
75 <span class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></span>
70 <% end %>
76 <% end %>
71
77
72 <% other_formats_links do |f| %>
78 <% other_formats_links do |f| %>
73 <%= f.link_to 'Atom', :url => params.merge(:key => User.current.rss_key) %>
79 <%= f.link_to 'Atom', :url => params.merge(:key => User.current.rss_key) %>
74 <%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
80 <%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
75 <%= f.link_to 'PDF', :url => params %>
81 <%= f.link_to 'PDF', :url => params %>
76 <% end %>
82 <% end %>
77
83
78 <div id="csv-export-options" style="display:none;">
84 <div id="csv-export-options" style="display:none;">
79 <h3 class="title"><%= l(:label_export_options, :export_format => 'CSV') %></h3>
85 <h3 class="title"><%= l(:label_export_options, :export_format => 'CSV') %></h3>
80 <%= form_tag(_project_issues_path(@project, :format => 'csv'), :method => :get, :id => 'csv-export-form') do %>
86 <%= form_tag(_project_issues_path(@project, :format => 'csv'), :method => :get, :id => 'csv-export-form') do %>
81 <%= query_as_hidden_field_tags(@query) %>
87 <%= query_as_hidden_field_tags(@query) %>
82 <%= hidden_field_tag 'sort', @sort_criteria.to_param, :id => nil %>
88 <%= hidden_field_tag 'sort', @sort_criteria.to_param, :id => nil %>
83 <p>
89 <p>
84 <label><%= radio_button_tag 'csv[columns]', '', true %> <%= l(:description_selected_columns) %></label><br />
90 <label><%= radio_button_tag 'csv[columns]', '', true %> <%= l(:description_selected_columns) %></label><br />
85 <label><%= radio_button_tag 'csv[columns]', 'all' %> <%= l(:description_all_columns) %></label>
91 <label><%= radio_button_tag 'csv[columns]', 'all' %> <%= l(:description_all_columns) %></label>
86 </p>
92 </p>
87 <p>
93 <p>
88 <label><%= check_box_tag 'csv[description]', '1', @query.has_column?(:description) %> <%= l(:field_description) %></label>
94 <label><%= check_box_tag 'csv[description]', '1', @query.has_column?(:description) %> <%= l(:field_description) %></label>
89 </p>
95 </p>
90 <% if @issue_count > Setting.issues_export_limit.to_i %>
96 <% if @issue_count > Setting.issues_export_limit.to_i %>
91 <p class="icon icon-warning">
97 <p class="icon icon-warning">
92 <%= l(:setting_issues_export_limit) %>: <%= Setting.issues_export_limit.to_i %>
98 <%= l(:setting_issues_export_limit) %>: <%= Setting.issues_export_limit.to_i %>
93 </p>
99 </p>
94 <% end %>
100 <% end %>
95 <p class="buttons">
101 <p class="buttons">
96 <%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %>
102 <%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %>
97 <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
103 <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
98 </p>
104 </p>
99 <% end %>
105 <% end %>
100 </div>
106 </div>
101
107
102 <% end %>
108 <% end %>
103 <%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %>
109 <%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %>
104
110
105 <% content_for :sidebar do %>
111 <% content_for :sidebar do %>
106 <%= render :partial => 'issues/sidebar' %>
112 <%= render :partial => 'issues/sidebar' %>
107 <% end %>
113 <% end %>
108
114
109 <% content_for :header_tags do %>
115 <% content_for :header_tags do %>
110 <%= auto_discovery_link_tag(:atom,
116 <%= auto_discovery_link_tag(:atom,
111 {:query_id => @query, :format => 'atom',
117 {:query_id => @query, :format => 'atom',
112 :page => nil, :key => User.current.rss_key},
118 :page => nil, :key => User.current.rss_key},
113 :title => l(:label_issue_plural)) %>
119 :title => l(:label_issue_plural)) %>
114 <%= auto_discovery_link_tag(:atom,
120 <%= auto_discovery_link_tag(:atom,
115 {:controller => 'journals', :action => 'index',
121 {:controller => 'journals', :action => 'index',
116 :query_id => @query, :format => 'atom',
122 :query_id => @query, :format => 'atom',
117 :page => nil, :key => User.current.rss_key},
123 :page => nil, :key => User.current.rss_key},
118 :title => l(:label_changes_details)) %>
124 :title => l(:label_changes_details)) %>
119 <% end %>
125 <% end %>
120
126
121 <%= context_menu issues_context_menu_path %>
127 <%= context_menu issues_context_menu_path %>
@@ -1,278 +1,274
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 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 'redmine/core_ext'
18 require 'redmine/core_ext'
19
19
20 begin
20 begin
21 require 'rmagick' unless Object.const_defined?(:Magick)
21 require 'rmagick' unless Object.const_defined?(:Magick)
22 rescue LoadError
22 rescue LoadError
23 # RMagick is not available
23 # RMagick is not available
24 end
24 end
25 begin
25 begin
26 require 'redcarpet' unless Object.const_defined?(:Redcarpet)
26 require 'redcarpet' unless Object.const_defined?(:Redcarpet)
27 rescue LoadError
27 rescue LoadError
28 # Redcarpet is not available
28 # Redcarpet is not available
29 end
29 end
30
30
31 require 'redmine/acts/positioned'
31 require 'redmine/acts/positioned'
32
32
33 require 'redmine/scm/base'
33 require 'redmine/scm/base'
34 require 'redmine/access_control'
34 require 'redmine/access_control'
35 require 'redmine/access_keys'
35 require 'redmine/access_keys'
36 require 'redmine/activity'
36 require 'redmine/activity'
37 require 'redmine/activity/fetcher'
37 require 'redmine/activity/fetcher'
38 require 'redmine/ciphering'
38 require 'redmine/ciphering'
39 require 'redmine/codeset_util'
39 require 'redmine/codeset_util'
40 require 'redmine/field_format'
40 require 'redmine/field_format'
41 require 'redmine/menu_manager'
41 require 'redmine/menu_manager'
42 require 'redmine/notifiable'
42 require 'redmine/notifiable'
43 require 'redmine/platform'
43 require 'redmine/platform'
44 require 'redmine/mime_type'
44 require 'redmine/mime_type'
45 require 'redmine/notifiable'
45 require 'redmine/notifiable'
46 require 'redmine/search'
46 require 'redmine/search'
47 require 'redmine/syntax_highlighting'
47 require 'redmine/syntax_highlighting'
48 require 'redmine/thumbnail'
48 require 'redmine/thumbnail'
49 require 'redmine/unified_diff'
49 require 'redmine/unified_diff'
50 require 'redmine/utils'
50 require 'redmine/utils'
51 require 'redmine/version'
51 require 'redmine/version'
52 require 'redmine/wiki_formatting'
52 require 'redmine/wiki_formatting'
53
53
54 require 'redmine/default_data/loader'
54 require 'redmine/default_data/loader'
55 require 'redmine/helpers/calendar'
55 require 'redmine/helpers/calendar'
56 require 'redmine/helpers/diff'
56 require 'redmine/helpers/diff'
57 require 'redmine/helpers/gantt'
57 require 'redmine/helpers/gantt'
58 require 'redmine/helpers/time_report'
58 require 'redmine/helpers/time_report'
59 require 'redmine/views/other_formats_builder'
59 require 'redmine/views/other_formats_builder'
60 require 'redmine/views/labelled_form_builder'
60 require 'redmine/views/labelled_form_builder'
61 require 'redmine/views/builders'
61 require 'redmine/views/builders'
62
62
63 require 'redmine/themes'
63 require 'redmine/themes'
64 require 'redmine/hook'
64 require 'redmine/hook'
65 require 'redmine/hook/listener'
65 require 'redmine/hook/listener'
66 require 'redmine/hook/view_listener'
66 require 'redmine/hook/view_listener'
67 require 'redmine/plugin'
67 require 'redmine/plugin'
68
68
69 Redmine::Scm::Base.add "Subversion"
69 Redmine::Scm::Base.add "Subversion"
70 Redmine::Scm::Base.add "Darcs"
70 Redmine::Scm::Base.add "Darcs"
71 Redmine::Scm::Base.add "Mercurial"
71 Redmine::Scm::Base.add "Mercurial"
72 Redmine::Scm::Base.add "Cvs"
72 Redmine::Scm::Base.add "Cvs"
73 Redmine::Scm::Base.add "Bazaar"
73 Redmine::Scm::Base.add "Bazaar"
74 Redmine::Scm::Base.add "Git"
74 Redmine::Scm::Base.add "Git"
75 Redmine::Scm::Base.add "Filesystem"
75 Redmine::Scm::Base.add "Filesystem"
76
76
77 # Permissions
77 # Permissions
78 Redmine::AccessControl.map do |map|
78 Redmine::AccessControl.map do |map|
79 map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true, :read => true
79 map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true, :read => true
80 map.permission :search_project, {:search => :index}, :public => true, :read => true
80 map.permission :search_project, {:search => :index}, :public => true, :read => true
81 map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin
81 map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin
82 map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member
82 map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member
83 map.permission :close_project, {:projects => [:close, :reopen]}, :require => :member, :read => true
83 map.permission :close_project, {:projects => [:close, :reopen]}, :require => :member, :read => true
84 map.permission :select_project_modules, {:projects => :modules}, :require => :member
84 map.permission :select_project_modules, {:projects => :modules}, :require => :member
85 map.permission :view_members, {:members => [:index, :show]}, :public => true, :read => true
85 map.permission :view_members, {:members => [:index, :show]}, :public => true, :read => true
86 map.permission :manage_members, {:projects => :settings, :members => [:index, :show, :new, :create, :update, :destroy, :autocomplete]}, :require => :member
86 map.permission :manage_members, {:projects => :settings, :members => [:index, :show, :new, :create, :update, :destroy, :autocomplete]}, :require => :member
87 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
87 map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member
88 map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
88 map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member
89
89
90 map.project_module :issue_tracking do |map|
90 map.project_module :issue_tracking do |map|
91 # Issue categories
91 # Issue categories
92 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
92 map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
93 # Issues
93 # Issues
94 map.permission :view_issues, {:issues => [:index, :show],
94 map.permission :view_issues, {:issues => [:index, :show],
95 :auto_complete => [:issues],
95 :auto_complete => [:issues],
96 :context_menus => [:issues],
96 :context_menus => [:issues],
97 :versions => [:index, :show, :status_by],
97 :versions => [:index, :show, :status_by],
98 :journals => [:index, :diff],
98 :journals => [:index, :diff],
99 :queries => :index,
99 :queries => :index,
100 :reports => [:issue_report, :issue_report_details]},
100 :reports => [:issue_report, :issue_report_details]},
101 :read => true
101 :read => true
102 map.permission :add_issues, {:issues => [:new, :create], :attachments => :upload}
102 map.permission :add_issues, {:issues => [:new, :create], :attachments => :upload}
103 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update], :journals => [:new], :attachments => :upload}
103 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update], :journals => [:new], :attachments => :upload}
104 map.permission :copy_issues, {:issues => [:new, :create, :bulk_edit, :bulk_update], :attachments => :upload}
104 map.permission :copy_issues, {:issues => [:new, :create, :bulk_edit, :bulk_update], :attachments => :upload}
105 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
105 map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]}
106 map.permission :manage_subtasks, {}
106 map.permission :manage_subtasks, {}
107 map.permission :set_issues_private, {}
107 map.permission :set_issues_private, {}
108 map.permission :set_own_issues_private, {}, :require => :loggedin
108 map.permission :set_own_issues_private, {}, :require => :loggedin
109 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new], :attachments => :upload}
109 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new], :attachments => :upload}
110 map.permission :edit_issue_notes, {:journals => [:edit, :update]}, :require => :loggedin
110 map.permission :edit_issue_notes, {:journals => [:edit, :update]}, :require => :loggedin
111 map.permission :edit_own_issue_notes, {:journals => [:edit, :update]}, :require => :loggedin
111 map.permission :edit_own_issue_notes, {:journals => [:edit, :update]}, :require => :loggedin
112 map.permission :view_private_notes, {}, :read => true, :require => :member
112 map.permission :view_private_notes, {}, :read => true, :require => :member
113 map.permission :set_notes_private, {}, :require => :member
113 map.permission :set_notes_private, {}, :require => :member
114 map.permission :delete_issues, {:issues => :destroy}, :require => :member
114 map.permission :delete_issues, {:issues => :destroy}, :require => :member
115 # Queries
115 # Queries
116 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
116 map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member
117 map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
117 map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
118 # Watchers
118 # Watchers
119 map.permission :view_issue_watchers, {}, :read => true
119 map.permission :view_issue_watchers, {}, :read => true
120 map.permission :add_issue_watchers, {:watchers => [:new, :create, :append, :autocomplete_for_user]}
120 map.permission :add_issue_watchers, {:watchers => [:new, :create, :append, :autocomplete_for_user]}
121 map.permission :delete_issue_watchers, {:watchers => :destroy}
121 map.permission :delete_issue_watchers, {:watchers => :destroy}
122 map.permission :import_issues, {:imports => [:new, :create, :settings, :mapping, :run, :show]}
122 map.permission :import_issues, {:imports => [:new, :create, :settings, :mapping, :run, :show]}
123 end
123 end
124
124
125 map.project_module :time_tracking do |map|
125 map.project_module :time_tracking do |map|
126 map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
126 map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
127 map.permission :view_time_entries, {:timelog => [:index, :report, :show]}, :read => true
127 map.permission :view_time_entries, {:timelog => [:index, :report, :show]}, :read => true
128 map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
128 map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
129 map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
129 map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
130 map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
130 map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
131 end
131 end
132
132
133 map.project_module :news do |map|
133 map.project_module :news do |map|
134 map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy], :attachments => :upload}, :require => :member
134 map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy], :attachments => :upload}, :require => :member
135 map.permission :view_news, {:news => [:index, :show]}, :public => true, :read => true
135 map.permission :view_news, {:news => [:index, :show]}, :public => true, :read => true
136 map.permission :comment_news, {:comments => :create}
136 map.permission :comment_news, {:comments => :create}
137 end
137 end
138
138
139 map.project_module :documents do |map|
139 map.project_module :documents do |map|
140 map.permission :add_documents, {:documents => [:new, :create, :add_attachment], :attachments => :upload}, :require => :loggedin
140 map.permission :add_documents, {:documents => [:new, :create, :add_attachment], :attachments => :upload}, :require => :loggedin
141 map.permission :edit_documents, {:documents => [:edit, :update, :add_attachment], :attachments => :upload}, :require => :loggedin
141 map.permission :edit_documents, {:documents => [:edit, :update, :add_attachment], :attachments => :upload}, :require => :loggedin
142 map.permission :delete_documents, {:documents => [:destroy]}, :require => :loggedin
142 map.permission :delete_documents, {:documents => [:destroy]}, :require => :loggedin
143 map.permission :view_documents, {:documents => [:index, :show, :download]}, :read => true
143 map.permission :view_documents, {:documents => [:index, :show, :download]}, :read => true
144 end
144 end
145
145
146 map.project_module :files do |map|
146 map.project_module :files do |map|
147 map.permission :manage_files, {:files => [:new, :create], :attachments => :upload}, :require => :loggedin
147 map.permission :manage_files, {:files => [:new, :create], :attachments => :upload}, :require => :loggedin
148 map.permission :view_files, {:files => :index, :versions => :download}, :read => true
148 map.permission :view_files, {:files => :index, :versions => :download}, :read => true
149 end
149 end
150
150
151 map.project_module :wiki do |map|
151 map.project_module :wiki do |map|
152 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
152 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
153 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
153 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
154 map.permission :delete_wiki_pages, {:wiki => [:destroy, :destroy_version]}, :require => :member
154 map.permission :delete_wiki_pages, {:wiki => [:destroy, :destroy_version]}, :require => :member
155 map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true
155 map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true
156 map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true
156 map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true
157 map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true
157 map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true
158 map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment], :attachments => :upload
158 map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment], :attachments => :upload
159 map.permission :delete_wiki_pages_attachments, {}
159 map.permission :delete_wiki_pages_attachments, {}
160 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
160 map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member
161 end
161 end
162
162
163 map.project_module :repository do |map|
163 map.project_module :repository do |map|
164 map.permission :manage_repository, {:repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
164 map.permission :manage_repository, {:repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member
165 map.permission :browse_repository, {:repositories => [:show, :browse, :entry, :raw, :annotate, :changes, :diff, :stats, :graph]}, :read => true
165 map.permission :browse_repository, {:repositories => [:show, :browse, :entry, :raw, :annotate, :changes, :diff, :stats, :graph]}, :read => true
166 map.permission :view_changesets, {:repositories => [:show, :revisions, :revision]}, :read => true
166 map.permission :view_changesets, {:repositories => [:show, :revisions, :revision]}, :read => true
167 map.permission :commit_access, {}
167 map.permission :commit_access, {}
168 map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]}
168 map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]}
169 end
169 end
170
170
171 map.project_module :boards do |map|
171 map.project_module :boards do |map|
172 map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
172 map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member
173 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true, :read => true
173 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true, :read => true
174 map.permission :add_messages, {:messages => [:new, :reply, :quote], :attachments => :upload}
174 map.permission :add_messages, {:messages => [:new, :reply, :quote], :attachments => :upload}
175 map.permission :edit_messages, {:messages => :edit, :attachments => :upload}, :require => :member
175 map.permission :edit_messages, {:messages => :edit, :attachments => :upload}, :require => :member
176 map.permission :edit_own_messages, {:messages => :edit, :attachments => :upload}, :require => :loggedin
176 map.permission :edit_own_messages, {:messages => :edit, :attachments => :upload}, :require => :loggedin
177 map.permission :delete_messages, {:messages => :destroy}, :require => :member
177 map.permission :delete_messages, {:messages => :destroy}, :require => :member
178 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
178 map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin
179 end
179 end
180
180
181 map.project_module :calendar do |map|
181 map.project_module :calendar do |map|
182 map.permission :view_calendar, {:calendars => [:show, :update]}, :read => true
182 map.permission :view_calendar, {:calendars => [:show, :update]}, :read => true
183 end
183 end
184
184
185 map.project_module :gantt do |map|
185 map.project_module :gantt do |map|
186 map.permission :view_gantt, {:gantts => [:show, :update]}, :read => true
186 map.permission :view_gantt, {:gantts => [:show, :update]}, :read => true
187 end
187 end
188 end
188 end
189
189
190 Redmine::MenuManager.map :top_menu do |menu|
190 Redmine::MenuManager.map :top_menu do |menu|
191 menu.push :home, :home_path
191 menu.push :home, :home_path
192 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
192 menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
193 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
193 menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
194 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
194 menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
195 menu.push :help, Redmine::Info.help_url, :last => true
195 menu.push :help, Redmine::Info.help_url, :last => true
196 end
196 end
197
197
198 Redmine::MenuManager.map :account_menu do |menu|
198 Redmine::MenuManager.map :account_menu do |menu|
199 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
199 menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? }
200 menu.push :register, :register_path, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
200 menu.push :register, :register_path, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
201 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
201 menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? }
202 menu.push :logout, :signout_path, :html => {:method => 'post'}, :if => Proc.new { User.current.logged? }
202 menu.push :logout, :signout_path, :html => {:method => 'post'}, :if => Proc.new { User.current.logged? }
203 end
203 end
204
204
205 Redmine::MenuManager.map :application_menu do |menu|
205 Redmine::MenuManager.map :application_menu do |menu|
206 # Empty
206 # Empty
207 end
207 end
208
208
209 Redmine::MenuManager.map :admin_menu do |menu|
209 Redmine::MenuManager.map :admin_menu do |menu|
210 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
210 menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural
211 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
211 menu.push :users, {:controller => 'users'}, :caption => :label_user_plural
212 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
212 menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural
213 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
213 menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions
214 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
214 menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural
215 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
215 menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural,
216 :html => {:class => 'issue_statuses'}
216 :html => {:class => 'issue_statuses'}
217 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
217 menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow
218 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
218 menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural,
219 :html => {:class => 'custom_fields'}
219 :html => {:class => 'custom_fields'}
220 menu.push :enumerations, {:controller => 'enumerations'}
220 menu.push :enumerations, {:controller => 'enumerations'}
221 menu.push :settings, {:controller => 'settings'}
221 menu.push :settings, {:controller => 'settings'}
222 menu.push :ldap_authentication, {:controller => 'auth_sources', :action => 'index'},
222 menu.push :ldap_authentication, {:controller => 'auth_sources', :action => 'index'},
223 :html => {:class => 'server_authentication'}
223 :html => {:class => 'server_authentication'}
224 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
224 menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true
225 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
225 menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true
226 end
226 end
227
227
228 Redmine::MenuManager.map :project_menu do |menu|
228 Redmine::MenuManager.map :project_menu do |menu|
229 menu.push :overview, { :controller => 'projects', :action => 'show' }
229 menu.push :overview, { :controller => 'projects', :action => 'show' }
230 menu.push :activity, { :controller => 'activities', :action => 'index' }
230 menu.push :activity, { :controller => 'activities', :action => 'index' }
231 menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id,
231 menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id,
232 :if => Proc.new { |p| p.shared_versions.any? }
232 :if => Proc.new { |p| p.shared_versions.any? }
233 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
233 menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
234 menu.push :new_issue, { :controller => 'issues', :action => 'new', :copy_from => nil }, :param => :project_id, :caption => :label_issue_new,
235 :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) },
236 :if => Proc.new { |p| p.trackers.any? },
237 :permission => :add_issues
238 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
234 menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt
239 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
235 menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar
240 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
236 menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural
241 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
237 menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural
242 menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id,
238 menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id,
243 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
239 :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
244 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
240 menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id,
245 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
241 :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural
246 menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id
242 menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id
247 menu.push :repository, { :controller => 'repositories', :action => 'show', :repository_id => nil, :path => nil, :rev => nil },
243 menu.push :repository, { :controller => 'repositories', :action => 'show', :repository_id => nil, :path => nil, :rev => nil },
248 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
244 :if => Proc.new { |p| p.repository && !p.repository.new_record? }
249 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
245 menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true
250 end
246 end
251
247
252 Redmine::Activity.map do |activity|
248 Redmine::Activity.map do |activity|
253 activity.register :issues, :class_name => %w(Issue Journal)
249 activity.register :issues, :class_name => %w(Issue Journal)
254 activity.register :changesets
250 activity.register :changesets
255 activity.register :news
251 activity.register :news
256 activity.register :documents, :class_name => %w(Document Attachment)
252 activity.register :documents, :class_name => %w(Document Attachment)
257 activity.register :files, :class_name => 'Attachment'
253 activity.register :files, :class_name => 'Attachment'
258 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
254 activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false
259 activity.register :messages, :default => false
255 activity.register :messages, :default => false
260 activity.register :time_entries, :default => false
256 activity.register :time_entries, :default => false
261 end
257 end
262
258
263 Redmine::Search.map do |search|
259 Redmine::Search.map do |search|
264 search.register :issues
260 search.register :issues
265 search.register :news
261 search.register :news
266 search.register :documents
262 search.register :documents
267 search.register :changesets
263 search.register :changesets
268 search.register :wiki_pages
264 search.register :wiki_pages
269 search.register :messages
265 search.register :messages
270 search.register :projects
266 search.register :projects
271 end
267 end
272
268
273 Redmine::WikiFormatting.map do |format|
269 Redmine::WikiFormatting.map do |format|
274 format.register :textile
270 format.register :textile
275 format.register :markdown if Object.const_defined?(:Redcarpet)
271 format.register :markdown if Object.const_defined?(:Redcarpet)
276 end
272 end
277
273
278 ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
274 ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
@@ -1,4573 +1,4594
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 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 IssuesControllerTest < ActionController::TestCase
20 class IssuesControllerTest < ActionController::TestCase
21 fixtures :projects,
21 fixtures :projects,
22 :users, :email_addresses, :user_preferences,
22 :users, :email_addresses, :user_preferences,
23 :roles,
23 :roles,
24 :members,
24 :members,
25 :member_roles,
25 :member_roles,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :issue_relations,
28 :issue_relations,
29 :versions,
29 :versions,
30 :trackers,
30 :trackers,
31 :projects_trackers,
31 :projects_trackers,
32 :issue_categories,
32 :issue_categories,
33 :enabled_modules,
33 :enabled_modules,
34 :enumerations,
34 :enumerations,
35 :attachments,
35 :attachments,
36 :workflows,
36 :workflows,
37 :custom_fields,
37 :custom_fields,
38 :custom_values,
38 :custom_values,
39 :custom_fields_projects,
39 :custom_fields_projects,
40 :custom_fields_trackers,
40 :custom_fields_trackers,
41 :time_entries,
41 :time_entries,
42 :journals,
42 :journals,
43 :journal_details,
43 :journal_details,
44 :queries,
44 :queries,
45 :repositories,
45 :repositories,
46 :changesets
46 :changesets
47
47
48 include Redmine::I18n
48 include Redmine::I18n
49
49
50 def setup
50 def setup
51 User.current = nil
51 User.current = nil
52 end
52 end
53
53
54 def test_index
54 def test_index
55 with_settings :default_language => "en" do
55 with_settings :default_language => "en" do
56 get :index
56 get :index
57 assert_response :success
57 assert_response :success
58 assert_template 'index'
58 assert_template 'index'
59 assert_not_nil assigns(:issues)
59 assert_not_nil assigns(:issues)
60 assert_nil assigns(:project)
60 assert_nil assigns(:project)
61
61
62 # links to visible issues
62 # links to visible issues
63 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
63 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
64 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
64 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
65 # private projects hidden
65 # private projects hidden
66 assert_select 'a[href="/issues/6"]', 0
66 assert_select 'a[href="/issues/6"]', 0
67 assert_select 'a[href="/issues/4"]', 0
67 assert_select 'a[href="/issues/4"]', 0
68 # project column
68 # project column
69 assert_select 'th', :text => /Project/
69 assert_select 'th', :text => /Project/
70 end
70 end
71 end
71 end
72
72
73 def test_index_should_not_list_issues_when_module_disabled
73 def test_index_should_not_list_issues_when_module_disabled
74 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
74 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
75 get :index
75 get :index
76 assert_response :success
76 assert_response :success
77 assert_template 'index'
77 assert_template 'index'
78 assert_not_nil assigns(:issues)
78 assert_not_nil assigns(:issues)
79 assert_nil assigns(:project)
79 assert_nil assigns(:project)
80
80
81 assert_select 'a[href="/issues/1"]', 0
81 assert_select 'a[href="/issues/1"]', 0
82 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
82 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
83 end
83 end
84
84
85 def test_index_should_list_visible_issues_only
85 def test_index_should_list_visible_issues_only
86 get :index, :per_page => 100
86 get :index, :per_page => 100
87 assert_response :success
87 assert_response :success
88 assert_not_nil assigns(:issues)
88 assert_not_nil assigns(:issues)
89 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
89 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
90 end
90 end
91
91
92 def test_index_with_project
92 def test_index_with_project
93 Setting.display_subprojects_issues = 0
93 Setting.display_subprojects_issues = 0
94 get :index, :project_id => 1
94 get :index, :project_id => 1
95 assert_response :success
95 assert_response :success
96 assert_template 'index'
96 assert_template 'index'
97 assert_not_nil assigns(:issues)
97 assert_not_nil assigns(:issues)
98
98
99 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
99 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
100 assert_select 'a[href="/issues/5"]', 0
100 assert_select 'a[href="/issues/5"]', 0
101 end
101 end
102
102
103 def test_index_with_project_and_subprojects
103 def test_index_with_project_and_subprojects
104 Setting.display_subprojects_issues = 1
104 Setting.display_subprojects_issues = 1
105 get :index, :project_id => 1
105 get :index, :project_id => 1
106 assert_response :success
106 assert_response :success
107 assert_template 'index'
107 assert_template 'index'
108 assert_not_nil assigns(:issues)
108 assert_not_nil assigns(:issues)
109
109
110 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
110 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
111 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
111 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
112 assert_select 'a[href="/issues/6"]', 0
112 assert_select 'a[href="/issues/6"]', 0
113 end
113 end
114
114
115 def test_index_with_project_and_subprojects_should_show_private_subprojects_with_permission
115 def test_index_with_project_and_subprojects_should_show_private_subprojects_with_permission
116 @request.session[:user_id] = 2
116 @request.session[:user_id] = 2
117 Setting.display_subprojects_issues = 1
117 Setting.display_subprojects_issues = 1
118 get :index, :project_id => 1
118 get :index, :project_id => 1
119 assert_response :success
119 assert_response :success
120 assert_template 'index'
120 assert_template 'index'
121 assert_not_nil assigns(:issues)
121 assert_not_nil assigns(:issues)
122
122
123 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
123 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
124 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
124 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
125 assert_select 'a[href="/issues/6"]', :text => /Issue of a private subproject/
125 assert_select 'a[href="/issues/6"]', :text => /Issue of a private subproject/
126 end
126 end
127
127
128 def test_index_with_project_and_default_filter
128 def test_index_with_project_and_default_filter
129 get :index, :project_id => 1, :set_filter => 1
129 get :index, :project_id => 1, :set_filter => 1
130 assert_response :success
130 assert_response :success
131 assert_template 'index'
131 assert_template 'index'
132 assert_not_nil assigns(:issues)
132 assert_not_nil assigns(:issues)
133
133
134 query = assigns(:query)
134 query = assigns(:query)
135 assert_not_nil query
135 assert_not_nil query
136 # default filter
136 # default filter
137 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
137 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
138 end
138 end
139
139
140 def test_index_with_project_and_filter
140 def test_index_with_project_and_filter
141 get :index, :project_id => 1, :set_filter => 1,
141 get :index, :project_id => 1, :set_filter => 1,
142 :f => ['tracker_id'],
142 :f => ['tracker_id'],
143 :op => {'tracker_id' => '='},
143 :op => {'tracker_id' => '='},
144 :v => {'tracker_id' => ['1']}
144 :v => {'tracker_id' => ['1']}
145 assert_response :success
145 assert_response :success
146 assert_template 'index'
146 assert_template 'index'
147 assert_not_nil assigns(:issues)
147 assert_not_nil assigns(:issues)
148
148
149 query = assigns(:query)
149 query = assigns(:query)
150 assert_not_nil query
150 assert_not_nil query
151 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
151 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
152 end
152 end
153
153
154 def test_index_with_short_filters
154 def test_index_with_short_filters
155 to_test = {
155 to_test = {
156 'status_id' => {
156 'status_id' => {
157 'o' => { :op => 'o', :values => [''] },
157 'o' => { :op => 'o', :values => [''] },
158 'c' => { :op => 'c', :values => [''] },
158 'c' => { :op => 'c', :values => [''] },
159 '7' => { :op => '=', :values => ['7'] },
159 '7' => { :op => '=', :values => ['7'] },
160 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
160 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
161 '=7' => { :op => '=', :values => ['7'] },
161 '=7' => { :op => '=', :values => ['7'] },
162 '!3' => { :op => '!', :values => ['3'] },
162 '!3' => { :op => '!', :values => ['3'] },
163 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
163 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
164 'subject' => {
164 'subject' => {
165 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
165 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
166 'o' => { :op => '=', :values => ['o'] },
166 'o' => { :op => '=', :values => ['o'] },
167 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
167 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
168 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
168 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
169 'tracker_id' => {
169 'tracker_id' => {
170 '3' => { :op => '=', :values => ['3'] },
170 '3' => { :op => '=', :values => ['3'] },
171 '=3' => { :op => '=', :values => ['3'] }},
171 '=3' => { :op => '=', :values => ['3'] }},
172 'start_date' => {
172 'start_date' => {
173 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
173 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
174 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
174 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
175 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
175 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
176 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
176 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
177 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
177 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
178 '<t+2' => { :op => '<t+', :values => ['2'] },
178 '<t+2' => { :op => '<t+', :values => ['2'] },
179 '>t+2' => { :op => '>t+', :values => ['2'] },
179 '>t+2' => { :op => '>t+', :values => ['2'] },
180 't+2' => { :op => 't+', :values => ['2'] },
180 't+2' => { :op => 't+', :values => ['2'] },
181 't' => { :op => 't', :values => [''] },
181 't' => { :op => 't', :values => [''] },
182 'w' => { :op => 'w', :values => [''] },
182 'w' => { :op => 'w', :values => [''] },
183 '>t-2' => { :op => '>t-', :values => ['2'] },
183 '>t-2' => { :op => '>t-', :values => ['2'] },
184 '<t-2' => { :op => '<t-', :values => ['2'] },
184 '<t-2' => { :op => '<t-', :values => ['2'] },
185 't-2' => { :op => 't-', :values => ['2'] }},
185 't-2' => { :op => 't-', :values => ['2'] }},
186 'created_on' => {
186 'created_on' => {
187 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
187 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
188 '<t-2' => { :op => '<t-', :values => ['2'] },
188 '<t-2' => { :op => '<t-', :values => ['2'] },
189 '>t-2' => { :op => '>t-', :values => ['2'] },
189 '>t-2' => { :op => '>t-', :values => ['2'] },
190 't-2' => { :op => 't-', :values => ['2'] }},
190 't-2' => { :op => 't-', :values => ['2'] }},
191 'cf_1' => {
191 'cf_1' => {
192 'c' => { :op => '=', :values => ['c'] },
192 'c' => { :op => '=', :values => ['c'] },
193 '!c' => { :op => '!', :values => ['c'] },
193 '!c' => { :op => '!', :values => ['c'] },
194 '!*' => { :op => '!*', :values => [''] },
194 '!*' => { :op => '!*', :values => [''] },
195 '*' => { :op => '*', :values => [''] }},
195 '*' => { :op => '*', :values => [''] }},
196 'estimated_hours' => {
196 'estimated_hours' => {
197 '=13.4' => { :op => '=', :values => ['13.4'] },
197 '=13.4' => { :op => '=', :values => ['13.4'] },
198 '>=45' => { :op => '>=', :values => ['45'] },
198 '>=45' => { :op => '>=', :values => ['45'] },
199 '<=125' => { :op => '<=', :values => ['125'] },
199 '<=125' => { :op => '<=', :values => ['125'] },
200 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
200 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
201 '!*' => { :op => '!*', :values => [''] },
201 '!*' => { :op => '!*', :values => [''] },
202 '*' => { :op => '*', :values => [''] }}
202 '*' => { :op => '*', :values => [''] }}
203 }
203 }
204
204
205 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
205 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
206
206
207 to_test.each do |field, expression_and_expected|
207 to_test.each do |field, expression_and_expected|
208 expression_and_expected.each do |filter_expression, expected|
208 expression_and_expected.each do |filter_expression, expected|
209
209
210 get :index, :set_filter => 1, field => filter_expression
210 get :index, :set_filter => 1, field => filter_expression
211
211
212 assert_response :success
212 assert_response :success
213 assert_template 'index'
213 assert_template 'index'
214 assert_not_nil assigns(:issues)
214 assert_not_nil assigns(:issues)
215
215
216 query = assigns(:query)
216 query = assigns(:query)
217 assert_not_nil query
217 assert_not_nil query
218 assert query.has_filter?(field)
218 assert query.has_filter?(field)
219 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
219 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
220 end
220 end
221 end
221 end
222 end
222 end
223
223
224 def test_index_with_project_and_empty_filters
224 def test_index_with_project_and_empty_filters
225 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
225 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
226 assert_response :success
226 assert_response :success
227 assert_template 'index'
227 assert_template 'index'
228 assert_not_nil assigns(:issues)
228 assert_not_nil assigns(:issues)
229
229
230 query = assigns(:query)
230 query = assigns(:query)
231 assert_not_nil query
231 assert_not_nil query
232 # no filter
232 # no filter
233 assert_equal({}, query.filters)
233 assert_equal({}, query.filters)
234 end
234 end
235
235
236 def test_index_with_project_custom_field_filter
236 def test_index_with_project_custom_field_filter
237 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
237 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
238 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
238 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
239 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
239 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
240 filter_name = "project.cf_#{field.id}"
240 filter_name = "project.cf_#{field.id}"
241 @request.session[:user_id] = 1
241 @request.session[:user_id] = 1
242
242
243 get :index, :set_filter => 1,
243 get :index, :set_filter => 1,
244 :f => [filter_name],
244 :f => [filter_name],
245 :op => {filter_name => '='},
245 :op => {filter_name => '='},
246 :v => {filter_name => ['Foo']}
246 :v => {filter_name => ['Foo']}
247 assert_response :success
247 assert_response :success
248 assert_template 'index'
248 assert_template 'index'
249 assert_equal [3, 5], assigns(:issues).map(&:project_id).uniq.sort
249 assert_equal [3, 5], assigns(:issues).map(&:project_id).uniq.sort
250 end
250 end
251
251
252 def test_index_with_query
252 def test_index_with_query
253 get :index, :project_id => 1, :query_id => 5
253 get :index, :project_id => 1, :query_id => 5
254 assert_response :success
254 assert_response :success
255 assert_template 'index'
255 assert_template 'index'
256 assert_not_nil assigns(:issues)
256 assert_not_nil assigns(:issues)
257 assert_nil assigns(:issue_count_by_group)
257 assert_nil assigns(:issue_count_by_group)
258 end
258 end
259
259
260 def test_index_with_query_grouped_by_tracker
260 def test_index_with_query_grouped_by_tracker
261 get :index, :project_id => 1, :query_id => 6
261 get :index, :project_id => 1, :query_id => 6
262 assert_response :success
262 assert_response :success
263 assert_template 'index'
263 assert_template 'index'
264 assert_not_nil assigns(:issues)
264 assert_not_nil assigns(:issues)
265 assert_not_nil assigns(:issue_count_by_group)
265 assert_not_nil assigns(:issue_count_by_group)
266 end
266 end
267
267
268 def test_index_with_query_grouped_and_sorted_by_category
268 def test_index_with_query_grouped_and_sorted_by_category
269 get :index, :project_id => 1, :set_filter => 1, :group_by => "category", :sort => "category"
269 get :index, :project_id => 1, :set_filter => 1, :group_by => "category", :sort => "category"
270 assert_response :success
270 assert_response :success
271 assert_template 'index'
271 assert_template 'index'
272 assert_not_nil assigns(:issues)
272 assert_not_nil assigns(:issues)
273 assert_not_nil assigns(:issue_count_by_group)
273 assert_not_nil assigns(:issue_count_by_group)
274 end
274 end
275
275
276 def test_index_with_query_grouped_by_list_custom_field
276 def test_index_with_query_grouped_by_list_custom_field
277 get :index, :project_id => 1, :query_id => 9
277 get :index, :project_id => 1, :query_id => 9
278 assert_response :success
278 assert_response :success
279 assert_template 'index'
279 assert_template 'index'
280 assert_not_nil assigns(:issues)
280 assert_not_nil assigns(:issues)
281 assert_not_nil assigns(:issue_count_by_group)
281 assert_not_nil assigns(:issue_count_by_group)
282 end
282 end
283
283
284 def test_index_with_query_grouped_by_key_value_custom_field
284 def test_index_with_query_grouped_by_key_value_custom_field
285 cf = IssueCustomField.create!(:name => 'Key', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'enumeration')
285 cf = IssueCustomField.create!(:name => 'Key', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'enumeration')
286 cf.enumerations << valueb = CustomFieldEnumeration.new(:name => 'Value B', :position => 1)
286 cf.enumerations << valueb = CustomFieldEnumeration.new(:name => 'Value B', :position => 1)
287 cf.enumerations << valuea = CustomFieldEnumeration.new(:name => 'Value A', :position => 2)
287 cf.enumerations << valuea = CustomFieldEnumeration.new(:name => 'Value A', :position => 2)
288 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => valueb.id)
288 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => valueb.id)
289 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => valueb.id)
289 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => valueb.id)
290 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => valuea.id)
290 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => valuea.id)
291 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
291 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
292
292
293 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
293 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
294 assert_response :success
294 assert_response :success
295 assert_template 'index'
295 assert_template 'index'
296 assert_not_nil assigns(:issues)
296 assert_not_nil assigns(:issues)
297 assert_not_nil assigns(:issue_count_by_group)
297 assert_not_nil assigns(:issue_count_by_group)
298
298
299 assert_select 'tr.group', 3
299 assert_select 'tr.group', 3
300 assert_select 'tr.group' do
300 assert_select 'tr.group' do
301 assert_select 'span.name', :text => 'Value B'
301 assert_select 'span.name', :text => 'Value B'
302 assert_select 'span.count', :text => '2'
302 assert_select 'span.count', :text => '2'
303 end
303 end
304 assert_select 'tr.group' do
304 assert_select 'tr.group' do
305 assert_select 'span.name', :text => 'Value A'
305 assert_select 'span.name', :text => 'Value A'
306 assert_select 'span.count', :text => '1'
306 assert_select 'span.count', :text => '1'
307 end
307 end
308 end
308 end
309
309
310 def test_index_with_query_grouped_by_user_custom_field
310 def test_index_with_query_grouped_by_user_custom_field
311 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
311 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
312 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
312 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
313 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
313 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
314 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
314 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
315 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
315 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
316
316
317 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
317 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
318 assert_response :success
318 assert_response :success
319
319
320 assert_select 'tr.group', 3
320 assert_select 'tr.group', 3
321 assert_select 'tr.group' do
321 assert_select 'tr.group' do
322 assert_select 'a', :text => 'John Smith'
322 assert_select 'a', :text => 'John Smith'
323 assert_select 'span.count', :text => '1'
323 assert_select 'span.count', :text => '1'
324 end
324 end
325 assert_select 'tr.group' do
325 assert_select 'tr.group' do
326 assert_select 'a', :text => 'Dave Lopper'
326 assert_select 'a', :text => 'Dave Lopper'
327 assert_select 'span.count', :text => '2'
327 assert_select 'span.count', :text => '2'
328 end
328 end
329 end
329 end
330
330
331 def test_index_grouped_by_boolean_custom_field_should_distinguish_blank_and_false_values
331 def test_index_grouped_by_boolean_custom_field_should_distinguish_blank_and_false_values
332 cf = IssueCustomField.create!(:name => 'Bool', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'bool')
332 cf = IssueCustomField.create!(:name => 'Bool', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'bool')
333 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '1')
333 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '1')
334 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '0')
334 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '0')
335 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '')
335 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '')
336
336
337 with_settings :default_language => 'en' do
337 with_settings :default_language => 'en' do
338 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
338 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
339 assert_response :success
339 assert_response :success
340 end
340 end
341
341
342 assert_select 'tr.group', 3
342 assert_select 'tr.group', 3
343 assert_select 'tr.group', :text => /Yes/
343 assert_select 'tr.group', :text => /Yes/
344 assert_select 'tr.group', :text => /No/
344 assert_select 'tr.group', :text => /No/
345 assert_select 'tr.group', :text => /blank/
345 assert_select 'tr.group', :text => /blank/
346 end
346 end
347
347
348 def test_index_grouped_by_boolean_custom_field_with_false_group_in_first_position_should_show_the_group
348 def test_index_grouped_by_boolean_custom_field_with_false_group_in_first_position_should_show_the_group
349 cf = IssueCustomField.create!(:name => 'Bool', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'bool', :is_filter => true)
349 cf = IssueCustomField.create!(:name => 'Bool', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'bool', :is_filter => true)
350 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '0')
350 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '0')
351 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '0')
351 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '0')
352
352
353 with_settings :default_language => 'en' do
353 with_settings :default_language => 'en' do
354 get :index, :project_id => 1, :set_filter => 1, "cf_#{cf.id}" => "*", :group_by => "cf_#{cf.id}"
354 get :index, :project_id => 1, :set_filter => 1, "cf_#{cf.id}" => "*", :group_by => "cf_#{cf.id}"
355 assert_response :success
355 assert_response :success
356 assert_equal [1, 2], assigns(:issues).map(&:id).sort
356 assert_equal [1, 2], assigns(:issues).map(&:id).sort
357 end
357 end
358
358
359 assert_select 'tr.group', 1
359 assert_select 'tr.group', 1
360 assert_select 'tr.group', :text => /No/
360 assert_select 'tr.group', :text => /No/
361 end
361 end
362
362
363 def test_index_with_query_grouped_by_tracker_in_normal_order
363 def test_index_with_query_grouped_by_tracker_in_normal_order
364 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
364 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
365
365
366 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc'
366 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc'
367 assert_response :success
367 assert_response :success
368
368
369 trackers = assigns(:issues).map(&:tracker).uniq
369 trackers = assigns(:issues).map(&:tracker).uniq
370 assert_equal [1, 2, 3], trackers.map(&:id)
370 assert_equal [1, 2, 3], trackers.map(&:id)
371 end
371 end
372
372
373 def test_index_with_query_grouped_by_tracker_in_reverse_order
373 def test_index_with_query_grouped_by_tracker_in_reverse_order
374 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
374 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
375
375
376 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc,tracker:desc'
376 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc,tracker:desc'
377 assert_response :success
377 assert_response :success
378
378
379 trackers = assigns(:issues).map(&:tracker).uniq
379 trackers = assigns(:issues).map(&:tracker).uniq
380 assert_equal [3, 2, 1], trackers.map(&:id)
380 assert_equal [3, 2, 1], trackers.map(&:id)
381 end
381 end
382
382
383 def test_index_with_query_id_and_project_id_should_set_session_query
383 def test_index_with_query_id_and_project_id_should_set_session_query
384 get :index, :project_id => 1, :query_id => 4
384 get :index, :project_id => 1, :query_id => 4
385 assert_response :success
385 assert_response :success
386 assert_kind_of Hash, session[:query]
386 assert_kind_of Hash, session[:query]
387 assert_equal 4, session[:query][:id]
387 assert_equal 4, session[:query][:id]
388 assert_equal 1, session[:query][:project_id]
388 assert_equal 1, session[:query][:project_id]
389 end
389 end
390
390
391 def test_index_with_invalid_query_id_should_respond_404
391 def test_index_with_invalid_query_id_should_respond_404
392 get :index, :project_id => 1, :query_id => 999
392 get :index, :project_id => 1, :query_id => 999
393 assert_response 404
393 assert_response 404
394 end
394 end
395
395
396 def test_index_with_cross_project_query_in_session_should_show_project_issues
396 def test_index_with_cross_project_query_in_session_should_show_project_issues
397 q = IssueQuery.create!(:name => "test", :user_id => 2, :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
397 q = IssueQuery.create!(:name => "test", :user_id => 2, :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
398 @request.session[:query] = {:id => q.id, :project_id => 1}
398 @request.session[:query] = {:id => q.id, :project_id => 1}
399
399
400 with_settings :display_subprojects_issues => '0' do
400 with_settings :display_subprojects_issues => '0' do
401 get :index, :project_id => 1
401 get :index, :project_id => 1
402 end
402 end
403 assert_response :success
403 assert_response :success
404 assert_not_nil assigns(:query)
404 assert_not_nil assigns(:query)
405 assert_equal q.id, assigns(:query).id
405 assert_equal q.id, assigns(:query).id
406 assert_equal 1, assigns(:query).project_id
406 assert_equal 1, assigns(:query).project_id
407 assert_equal [1], assigns(:issues).map(&:project_id).uniq
407 assert_equal [1], assigns(:issues).map(&:project_id).uniq
408 end
408 end
409
409
410 def test_private_query_should_not_be_available_to_other_users
410 def test_private_query_should_not_be_available_to_other_users
411 q = IssueQuery.create!(:name => "private", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
411 q = IssueQuery.create!(:name => "private", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
412 @request.session[:user_id] = 3
412 @request.session[:user_id] = 3
413
413
414 get :index, :query_id => q.id
414 get :index, :query_id => q.id
415 assert_response 403
415 assert_response 403
416 end
416 end
417
417
418 def test_private_query_should_be_available_to_its_user
418 def test_private_query_should_be_available_to_its_user
419 q = IssueQuery.create!(:name => "private", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
419 q = IssueQuery.create!(:name => "private", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
420 @request.session[:user_id] = 2
420 @request.session[:user_id] = 2
421
421
422 get :index, :query_id => q.id
422 get :index, :query_id => q.id
423 assert_response :success
423 assert_response :success
424 end
424 end
425
425
426 def test_public_query_should_be_available_to_other_users
426 def test_public_query_should_be_available_to_other_users
427 q = IssueQuery.create!(:name => "public", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
427 q = IssueQuery.create!(:name => "public", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
428 @request.session[:user_id] = 3
428 @request.session[:user_id] = 3
429
429
430 get :index, :query_id => q.id
430 get :index, :query_id => q.id
431 assert_response :success
431 assert_response :success
432 end
432 end
433
433
434 def test_index_should_omit_page_param_in_export_links
434 def test_index_should_omit_page_param_in_export_links
435 get :index, :page => 2
435 get :index, :page => 2
436 assert_response :success
436 assert_response :success
437 assert_select 'a.atom[href="/issues.atom"]'
437 assert_select 'a.atom[href="/issues.atom"]'
438 assert_select 'a.csv[href="/issues.csv"]'
438 assert_select 'a.csv[href="/issues.csv"]'
439 assert_select 'a.pdf[href="/issues.pdf"]'
439 assert_select 'a.pdf[href="/issues.pdf"]'
440 assert_select 'form#csv-export-form[action="/issues.csv"]'
440 assert_select 'form#csv-export-form[action="/issues.csv"]'
441 end
441 end
442
442
443 def test_index_should_not_warn_when_not_exceeding_export_limit
443 def test_index_should_not_warn_when_not_exceeding_export_limit
444 with_settings :issues_export_limit => 200 do
444 with_settings :issues_export_limit => 200 do
445 get :index
445 get :index
446 assert_select '#csv-export-options p.icon-warning', 0
446 assert_select '#csv-export-options p.icon-warning', 0
447 end
447 end
448 end
448 end
449
449
450 def test_index_should_warn_when_exceeding_export_limit
450 def test_index_should_warn_when_exceeding_export_limit
451 with_settings :issues_export_limit => 2 do
451 with_settings :issues_export_limit => 2 do
452 get :index
452 get :index
453 assert_select '#csv-export-options p.icon-warning', :text => %r{limit: 2}
453 assert_select '#csv-export-options p.icon-warning', :text => %r{limit: 2}
454 end
454 end
455 end
455 end
456
456
457 def test_index_should_include_query_params_as_hidden_fields_in_csv_export_form
457 def test_index_should_include_query_params_as_hidden_fields_in_csv_export_form
458 get :index, :project_id => 1, :set_filter => "1", :tracker_id => "2", :sort => 'status', :c => ["status", "priority"]
458 get :index, :project_id => 1, :set_filter => "1", :tracker_id => "2", :sort => 'status', :c => ["status", "priority"]
459
459
460 assert_select '#csv-export-form[action=?]', '/projects/ecookbook/issues.csv'
460 assert_select '#csv-export-form[action=?]', '/projects/ecookbook/issues.csv'
461 assert_select '#csv-export-form[method=?]', 'get'
461 assert_select '#csv-export-form[method=?]', 'get'
462
462
463 assert_select '#csv-export-form' do
463 assert_select '#csv-export-form' do
464 assert_select 'input[name=?][value=?]', 'set_filter', '1'
464 assert_select 'input[name=?][value=?]', 'set_filter', '1'
465
465
466 assert_select 'input[name=?][value=?]', 'f[]', 'tracker_id'
466 assert_select 'input[name=?][value=?]', 'f[]', 'tracker_id'
467 assert_select 'input[name=?][value=?]', 'op[tracker_id]', '='
467 assert_select 'input[name=?][value=?]', 'op[tracker_id]', '='
468 assert_select 'input[name=?][value=?]', 'v[tracker_id][]', '2'
468 assert_select 'input[name=?][value=?]', 'v[tracker_id][]', '2'
469
469
470 assert_select 'input[name=?][value=?]', 'c[]', 'status'
470 assert_select 'input[name=?][value=?]', 'c[]', 'status'
471 assert_select 'input[name=?][value=?]', 'c[]', 'priority'
471 assert_select 'input[name=?][value=?]', 'c[]', 'priority'
472
472
473 assert_select 'input[name=?][value=?]', 'sort', 'status'
473 assert_select 'input[name=?][value=?]', 'sort', 'status'
474 end
474 end
475 end
475 end
476
476
477 def test_index_csv
477 def test_index_csv
478 get :index, :format => 'csv'
478 get :index, :format => 'csv'
479 assert_response :success
479 assert_response :success
480 assert_not_nil assigns(:issues)
480 assert_not_nil assigns(:issues)
481 assert_equal 'text/csv; header=present', @response.content_type
481 assert_equal 'text/csv; header=present', @response.content_type
482 assert @response.body.starts_with?("#,")
482 assert @response.body.starts_with?("#,")
483 lines = @response.body.chomp.split("\n")
483 lines = @response.body.chomp.split("\n")
484 assert_equal assigns(:query).columns.size, lines[0].split(',').size
484 assert_equal assigns(:query).columns.size, lines[0].split(',').size
485 end
485 end
486
486
487 def test_index_csv_with_project
487 def test_index_csv_with_project
488 get :index, :project_id => 1, :format => 'csv'
488 get :index, :project_id => 1, :format => 'csv'
489 assert_response :success
489 assert_response :success
490 assert_not_nil assigns(:issues)
490 assert_not_nil assigns(:issues)
491 assert_equal 'text/csv; header=present', @response.content_type
491 assert_equal 'text/csv; header=present', @response.content_type
492 end
492 end
493
493
494 def test_index_csv_with_description
494 def test_index_csv_with_description
495 Issue.generate!(:description => 'test_index_csv_with_description')
495 Issue.generate!(:description => 'test_index_csv_with_description')
496
496
497 with_settings :default_language => 'en' do
497 with_settings :default_language => 'en' do
498 get :index, :format => 'csv', :csv => {:description => '1'}
498 get :index, :format => 'csv', :csv => {:description => '1'}
499 assert_response :success
499 assert_response :success
500 assert_not_nil assigns(:issues)
500 assert_not_nil assigns(:issues)
501 end
501 end
502
502
503 assert_equal 'text/csv; header=present', response.content_type
503 assert_equal 'text/csv; header=present', response.content_type
504 headers = response.body.chomp.split("\n").first.split(',')
504 headers = response.body.chomp.split("\n").first.split(',')
505 assert_include 'Description', headers
505 assert_include 'Description', headers
506 assert_include 'test_index_csv_with_description', response.body
506 assert_include 'test_index_csv_with_description', response.body
507 end
507 end
508
508
509 def test_index_csv_with_spent_time_column
509 def test_index_csv_with_spent_time_column
510 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :subject => 'test_index_csv_with_spent_time_column', :author_id => 2)
510 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :subject => 'test_index_csv_with_spent_time_column', :author_id => 2)
511 TimeEntry.create!(:project => issue.project, :issue => issue, :hours => 7.33, :user => User.find(2), :spent_on => Date.today)
511 TimeEntry.create!(:project => issue.project, :issue => issue, :hours => 7.33, :user => User.find(2), :spent_on => Date.today)
512
512
513 get :index, :format => 'csv', :set_filter => '1', :c => %w(subject spent_hours)
513 get :index, :format => 'csv', :set_filter => '1', :c => %w(subject spent_hours)
514 assert_response :success
514 assert_response :success
515 assert_equal 'text/csv; header=present', @response.content_type
515 assert_equal 'text/csv; header=present', @response.content_type
516 lines = @response.body.chomp.split("\n")
516 lines = @response.body.chomp.split("\n")
517 assert_include "#{issue.id},#{issue.subject},7.33", lines
517 assert_include "#{issue.id},#{issue.subject},7.33", lines
518 end
518 end
519
519
520 def test_index_csv_with_all_columns
520 def test_index_csv_with_all_columns
521 get :index, :format => 'csv', :csv => {:columns => 'all'}
521 get :index, :format => 'csv', :csv => {:columns => 'all'}
522 assert_response :success
522 assert_response :success
523 assert_not_nil assigns(:issues)
523 assert_not_nil assigns(:issues)
524 assert_equal 'text/csv; header=present', @response.content_type
524 assert_equal 'text/csv; header=present', @response.content_type
525 assert_match /\A#,/, response.body
525 assert_match /\A#,/, response.body
526 lines = response.body.chomp.split("\n")
526 lines = response.body.chomp.split("\n")
527 assert_equal assigns(:query).available_inline_columns.size, lines[0].split(',').size
527 assert_equal assigns(:query).available_inline_columns.size, lines[0].split(',').size
528 end
528 end
529
529
530 def test_index_csv_with_multi_column_field
530 def test_index_csv_with_multi_column_field
531 CustomField.find(1).update_attribute :multiple, true
531 CustomField.find(1).update_attribute :multiple, true
532 issue = Issue.find(1)
532 issue = Issue.find(1)
533 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
533 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
534 issue.save!
534 issue.save!
535
535
536 get :index, :format => 'csv', :csv => {:columns => 'all'}
536 get :index, :format => 'csv', :csv => {:columns => 'all'}
537 assert_response :success
537 assert_response :success
538 lines = @response.body.chomp.split("\n")
538 lines = @response.body.chomp.split("\n")
539 assert lines.detect {|line| line.include?('"MySQL, Oracle"')}
539 assert lines.detect {|line| line.include?('"MySQL, Oracle"')}
540 end
540 end
541
541
542 def test_index_csv_should_format_float_custom_fields_with_csv_decimal_separator
542 def test_index_csv_should_format_float_custom_fields_with_csv_decimal_separator
543 field = IssueCustomField.create!(:name => 'Float', :is_for_all => true, :tracker_ids => [1], :field_format => 'float')
543 field = IssueCustomField.create!(:name => 'Float', :is_for_all => true, :tracker_ids => [1], :field_format => 'float')
544 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {field.id => '185.6'})
544 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {field.id => '185.6'})
545
545
546 with_settings :default_language => 'fr' do
546 with_settings :default_language => 'fr' do
547 get :index, :format => 'csv', :csv => {:columns => 'all'}
547 get :index, :format => 'csv', :csv => {:columns => 'all'}
548 assert_response :success
548 assert_response :success
549 issue_line = response.body.chomp.split("\n").map {|line| line.split(';')}.detect {|line| line[0]==issue.id.to_s}
549 issue_line = response.body.chomp.split("\n").map {|line| line.split(';')}.detect {|line| line[0]==issue.id.to_s}
550 assert_include '185,60', issue_line
550 assert_include '185,60', issue_line
551 end
551 end
552
552
553 with_settings :default_language => 'en' do
553 with_settings :default_language => 'en' do
554 get :index, :format => 'csv', :csv => {:columns => 'all'}
554 get :index, :format => 'csv', :csv => {:columns => 'all'}
555 assert_response :success
555 assert_response :success
556 issue_line = response.body.chomp.split("\n").map {|line| line.split(',')}.detect {|line| line[0]==issue.id.to_s}
556 issue_line = response.body.chomp.split("\n").map {|line| line.split(',')}.detect {|line| line[0]==issue.id.to_s}
557 assert_include '185.60', issue_line
557 assert_include '185.60', issue_line
558 end
558 end
559 end
559 end
560
560
561 def test_index_csv_should_fill_parent_column_with_parent_id
561 def test_index_csv_should_fill_parent_column_with_parent_id
562 Issue.delete_all
562 Issue.delete_all
563 parent = Issue.generate!
563 parent = Issue.generate!
564 child = Issue.generate!(:parent_issue_id => parent.id)
564 child = Issue.generate!(:parent_issue_id => parent.id)
565
565
566 with_settings :default_language => 'en' do
566 with_settings :default_language => 'en' do
567 get :index, :format => 'csv', :c => %w(parent)
567 get :index, :format => 'csv', :c => %w(parent)
568 end
568 end
569 lines = response.body.split("\n")
569 lines = response.body.split("\n")
570 assert_include "#{child.id},#{parent.id}", lines
570 assert_include "#{child.id},#{parent.id}", lines
571 end
571 end
572
572
573 def test_index_csv_big_5
573 def test_index_csv_big_5
574 with_settings :default_language => "zh-TW" do
574 with_settings :default_language => "zh-TW" do
575 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88".force_encoding('UTF-8')
575 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88".force_encoding('UTF-8')
576 str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
576 str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
577 issue = Issue.generate!(:subject => str_utf8)
577 issue = Issue.generate!(:subject => str_utf8)
578
578
579 get :index, :project_id => 1,
579 get :index, :project_id => 1,
580 :f => ['subject'],
580 :f => ['subject'],
581 :op => '=', :values => [str_utf8],
581 :op => '=', :values => [str_utf8],
582 :format => 'csv'
582 :format => 'csv'
583 assert_equal 'text/csv; header=present', @response.content_type
583 assert_equal 'text/csv; header=present', @response.content_type
584 lines = @response.body.chomp.split("\n")
584 lines = @response.body.chomp.split("\n")
585 header = lines[0]
585 header = lines[0]
586 status = "\xaa\xac\xbaA".force_encoding('Big5')
586 status = "\xaa\xac\xbaA".force_encoding('Big5')
587 assert_include status, header
587 assert_include status, header
588 issue_line = lines.find {|l| l =~ /^#{issue.id},/}
588 issue_line = lines.find {|l| l =~ /^#{issue.id},/}
589 assert_include str_big5, issue_line
589 assert_include str_big5, issue_line
590 end
590 end
591 end
591 end
592
592
593 def test_index_csv_cannot_convert_should_be_replaced_big_5
593 def test_index_csv_cannot_convert_should_be_replaced_big_5
594 with_settings :default_language => "zh-TW" do
594 with_settings :default_language => "zh-TW" do
595 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
595 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
596 issue = Issue.generate!(:subject => str_utf8)
596 issue = Issue.generate!(:subject => str_utf8)
597
597
598 get :index, :project_id => 1,
598 get :index, :project_id => 1,
599 :f => ['subject'],
599 :f => ['subject'],
600 :op => '=', :values => [str_utf8],
600 :op => '=', :values => [str_utf8],
601 :c => ['status', 'subject'],
601 :c => ['status', 'subject'],
602 :format => 'csv',
602 :format => 'csv',
603 :set_filter => 1
603 :set_filter => 1
604 assert_equal 'text/csv; header=present', @response.content_type
604 assert_equal 'text/csv; header=present', @response.content_type
605 lines = @response.body.chomp.split("\n")
605 lines = @response.body.chomp.split("\n")
606 header = lines[0]
606 header = lines[0]
607 issue_line = lines.find {|l| l =~ /^#{issue.id},/}
607 issue_line = lines.find {|l| l =~ /^#{issue.id},/}
608 s1 = "\xaa\xac\xbaA".force_encoding('Big5') # status
608 s1 = "\xaa\xac\xbaA".force_encoding('Big5') # status
609 assert header.include?(s1)
609 assert header.include?(s1)
610 s2 = issue_line.split(",")[2]
610 s2 = issue_line.split(",")[2]
611 s3 = "\xa5H?".force_encoding('Big5') # subject
611 s3 = "\xa5H?".force_encoding('Big5') # subject
612 assert_equal s3, s2
612 assert_equal s3, s2
613 end
613 end
614 end
614 end
615
615
616 def test_index_csv_tw
616 def test_index_csv_tw
617 with_settings :default_language => "zh-TW" do
617 with_settings :default_language => "zh-TW" do
618 str1 = "test_index_csv_tw"
618 str1 = "test_index_csv_tw"
619 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
619 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
620
620
621 get :index, :project_id => 1,
621 get :index, :project_id => 1,
622 :f => ['subject'],
622 :f => ['subject'],
623 :op => '=', :values => [str1],
623 :op => '=', :values => [str1],
624 :c => ['estimated_hours', 'subject'],
624 :c => ['estimated_hours', 'subject'],
625 :format => 'csv',
625 :format => 'csv',
626 :set_filter => 1
626 :set_filter => 1
627 assert_equal 'text/csv; header=present', @response.content_type
627 assert_equal 'text/csv; header=present', @response.content_type
628 lines = @response.body.chomp.split("\n")
628 lines = @response.body.chomp.split("\n")
629 assert_include "#{issue.id},1234.50,#{str1}", lines
629 assert_include "#{issue.id},1234.50,#{str1}", lines
630 end
630 end
631 end
631 end
632
632
633 def test_index_csv_fr
633 def test_index_csv_fr
634 with_settings :default_language => "fr" do
634 with_settings :default_language => "fr" do
635 str1 = "test_index_csv_fr"
635 str1 = "test_index_csv_fr"
636 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
636 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
637
637
638 get :index, :project_id => 1,
638 get :index, :project_id => 1,
639 :f => ['subject'],
639 :f => ['subject'],
640 :op => '=', :values => [str1],
640 :op => '=', :values => [str1],
641 :c => ['estimated_hours', 'subject'],
641 :c => ['estimated_hours', 'subject'],
642 :format => 'csv',
642 :format => 'csv',
643 :set_filter => 1
643 :set_filter => 1
644 assert_equal 'text/csv; header=present', @response.content_type
644 assert_equal 'text/csv; header=present', @response.content_type
645 lines = @response.body.chomp.split("\n")
645 lines = @response.body.chomp.split("\n")
646 assert_include "#{issue.id};1234,50;#{str1}", lines
646 assert_include "#{issue.id};1234,50;#{str1}", lines
647 end
647 end
648 end
648 end
649
649
650 def test_index_pdf
650 def test_index_pdf
651 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
651 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
652 with_settings :default_language => lang do
652 with_settings :default_language => lang do
653
653
654 get :index
654 get :index
655 assert_response :success
655 assert_response :success
656 assert_template 'index'
656 assert_template 'index'
657
657
658 get :index, :format => 'pdf'
658 get :index, :format => 'pdf'
659 assert_response :success
659 assert_response :success
660 assert_not_nil assigns(:issues)
660 assert_not_nil assigns(:issues)
661 assert_equal 'application/pdf', @response.content_type
661 assert_equal 'application/pdf', @response.content_type
662
662
663 get :index, :project_id => 1, :format => 'pdf'
663 get :index, :project_id => 1, :format => 'pdf'
664 assert_response :success
664 assert_response :success
665 assert_not_nil assigns(:issues)
665 assert_not_nil assigns(:issues)
666 assert_equal 'application/pdf', @response.content_type
666 assert_equal 'application/pdf', @response.content_type
667
667
668 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
668 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
669 assert_response :success
669 assert_response :success
670 assert_not_nil assigns(:issues)
670 assert_not_nil assigns(:issues)
671 assert_equal 'application/pdf', @response.content_type
671 assert_equal 'application/pdf', @response.content_type
672 end
672 end
673 end
673 end
674 end
674 end
675
675
676 def test_index_pdf_with_query_grouped_by_list_custom_field
676 def test_index_pdf_with_query_grouped_by_list_custom_field
677 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
677 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
678 assert_response :success
678 assert_response :success
679 assert_not_nil assigns(:issues)
679 assert_not_nil assigns(:issues)
680 assert_not_nil assigns(:issue_count_by_group)
680 assert_not_nil assigns(:issue_count_by_group)
681 assert_equal 'application/pdf', @response.content_type
681 assert_equal 'application/pdf', @response.content_type
682 end
682 end
683
683
684 def test_index_atom
684 def test_index_atom
685 get :index, :project_id => 'ecookbook', :format => 'atom'
685 get :index, :project_id => 'ecookbook', :format => 'atom'
686 assert_response :success
686 assert_response :success
687 assert_template 'common/feed'
687 assert_template 'common/feed'
688 assert_equal 'application/atom+xml', response.content_type
688 assert_equal 'application/atom+xml', response.content_type
689
689
690 assert_select 'feed' do
690 assert_select 'feed' do
691 assert_select 'link[rel=self][href=?]', 'http://test.host/projects/ecookbook/issues.atom'
691 assert_select 'link[rel=self][href=?]', 'http://test.host/projects/ecookbook/issues.atom'
692 assert_select 'link[rel=alternate][href=?]', 'http://test.host/projects/ecookbook/issues'
692 assert_select 'link[rel=alternate][href=?]', 'http://test.host/projects/ecookbook/issues'
693 assert_select 'entry link[href=?]', 'http://test.host/issues/1'
693 assert_select 'entry link[href=?]', 'http://test.host/issues/1'
694 end
694 end
695 end
695 end
696
696
697 def test_index_sort
697 def test_index_sort
698 get :index, :sort => 'tracker,id:desc'
698 get :index, :sort => 'tracker,id:desc'
699 assert_response :success
699 assert_response :success
700
700
701 sort_params = @request.session['issues_index_sort']
701 sort_params = @request.session['issues_index_sort']
702 assert sort_params.is_a?(String)
702 assert sort_params.is_a?(String)
703 assert_equal 'tracker,id:desc', sort_params
703 assert_equal 'tracker,id:desc', sort_params
704
704
705 issues = assigns(:issues)
705 issues = assigns(:issues)
706 assert_not_nil issues
706 assert_not_nil issues
707 assert !issues.empty?
707 assert !issues.empty?
708 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
708 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
709 assert_select 'table.issues.sort-by-tracker.sort-asc'
709 assert_select 'table.issues.sort-by-tracker.sort-asc'
710 end
710 end
711
711
712 def test_index_sort_by_field_not_included_in_columns
712 def test_index_sort_by_field_not_included_in_columns
713 Setting.issue_list_default_columns = %w(subject author)
713 Setting.issue_list_default_columns = %w(subject author)
714 get :index, :sort => 'tracker'
714 get :index, :sort => 'tracker'
715 end
715 end
716
716
717 def test_index_sort_by_assigned_to
717 def test_index_sort_by_assigned_to
718 get :index, :sort => 'assigned_to'
718 get :index, :sort => 'assigned_to'
719 assert_response :success
719 assert_response :success
720 assignees = assigns(:issues).collect(&:assigned_to).compact
720 assignees = assigns(:issues).collect(&:assigned_to).compact
721 assert_equal assignees.sort, assignees
721 assert_equal assignees.sort, assignees
722 assert_select 'table.issues.sort-by-assigned-to.sort-asc'
722 assert_select 'table.issues.sort-by-assigned-to.sort-asc'
723 end
723 end
724
724
725 def test_index_sort_by_assigned_to_desc
725 def test_index_sort_by_assigned_to_desc
726 get :index, :sort => 'assigned_to:desc'
726 get :index, :sort => 'assigned_to:desc'
727 assert_response :success
727 assert_response :success
728 assignees = assigns(:issues).collect(&:assigned_to).compact
728 assignees = assigns(:issues).collect(&:assigned_to).compact
729 assert_equal assignees.sort.reverse, assignees
729 assert_equal assignees.sort.reverse, assignees
730 assert_select 'table.issues.sort-by-assigned-to.sort-desc'
730 assert_select 'table.issues.sort-by-assigned-to.sort-desc'
731 end
731 end
732
732
733 def test_index_group_by_assigned_to
733 def test_index_group_by_assigned_to
734 get :index, :group_by => 'assigned_to', :sort => 'priority'
734 get :index, :group_by => 'assigned_to', :sort => 'priority'
735 assert_response :success
735 assert_response :success
736 end
736 end
737
737
738 def test_index_sort_by_author
738 def test_index_sort_by_author
739 get :index, :sort => 'author'
739 get :index, :sort => 'author'
740 assert_response :success
740 assert_response :success
741 authors = assigns(:issues).collect(&:author)
741 authors = assigns(:issues).collect(&:author)
742 assert_equal authors.sort, authors
742 assert_equal authors.sort, authors
743 end
743 end
744
744
745 def test_index_sort_by_author_desc
745 def test_index_sort_by_author_desc
746 get :index, :sort => 'author:desc'
746 get :index, :sort => 'author:desc'
747 assert_response :success
747 assert_response :success
748 authors = assigns(:issues).collect(&:author)
748 authors = assigns(:issues).collect(&:author)
749 assert_equal authors.sort.reverse, authors
749 assert_equal authors.sort.reverse, authors
750 end
750 end
751
751
752 def test_index_group_by_author
752 def test_index_group_by_author
753 get :index, :group_by => 'author', :sort => 'priority'
753 get :index, :group_by => 'author', :sort => 'priority'
754 assert_response :success
754 assert_response :success
755 end
755 end
756
756
757 def test_index_sort_by_spent_hours
757 def test_index_sort_by_spent_hours
758 get :index, :sort => 'spent_hours:desc'
758 get :index, :sort => 'spent_hours:desc'
759 assert_response :success
759 assert_response :success
760 hours = assigns(:issues).collect(&:spent_hours)
760 hours = assigns(:issues).collect(&:spent_hours)
761 assert_equal hours.sort.reverse, hours
761 assert_equal hours.sort.reverse, hours
762 end
762 end
763
763
764 def test_index_sort_by_total_spent_hours
764 def test_index_sort_by_total_spent_hours
765 get :index, :sort => 'total_spent_hours:desc'
765 get :index, :sort => 'total_spent_hours:desc'
766 assert_response :success
766 assert_response :success
767 hours = assigns(:issues).collect(&:total_spent_hours)
767 hours = assigns(:issues).collect(&:total_spent_hours)
768 assert_equal hours.sort.reverse, hours
768 assert_equal hours.sort.reverse, hours
769 end
769 end
770
770
771 def test_index_sort_by_total_estimated_hours
771 def test_index_sort_by_total_estimated_hours
772 get :index, :sort => 'total_estimated_hours:desc'
772 get :index, :sort => 'total_estimated_hours:desc'
773 assert_response :success
773 assert_response :success
774 hours = assigns(:issues).collect(&:total_estimated_hours)
774 hours = assigns(:issues).collect(&:total_estimated_hours)
775 assert_equal hours.sort.reverse, hours
775 assert_equal hours.sort.reverse, hours
776 end
776 end
777
777
778 def test_index_sort_by_user_custom_field
778 def test_index_sort_by_user_custom_field
779 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
779 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
780 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
780 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
781 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
781 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
782 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
782 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
783 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
783 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
784
784
785 get :index, :project_id => 1, :set_filter => 1, :sort => "cf_#{cf.id},id"
785 get :index, :project_id => 1, :set_filter => 1, :sort => "cf_#{cf.id},id"
786 assert_response :success
786 assert_response :success
787
787
788 assert_equal [2, 3, 1], assigns(:issues).select {|issue| issue.custom_field_value(cf).present?}.map(&:id)
788 assert_equal [2, 3, 1], assigns(:issues).select {|issue| issue.custom_field_value(cf).present?}.map(&:id)
789 end
789 end
790
790
791 def test_index_with_columns
791 def test_index_with_columns
792 columns = ['tracker', 'subject', 'assigned_to']
792 columns = ['tracker', 'subject', 'assigned_to']
793 get :index, :set_filter => 1, :c => columns
793 get :index, :set_filter => 1, :c => columns
794 assert_response :success
794 assert_response :success
795
795
796 # query should use specified columns
796 # query should use specified columns
797 query = assigns(:query)
797 query = assigns(:query)
798 assert_kind_of IssueQuery, query
798 assert_kind_of IssueQuery, query
799 assert_equal columns, query.column_names.map(&:to_s)
799 assert_equal columns, query.column_names.map(&:to_s)
800
800
801 # columns should be stored in session
801 # columns should be stored in session
802 assert_kind_of Hash, session[:query]
802 assert_kind_of Hash, session[:query]
803 assert_kind_of Array, session[:query][:column_names]
803 assert_kind_of Array, session[:query][:column_names]
804 assert_equal columns, session[:query][:column_names].map(&:to_s)
804 assert_equal columns, session[:query][:column_names].map(&:to_s)
805
805
806 # ensure only these columns are kept in the selected columns list
806 # ensure only these columns are kept in the selected columns list
807 assert_select 'select#selected_columns option' do
807 assert_select 'select#selected_columns option' do
808 assert_select 'option', 3
808 assert_select 'option', 3
809 assert_select 'option[value=tracker]'
809 assert_select 'option[value=tracker]'
810 assert_select 'option[value=project]', 0
810 assert_select 'option[value=project]', 0
811 end
811 end
812 end
812 end
813
813
814 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
814 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
815 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
815 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
816 get :index, :set_filter => 1
816 get :index, :set_filter => 1
817
817
818 # query should use specified columns
818 # query should use specified columns
819 query = assigns(:query)
819 query = assigns(:query)
820 assert_kind_of IssueQuery, query
820 assert_kind_of IssueQuery, query
821 assert_equal [:id, :project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
821 assert_equal [:id, :project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
822 end
822 end
823
823
824 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
824 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
825 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
825 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
826 columns = ['id', 'tracker', 'subject', 'assigned_to']
826 columns = ['id', 'tracker', 'subject', 'assigned_to']
827 get :index, :set_filter => 1, :c => columns
827 get :index, :set_filter => 1, :c => columns
828
828
829 # query should use specified columns
829 # query should use specified columns
830 query = assigns(:query)
830 query = assigns(:query)
831 assert_kind_of IssueQuery, query
831 assert_kind_of IssueQuery, query
832 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
832 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
833 end
833 end
834
834
835 def test_index_with_default_columns_should_respect_default_columns_order
835 def test_index_with_default_columns_should_respect_default_columns_order
836 columns = ['assigned_to', 'subject', 'status', 'tracker']
836 columns = ['assigned_to', 'subject', 'status', 'tracker']
837 with_settings :issue_list_default_columns => columns do
837 with_settings :issue_list_default_columns => columns do
838 get :index, :project_id => 1, :set_filter => 1
838 get :index, :project_id => 1, :set_filter => 1
839
839
840 query = assigns(:query)
840 query = assigns(:query)
841 assert_equal (['id'] + columns).map(&:to_sym), query.columns.map(&:name)
841 assert_equal (['id'] + columns).map(&:to_sym), query.columns.map(&:name)
842 end
842 end
843 end
843 end
844
844
845 def test_index_with_custom_field_column
845 def test_index_with_custom_field_column
846 columns = %w(tracker subject cf_2)
846 columns = %w(tracker subject cf_2)
847 get :index, :set_filter => 1, :c => columns
847 get :index, :set_filter => 1, :c => columns
848 assert_response :success
848 assert_response :success
849
849
850 # query should use specified columns
850 # query should use specified columns
851 query = assigns(:query)
851 query = assigns(:query)
852 assert_kind_of IssueQuery, query
852 assert_kind_of IssueQuery, query
853 assert_equal columns, query.column_names.map(&:to_s)
853 assert_equal columns, query.column_names.map(&:to_s)
854
854
855 assert_select 'table.issues td.cf_2.string'
855 assert_select 'table.issues td.cf_2.string'
856 end
856 end
857
857
858 def test_index_with_multi_custom_field_column
858 def test_index_with_multi_custom_field_column
859 field = CustomField.find(1)
859 field = CustomField.find(1)
860 field.update_attribute :multiple, true
860 field.update_attribute :multiple, true
861 issue = Issue.find(1)
861 issue = Issue.find(1)
862 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
862 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
863 issue.save!
863 issue.save!
864
864
865 get :index, :set_filter => 1, :c => %w(tracker subject cf_1)
865 get :index, :set_filter => 1, :c => %w(tracker subject cf_1)
866 assert_response :success
866 assert_response :success
867
867
868 assert_select 'table.issues td.cf_1', :text => 'MySQL, Oracle'
868 assert_select 'table.issues td.cf_1', :text => 'MySQL, Oracle'
869 end
869 end
870
870
871 def test_index_with_multi_user_custom_field_column
871 def test_index_with_multi_user_custom_field_column
872 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
872 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
873 :tracker_ids => [1], :is_for_all => true)
873 :tracker_ids => [1], :is_for_all => true)
874 issue = Issue.find(1)
874 issue = Issue.find(1)
875 issue.custom_field_values = {field.id => ['2', '3']}
875 issue.custom_field_values = {field.id => ['2', '3']}
876 issue.save!
876 issue.save!
877
877
878 get :index, :set_filter => 1, :c => ['tracker', 'subject', "cf_#{field.id}"]
878 get :index, :set_filter => 1, :c => ['tracker', 'subject', "cf_#{field.id}"]
879 assert_response :success
879 assert_response :success
880
880
881 assert_select "table.issues td.cf_#{field.id}" do
881 assert_select "table.issues td.cf_#{field.id}" do
882 assert_select 'a', 2
882 assert_select 'a', 2
883 assert_select 'a[href=?]', '/users/2', :text => 'John Smith'
883 assert_select 'a[href=?]', '/users/2', :text => 'John Smith'
884 assert_select 'a[href=?]', '/users/3', :text => 'Dave Lopper'
884 assert_select 'a[href=?]', '/users/3', :text => 'Dave Lopper'
885 end
885 end
886 end
886 end
887
887
888 def test_index_with_date_column
888 def test_index_with_date_column
889 with_settings :date_format => '%d/%m/%Y' do
889 with_settings :date_format => '%d/%m/%Y' do
890 Issue.find(1).update_attribute :start_date, '1987-08-24'
890 Issue.find(1).update_attribute :start_date, '1987-08-24'
891 get :index, :set_filter => 1, :c => %w(start_date)
891 get :index, :set_filter => 1, :c => %w(start_date)
892 assert_select "table.issues td.start_date", :text => '24/08/1987'
892 assert_select "table.issues td.start_date", :text => '24/08/1987'
893 end
893 end
894 end
894 end
895
895
896 def test_index_with_done_ratio_column
896 def test_index_with_done_ratio_column
897 Issue.find(1).update_attribute :done_ratio, 40
897 Issue.find(1).update_attribute :done_ratio, 40
898 get :index, :set_filter => 1, :c => %w(done_ratio)
898 get :index, :set_filter => 1, :c => %w(done_ratio)
899 assert_select 'table.issues td.done_ratio' do
899 assert_select 'table.issues td.done_ratio' do
900 assert_select 'table.progress' do
900 assert_select 'table.progress' do
901 assert_select 'td.closed[style=?]', 'width: 40%;'
901 assert_select 'td.closed[style=?]', 'width: 40%;'
902 end
902 end
903 end
903 end
904 end
904 end
905
905
906 def test_index_with_spent_hours_column
906 def test_index_with_spent_hours_column
907 Issue.expects(:load_visible_spent_hours).once
907 Issue.expects(:load_visible_spent_hours).once
908 get :index, :set_filter => 1, :c => %w(subject spent_hours)
908 get :index, :set_filter => 1, :c => %w(subject spent_hours)
909 assert_select 'table.issues tr#issue-3 td.spent_hours', :text => '1.00'
909 assert_select 'table.issues tr#issue-3 td.spent_hours', :text => '1.00'
910 end
910 end
911
911
912 def test_index_with_total_spent_hours_column
912 def test_index_with_total_spent_hours_column
913 Issue.expects(:load_visible_total_spent_hours).once
913 Issue.expects(:load_visible_total_spent_hours).once
914 get :index, :set_filter => 1, :c => %w(subject total_spent_hours)
914 get :index, :set_filter => 1, :c => %w(subject total_spent_hours)
915 assert_select 'table.issues tr#issue-3 td.total_spent_hours', :text => '1.00'
915 assert_select 'table.issues tr#issue-3 td.total_spent_hours', :text => '1.00'
916 end
916 end
917
917
918 def test_index_with_total_estimated_hours_column
918 def test_index_with_total_estimated_hours_column
919 get :index, :set_filter => 1, :c => %w(subject total_estimated_hours)
919 get :index, :set_filter => 1, :c => %w(subject total_estimated_hours)
920 assert_select 'table.issues td.total_estimated_hours'
920 assert_select 'table.issues td.total_estimated_hours'
921 end
921 end
922
922
923 def test_index_should_not_show_spent_hours_column_without_permission
923 def test_index_should_not_show_spent_hours_column_without_permission
924 Role.anonymous.remove_permission! :view_time_entries
924 Role.anonymous.remove_permission! :view_time_entries
925 get :index, :set_filter => 1, :c => %w(subject spent_hours)
925 get :index, :set_filter => 1, :c => %w(subject spent_hours)
926 assert_select 'td.spent_hours', 0
926 assert_select 'td.spent_hours', 0
927 end
927 end
928
928
929 def test_index_with_fixed_version_column
929 def test_index_with_fixed_version_column
930 get :index, :set_filter => 1, :c => %w(fixed_version)
930 get :index, :set_filter => 1, :c => %w(fixed_version)
931 assert_select 'table.issues td.fixed_version' do
931 assert_select 'table.issues td.fixed_version' do
932 assert_select 'a[href=?]', '/versions/2', :text => 'eCookbook - 1.0'
932 assert_select 'a[href=?]', '/versions/2', :text => 'eCookbook - 1.0'
933 end
933 end
934 end
934 end
935
935
936 def test_index_with_relations_column
936 def test_index_with_relations_column
937 IssueRelation.delete_all
937 IssueRelation.delete_all
938 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(7))
938 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(7))
939 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(8), :issue_to => Issue.find(1))
939 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(8), :issue_to => Issue.find(1))
940 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(1), :issue_to => Issue.find(11))
940 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(1), :issue_to => Issue.find(11))
941 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(12), :issue_to => Issue.find(2))
941 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(12), :issue_to => Issue.find(2))
942
942
943 get :index, :set_filter => 1, :c => %w(subject relations)
943 get :index, :set_filter => 1, :c => %w(subject relations)
944 assert_response :success
944 assert_response :success
945 assert_select "tr#issue-1 td.relations" do
945 assert_select "tr#issue-1 td.relations" do
946 assert_select "span", 3
946 assert_select "span", 3
947 assert_select "span", :text => "Related to #7"
947 assert_select "span", :text => "Related to #7"
948 assert_select "span", :text => "Related to #8"
948 assert_select "span", :text => "Related to #8"
949 assert_select "span", :text => "Blocks #11"
949 assert_select "span", :text => "Blocks #11"
950 end
950 end
951 assert_select "tr#issue-2 td.relations" do
951 assert_select "tr#issue-2 td.relations" do
952 assert_select "span", 1
952 assert_select "span", 1
953 assert_select "span", :text => "Blocked by #12"
953 assert_select "span", :text => "Blocked by #12"
954 end
954 end
955 assert_select "tr#issue-3 td.relations" do
955 assert_select "tr#issue-3 td.relations" do
956 assert_select "span", 0
956 assert_select "span", 0
957 end
957 end
958
958
959 get :index, :set_filter => 1, :c => %w(relations), :format => 'csv'
959 get :index, :set_filter => 1, :c => %w(relations), :format => 'csv'
960 assert_response :success
960 assert_response :success
961 assert_equal 'text/csv; header=present', response.content_type
961 assert_equal 'text/csv; header=present', response.content_type
962 lines = response.body.chomp.split("\n")
962 lines = response.body.chomp.split("\n")
963 assert_include '1,"Related to #7, Related to #8, Blocks #11"', lines
963 assert_include '1,"Related to #7, Related to #8, Blocks #11"', lines
964 assert_include '2,Blocked by #12', lines
964 assert_include '2,Blocked by #12', lines
965 assert_include '3,""', lines
965 assert_include '3,""', lines
966
966
967 get :index, :set_filter => 1, :c => %w(subject relations), :format => 'pdf'
967 get :index, :set_filter => 1, :c => %w(subject relations), :format => 'pdf'
968 assert_response :success
968 assert_response :success
969 assert_equal 'application/pdf', response.content_type
969 assert_equal 'application/pdf', response.content_type
970 end
970 end
971
971
972 def test_index_with_description_column
972 def test_index_with_description_column
973 get :index, :set_filter => 1, :c => %w(subject description)
973 get :index, :set_filter => 1, :c => %w(subject description)
974
974
975 assert_select 'table.issues thead th', 3 # columns: chekbox + id + subject
975 assert_select 'table.issues thead th', 3 # columns: chekbox + id + subject
976 assert_select 'td.description[colspan="3"]', :text => 'Unable to print recipes'
976 assert_select 'td.description[colspan="3"]', :text => 'Unable to print recipes'
977
977
978 get :index, :set_filter => 1, :c => %w(subject description), :format => 'pdf'
978 get :index, :set_filter => 1, :c => %w(subject description), :format => 'pdf'
979 assert_response :success
979 assert_response :success
980 assert_equal 'application/pdf', response.content_type
980 assert_equal 'application/pdf', response.content_type
981 end
981 end
982
982
983 def test_index_with_parent_column
983 def test_index_with_parent_column
984 Issue.delete_all
984 Issue.delete_all
985 parent = Issue.generate!
985 parent = Issue.generate!
986 child = Issue.generate!(:parent_issue_id => parent.id)
986 child = Issue.generate!(:parent_issue_id => parent.id)
987
987
988 get :index, :c => %w(parent)
988 get :index, :c => %w(parent)
989
989
990 assert_select 'td.parent', :text => "#{parent.tracker} ##{parent.id}"
990 assert_select 'td.parent', :text => "#{parent.tracker} ##{parent.id}"
991 assert_select 'td.parent a[title=?]', parent.subject
991 assert_select 'td.parent a[title=?]', parent.subject
992 end
992 end
993
993
994 def test_index_with_estimated_hours_total
994 def test_index_with_estimated_hours_total
995 Issue.delete_all
995 Issue.delete_all
996 Issue.generate!(:estimated_hours => 5.5)
996 Issue.generate!(:estimated_hours => 5.5)
997 Issue.generate!(:estimated_hours => 1.1)
997 Issue.generate!(:estimated_hours => 1.1)
998
998
999 get :index, :t => %w(estimated_hours)
999 get :index, :t => %w(estimated_hours)
1000 assert_response :success
1000 assert_response :success
1001 assert_select '.query-totals'
1001 assert_select '.query-totals'
1002 assert_select '.total-for-estimated-hours span.value', :text => '6.60'
1002 assert_select '.total-for-estimated-hours span.value', :text => '6.60'
1003 assert_select 'input[type=checkbox][name=?][value=estimated_hours][checked=checked]', 't[]'
1003 assert_select 'input[type=checkbox][name=?][value=estimated_hours][checked=checked]', 't[]'
1004 end
1004 end
1005
1005
1006 def test_index_with_grouped_query_and_estimated_hours_total
1006 def test_index_with_grouped_query_and_estimated_hours_total
1007 Issue.delete_all
1007 Issue.delete_all
1008 Issue.generate!(:estimated_hours => 5.5, :category_id => 1)
1008 Issue.generate!(:estimated_hours => 5.5, :category_id => 1)
1009 Issue.generate!(:estimated_hours => 2.3, :category_id => 1)
1009 Issue.generate!(:estimated_hours => 2.3, :category_id => 1)
1010 Issue.generate!(:estimated_hours => 1.1, :category_id => 2)
1010 Issue.generate!(:estimated_hours => 1.1, :category_id => 2)
1011 Issue.generate!(:estimated_hours => 4.6)
1011 Issue.generate!(:estimated_hours => 4.6)
1012
1012
1013 get :index, :t => %w(estimated_hours), :group_by => 'category'
1013 get :index, :t => %w(estimated_hours), :group_by => 'category'
1014 assert_response :success
1014 assert_response :success
1015 assert_select '.query-totals'
1015 assert_select '.query-totals'
1016 assert_select '.query-totals .total-for-estimated-hours span.value', :text => '13.50'
1016 assert_select '.query-totals .total-for-estimated-hours span.value', :text => '13.50'
1017 assert_select 'tr.group', :text => /Printing/ do
1017 assert_select 'tr.group', :text => /Printing/ do
1018 assert_select '.total-for-estimated-hours span.value', :text => '7.80'
1018 assert_select '.total-for-estimated-hours span.value', :text => '7.80'
1019 end
1019 end
1020 assert_select 'tr.group', :text => /Recipes/ do
1020 assert_select 'tr.group', :text => /Recipes/ do
1021 assert_select '.total-for-estimated-hours span.value', :text => '1.10'
1021 assert_select '.total-for-estimated-hours span.value', :text => '1.10'
1022 end
1022 end
1023 assert_select 'tr.group', :text => /blank/ do
1023 assert_select 'tr.group', :text => /blank/ do
1024 assert_select '.total-for-estimated-hours span.value', :text => '4.60'
1024 assert_select '.total-for-estimated-hours span.value', :text => '4.60'
1025 end
1025 end
1026 end
1026 end
1027
1027
1028 def test_index_with_int_custom_field_total
1028 def test_index_with_int_custom_field_total
1029 field = IssueCustomField.generate!(:field_format => 'int', :is_for_all => true)
1029 field = IssueCustomField.generate!(:field_format => 'int', :is_for_all => true)
1030 CustomValue.create!(:customized => Issue.find(1), :custom_field => field, :value => '2')
1030 CustomValue.create!(:customized => Issue.find(1), :custom_field => field, :value => '2')
1031 CustomValue.create!(:customized => Issue.find(2), :custom_field => field, :value => '7')
1031 CustomValue.create!(:customized => Issue.find(2), :custom_field => field, :value => '7')
1032
1032
1033 get :index, :t => ["cf_#{field.id}"]
1033 get :index, :t => ["cf_#{field.id}"]
1034 assert_response :success
1034 assert_response :success
1035 assert_select '.query-totals'
1035 assert_select '.query-totals'
1036 assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
1036 assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
1037 end
1037 end
1038
1038
1039 def test_index_totals_should_default_to_settings
1039 def test_index_totals_should_default_to_settings
1040 with_settings :issue_list_default_totals => ['estimated_hours'] do
1040 with_settings :issue_list_default_totals => ['estimated_hours'] do
1041 get :index
1041 get :index
1042 assert_response :success
1042 assert_response :success
1043 assert_select '.total-for-estimated-hours span.value'
1043 assert_select '.total-for-estimated-hours span.value'
1044 assert_select '.query-totals>span', 1
1044 assert_select '.query-totals>span', 1
1045 end
1045 end
1046 end
1046 end
1047
1047
1048 def test_index_send_html_if_query_is_invalid
1048 def test_index_send_html_if_query_is_invalid
1049 get :index, :f => ['start_date'], :op => {:start_date => '='}
1049 get :index, :f => ['start_date'], :op => {:start_date => '='}
1050 assert_equal 'text/html', @response.content_type
1050 assert_equal 'text/html', @response.content_type
1051 assert_template 'index'
1051 assert_template 'index'
1052 end
1052 end
1053
1053
1054 def test_index_send_nothing_if_query_is_invalid
1054 def test_index_send_nothing_if_query_is_invalid
1055 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
1055 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
1056 assert_equal 'text/csv', @response.content_type
1056 assert_equal 'text/csv', @response.content_type
1057 assert @response.body.blank?
1057 assert @response.body.blank?
1058 end
1058 end
1059
1059
1060 def test_index_should_include_new_issue_link
1061 @request.session[:user_id] = 2
1062 get :index, :project_id => 1
1063 assert_select 'a.new-issue[href="/projects/ecookbook/issues/new"]', :text => 'New issue'
1064 end
1065
1066 def test_index_should_not_include_new_issue_link_for_project_without_trackers
1067 Project.find(1).trackers.clear
1068
1069 @request.session[:user_id] = 2
1070 get :index, :project_id => 1
1071 assert_select 'a.new-issue', 0
1072 end
1073
1074 def test_index_should_not_include_new_issue_link_for_users_with_copy_issues_permission_only
1075 role = Role.find(1)
1076 role.remove_permission! :add_issues
1077 role.add_permission! :copy_issues
1078
1079 @request.session[:user_id] = 2
1080 get :index, :project_id => 1
1081 assert_select 'a.new-issue', 0
1082 end
1083
1060 def test_show_by_anonymous
1084 def test_show_by_anonymous
1061 get :show, :id => 1
1085 get :show, :id => 1
1062 assert_response :success
1086 assert_response :success
1063 assert_template 'show'
1087 assert_template 'show'
1064 assert_equal Issue.find(1), assigns(:issue)
1088 assert_equal Issue.find(1), assigns(:issue)
1065 assert_select 'div.issue div.description', :text => /Unable to print recipes/
1089 assert_select 'div.issue div.description', :text => /Unable to print recipes/
1066 # anonymous role is allowed to add a note
1090 # anonymous role is allowed to add a note
1067 assert_select 'form#issue-form' do
1091 assert_select 'form#issue-form' do
1068 assert_select 'fieldset' do
1092 assert_select 'fieldset' do
1069 assert_select 'legend', :text => 'Notes'
1093 assert_select 'legend', :text => 'Notes'
1070 assert_select 'textarea[name=?]', 'issue[notes]'
1094 assert_select 'textarea[name=?]', 'issue[notes]'
1071 end
1095 end
1072 end
1096 end
1073 assert_select 'title', :text => "Bug #1: Cannot print recipes - eCookbook - Redmine"
1097 assert_select 'title', :text => "Bug #1: Cannot print recipes - eCookbook - Redmine"
1074 end
1098 end
1075
1099
1076 def test_show_by_manager
1100 def test_show_by_manager
1077 @request.session[:user_id] = 2
1101 @request.session[:user_id] = 2
1078 get :show, :id => 1
1102 get :show, :id => 1
1079 assert_response :success
1103 assert_response :success
1080 assert_select 'a', :text => /Quote/
1104 assert_select 'a', :text => /Quote/
1081 assert_select 'form#issue-form' do
1105 assert_select 'form#issue-form' do
1082 assert_select 'fieldset' do
1106 assert_select 'fieldset' do
1083 assert_select 'legend', :text => 'Change properties'
1107 assert_select 'legend', :text => 'Change properties'
1084 assert_select 'input[name=?]', 'issue[subject]'
1108 assert_select 'input[name=?]', 'issue[subject]'
1085 end
1109 end
1086 assert_select 'fieldset' do
1110 assert_select 'fieldset' do
1087 assert_select 'legend', :text => 'Log time'
1111 assert_select 'legend', :text => 'Log time'
1088 assert_select 'input[name=?]', 'time_entry[hours]'
1112 assert_select 'input[name=?]', 'time_entry[hours]'
1089 end
1113 end
1090 assert_select 'fieldset' do
1114 assert_select 'fieldset' do
1091 assert_select 'legend', :text => 'Notes'
1115 assert_select 'legend', :text => 'Notes'
1092 assert_select 'textarea[name=?]', 'issue[notes]'
1116 assert_select 'textarea[name=?]', 'issue[notes]'
1093 end
1117 end
1094 end
1118 end
1095 end
1119 end
1096
1120
1097 def test_show_should_display_update_form
1121 def test_show_should_display_update_form
1098 @request.session[:user_id] = 2
1122 @request.session[:user_id] = 2
1099 get :show, :id => 1
1123 get :show, :id => 1
1100 assert_response :success
1124 assert_response :success
1101
1125
1102 assert_select 'form#issue-form' do
1126 assert_select 'form#issue-form' do
1103 assert_select 'input[name=?]', 'issue[is_private]'
1127 assert_select 'input[name=?]', 'issue[is_private]'
1104 assert_select 'select[name=?]', 'issue[project_id]'
1128 assert_select 'select[name=?]', 'issue[project_id]'
1105 assert_select 'select[name=?]', 'issue[tracker_id]'
1129 assert_select 'select[name=?]', 'issue[tracker_id]'
1106 assert_select 'input[name=?]', 'issue[subject]'
1130 assert_select 'input[name=?]', 'issue[subject]'
1107 assert_select 'textarea[name=?]', 'issue[description]'
1131 assert_select 'textarea[name=?]', 'issue[description]'
1108 assert_select 'select[name=?]', 'issue[status_id]'
1132 assert_select 'select[name=?]', 'issue[status_id]'
1109 assert_select 'select[name=?]', 'issue[priority_id]'
1133 assert_select 'select[name=?]', 'issue[priority_id]'
1110 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1134 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1111 assert_select 'select[name=?]', 'issue[category_id]'
1135 assert_select 'select[name=?]', 'issue[category_id]'
1112 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1136 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1113 assert_select 'input[name=?]', 'issue[parent_issue_id]'
1137 assert_select 'input[name=?]', 'issue[parent_issue_id]'
1114 assert_select 'input[name=?]', 'issue[start_date]'
1138 assert_select 'input[name=?]', 'issue[start_date]'
1115 assert_select 'input[name=?]', 'issue[due_date]'
1139 assert_select 'input[name=?]', 'issue[due_date]'
1116 assert_select 'select[name=?]', 'issue[done_ratio]'
1140 assert_select 'select[name=?]', 'issue[done_ratio]'
1117 assert_select 'input[name=?]', 'issue[custom_field_values][2]'
1141 assert_select 'input[name=?]', 'issue[custom_field_values][2]'
1118 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1142 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1119 assert_select 'textarea[name=?]', 'issue[notes]'
1143 assert_select 'textarea[name=?]', 'issue[notes]'
1120 end
1144 end
1121 end
1145 end
1122
1146
1123 def test_show_should_display_update_form_with_minimal_permissions
1147 def test_show_should_display_update_form_with_minimal_permissions
1124 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
1148 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
1125 WorkflowTransition.delete_all :role_id => 1
1149 WorkflowTransition.delete_all :role_id => 1
1126
1150
1127 @request.session[:user_id] = 2
1151 @request.session[:user_id] = 2
1128 get :show, :id => 1
1152 get :show, :id => 1
1129 assert_response :success
1153 assert_response :success
1130
1154
1131 assert_select 'form#issue-form' do
1155 assert_select 'form#issue-form' do
1132 assert_select 'input[name=?]', 'issue[is_private]', 0
1156 assert_select 'input[name=?]', 'issue[is_private]', 0
1133 assert_select 'select[name=?]', 'issue[project_id]', 0
1157 assert_select 'select[name=?]', 'issue[project_id]', 0
1134 assert_select 'select[name=?]', 'issue[tracker_id]', 0
1158 assert_select 'select[name=?]', 'issue[tracker_id]', 0
1135 assert_select 'input[name=?]', 'issue[subject]', 0
1159 assert_select 'input[name=?]', 'issue[subject]', 0
1136 assert_select 'textarea[name=?]', 'issue[description]', 0
1160 assert_select 'textarea[name=?]', 'issue[description]', 0
1137 assert_select 'select[name=?]', 'issue[status_id]', 0
1161 assert_select 'select[name=?]', 'issue[status_id]', 0
1138 assert_select 'select[name=?]', 'issue[priority_id]', 0
1162 assert_select 'select[name=?]', 'issue[priority_id]', 0
1139 assert_select 'select[name=?]', 'issue[assigned_to_id]', 0
1163 assert_select 'select[name=?]', 'issue[assigned_to_id]', 0
1140 assert_select 'select[name=?]', 'issue[category_id]', 0
1164 assert_select 'select[name=?]', 'issue[category_id]', 0
1141 assert_select 'select[name=?]', 'issue[fixed_version_id]', 0
1165 assert_select 'select[name=?]', 'issue[fixed_version_id]', 0
1142 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
1166 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
1143 assert_select 'input[name=?]', 'issue[start_date]', 0
1167 assert_select 'input[name=?]', 'issue[start_date]', 0
1144 assert_select 'input[name=?]', 'issue[due_date]', 0
1168 assert_select 'input[name=?]', 'issue[due_date]', 0
1145 assert_select 'select[name=?]', 'issue[done_ratio]', 0
1169 assert_select 'select[name=?]', 'issue[done_ratio]', 0
1146 assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
1170 assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
1147 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1171 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1148 assert_select 'textarea[name=?]', 'issue[notes]'
1172 assert_select 'textarea[name=?]', 'issue[notes]'
1149 end
1173 end
1150 end
1174 end
1151
1175
1152 def test_show_should_not_display_update_form_without_permissions
1176 def test_show_should_not_display_update_form_without_permissions
1153 Role.find(1).update_attribute :permissions, [:view_issues]
1177 Role.find(1).update_attribute :permissions, [:view_issues]
1154
1178
1155 @request.session[:user_id] = 2
1179 @request.session[:user_id] = 2
1156 get :show, :id => 1
1180 get :show, :id => 1
1157 assert_response :success
1181 assert_response :success
1158
1182
1159 assert_select 'form#issue-form', 0
1183 assert_select 'form#issue-form', 0
1160 end
1184 end
1161
1185
1162 def test_update_form_should_not_display_inactive_enumerations
1186 def test_update_form_should_not_display_inactive_enumerations
1163 assert !IssuePriority.find(15).active?
1187 assert !IssuePriority.find(15).active?
1164
1188
1165 @request.session[:user_id] = 2
1189 @request.session[:user_id] = 2
1166 get :show, :id => 1
1190 get :show, :id => 1
1167 assert_response :success
1191 assert_response :success
1168
1192
1169 assert_select 'form#issue-form' do
1193 assert_select 'form#issue-form' do
1170 assert_select 'select[name=?]', 'issue[priority_id]' do
1194 assert_select 'select[name=?]', 'issue[priority_id]' do
1171 assert_select 'option[value="4"]'
1195 assert_select 'option[value="4"]'
1172 assert_select 'option[value="15"]', 0
1196 assert_select 'option[value="15"]', 0
1173 end
1197 end
1174 end
1198 end
1175 end
1199 end
1176
1200
1177 def test_update_form_should_allow_attachment_upload
1201 def test_update_form_should_allow_attachment_upload
1178 @request.session[:user_id] = 2
1202 @request.session[:user_id] = 2
1179 get :show, :id => 1
1203 get :show, :id => 1
1180
1204
1181 assert_select 'form#issue-form[method=post][enctype="multipart/form-data"]' do
1205 assert_select 'form#issue-form[method=post][enctype="multipart/form-data"]' do
1182 assert_select 'input[type=file][name=?]', 'attachments[dummy][file]'
1206 assert_select 'input[type=file][name=?]', 'attachments[dummy][file]'
1183 end
1207 end
1184 end
1208 end
1185
1209
1186 def test_show_should_deny_anonymous_access_without_permission
1210 def test_show_should_deny_anonymous_access_without_permission
1187 Role.anonymous.remove_permission!(:view_issues)
1211 Role.anonymous.remove_permission!(:view_issues)
1188 get :show, :id => 1
1212 get :show, :id => 1
1189 assert_response :redirect
1213 assert_response :redirect
1190 end
1214 end
1191
1215
1192 def test_show_should_deny_anonymous_access_to_private_issue
1216 def test_show_should_deny_anonymous_access_to_private_issue
1193 Issue.where(:id => 1).update_all(["is_private = ?", true])
1217 Issue.where(:id => 1).update_all(["is_private = ?", true])
1194 get :show, :id => 1
1218 get :show, :id => 1
1195 assert_response :redirect
1219 assert_response :redirect
1196 end
1220 end
1197
1221
1198 def test_show_should_deny_non_member_access_without_permission
1222 def test_show_should_deny_non_member_access_without_permission
1199 Role.non_member.remove_permission!(:view_issues)
1223 Role.non_member.remove_permission!(:view_issues)
1200 @request.session[:user_id] = 9
1224 @request.session[:user_id] = 9
1201 get :show, :id => 1
1225 get :show, :id => 1
1202 assert_response 403
1226 assert_response 403
1203 end
1227 end
1204
1228
1205 def test_show_should_deny_non_member_access_to_private_issue
1229 def test_show_should_deny_non_member_access_to_private_issue
1206 Issue.where(:id => 1).update_all(["is_private = ?", true])
1230 Issue.where(:id => 1).update_all(["is_private = ?", true])
1207 @request.session[:user_id] = 9
1231 @request.session[:user_id] = 9
1208 get :show, :id => 1
1232 get :show, :id => 1
1209 assert_response 403
1233 assert_response 403
1210 end
1234 end
1211
1235
1212 def test_show_should_deny_member_access_without_permission
1236 def test_show_should_deny_member_access_without_permission
1213 Role.find(1).remove_permission!(:view_issues)
1237 Role.find(1).remove_permission!(:view_issues)
1214 @request.session[:user_id] = 2
1238 @request.session[:user_id] = 2
1215 get :show, :id => 1
1239 get :show, :id => 1
1216 assert_response 403
1240 assert_response 403
1217 end
1241 end
1218
1242
1219 def test_show_should_deny_member_access_to_private_issue_without_permission
1243 def test_show_should_deny_member_access_to_private_issue_without_permission
1220 Issue.where(:id => 1).update_all(["is_private = ?", true])
1244 Issue.where(:id => 1).update_all(["is_private = ?", true])
1221 @request.session[:user_id] = 3
1245 @request.session[:user_id] = 3
1222 get :show, :id => 1
1246 get :show, :id => 1
1223 assert_response 403
1247 assert_response 403
1224 end
1248 end
1225
1249
1226 def test_show_should_allow_author_access_to_private_issue
1250 def test_show_should_allow_author_access_to_private_issue
1227 Issue.where(:id => 1).update_all(["is_private = ?, author_id = 3", true])
1251 Issue.where(:id => 1).update_all(["is_private = ?, author_id = 3", true])
1228 @request.session[:user_id] = 3
1252 @request.session[:user_id] = 3
1229 get :show, :id => 1
1253 get :show, :id => 1
1230 assert_response :success
1254 assert_response :success
1231 end
1255 end
1232
1256
1233 def test_show_should_allow_assignee_access_to_private_issue
1257 def test_show_should_allow_assignee_access_to_private_issue
1234 Issue.where(:id => 1).update_all(["is_private = ?, assigned_to_id = 3", true])
1258 Issue.where(:id => 1).update_all(["is_private = ?, assigned_to_id = 3", true])
1235 @request.session[:user_id] = 3
1259 @request.session[:user_id] = 3
1236 get :show, :id => 1
1260 get :show, :id => 1
1237 assert_response :success
1261 assert_response :success
1238 end
1262 end
1239
1263
1240 def test_show_should_allow_member_access_to_private_issue_with_permission
1264 def test_show_should_allow_member_access_to_private_issue_with_permission
1241 Issue.where(:id => 1).update_all(["is_private = ?", true])
1265 Issue.where(:id => 1).update_all(["is_private = ?", true])
1242 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
1266 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
1243 @request.session[:user_id] = 3
1267 @request.session[:user_id] = 3
1244 get :show, :id => 1
1268 get :show, :id => 1
1245 assert_response :success
1269 assert_response :success
1246 end
1270 end
1247
1271
1248 def test_show_should_not_disclose_relations_to_invisible_issues
1272 def test_show_should_not_disclose_relations_to_invisible_issues
1249 Setting.cross_project_issue_relations = '1'
1273 Setting.cross_project_issue_relations = '1'
1250 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
1274 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
1251 # Relation to a private project issue
1275 # Relation to a private project issue
1252 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
1276 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
1253
1277
1254 get :show, :id => 1
1278 get :show, :id => 1
1255 assert_response :success
1279 assert_response :success
1256
1280
1257 assert_select 'div#relations' do
1281 assert_select 'div#relations' do
1258 assert_select 'a', :text => /#2$/
1282 assert_select 'a', :text => /#2$/
1259 assert_select 'a', :text => /#4$/, :count => 0
1283 assert_select 'a', :text => /#4$/, :count => 0
1260 end
1284 end
1261 end
1285 end
1262
1286
1263 def test_show_should_list_subtasks
1287 def test_show_should_list_subtasks
1264 Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1288 Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1265
1289
1266 get :show, :id => 1
1290 get :show, :id => 1
1267 assert_response :success
1291 assert_response :success
1268
1292
1269 assert_select 'div#issue_tree' do
1293 assert_select 'div#issue_tree' do
1270 assert_select 'td.subject', :text => /Child Issue/
1294 assert_select 'td.subject', :text => /Child Issue/
1271 end
1295 end
1272 end
1296 end
1273
1297
1274 def test_show_should_list_parents
1298 def test_show_should_list_parents
1275 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1299 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1276
1300
1277 get :show, :id => issue.id
1301 get :show, :id => issue.id
1278 assert_response :success
1302 assert_response :success
1279
1303
1280 assert_select 'div.subject' do
1304 assert_select 'div.subject' do
1281 assert_select 'h3', 'Child Issue'
1305 assert_select 'h3', 'Child Issue'
1282 assert_select 'a[href="/issues/1"]'
1306 assert_select 'a[href="/issues/1"]'
1283 end
1307 end
1284 end
1308 end
1285
1309
1286 def test_show_should_not_display_prev_next_links_without_query_in_session
1310 def test_show_should_not_display_prev_next_links_without_query_in_session
1287 get :show, :id => 1
1311 get :show, :id => 1
1288 assert_response :success
1312 assert_response :success
1289 assert_nil assigns(:prev_issue_id)
1313 assert_nil assigns(:prev_issue_id)
1290 assert_nil assigns(:next_issue_id)
1314 assert_nil assigns(:next_issue_id)
1291
1315
1292 assert_select 'div.next-prev-links', 0
1316 assert_select 'div.next-prev-links', 0
1293 end
1317 end
1294
1318
1295 def test_show_should_display_prev_next_links_with_query_in_session
1319 def test_show_should_display_prev_next_links_with_query_in_session
1296 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1320 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1297 @request.session['issues_index_sort'] = 'id'
1321 @request.session['issues_index_sort'] = 'id'
1298
1322
1299 with_settings :display_subprojects_issues => '0' do
1323 with_settings :display_subprojects_issues => '0' do
1300 get :show, :id => 3
1324 get :show, :id => 3
1301 end
1325 end
1302
1326
1303 assert_response :success
1327 assert_response :success
1304 # Previous and next issues for all projects
1328 # Previous and next issues for all projects
1305 assert_equal 2, assigns(:prev_issue_id)
1329 assert_equal 2, assigns(:prev_issue_id)
1306 assert_equal 5, assigns(:next_issue_id)
1330 assert_equal 5, assigns(:next_issue_id)
1307
1331
1308 count = Issue.open.visible.count
1332 count = Issue.open.visible.count
1309
1333
1310 assert_select 'div.next-prev-links' do
1334 assert_select 'div.next-prev-links' do
1311 assert_select 'a[href="/issues/2"]', :text => /Previous/
1335 assert_select 'a[href="/issues/2"]', :text => /Previous/
1312 assert_select 'a[href="/issues/5"]', :text => /Next/
1336 assert_select 'a[href="/issues/5"]', :text => /Next/
1313 assert_select 'span.position', :text => "3 of #{count}"
1337 assert_select 'span.position', :text => "3 of #{count}"
1314 end
1338 end
1315 end
1339 end
1316
1340
1317 def test_show_should_display_prev_next_links_with_saved_query_in_session
1341 def test_show_should_display_prev_next_links_with_saved_query_in_session
1318 query = IssueQuery.create!(:name => 'test', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user_id => 1,
1342 query = IssueQuery.create!(:name => 'test', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user_id => 1,
1319 :filters => {'status_id' => {:values => ['5'], :operator => '='}},
1343 :filters => {'status_id' => {:values => ['5'], :operator => '='}},
1320 :sort_criteria => [['id', 'asc']])
1344 :sort_criteria => [['id', 'asc']])
1321 @request.session[:query] = {:id => query.id, :project_id => nil}
1345 @request.session[:query] = {:id => query.id, :project_id => nil}
1322
1346
1323 get :show, :id => 11
1347 get :show, :id => 11
1324
1348
1325 assert_response :success
1349 assert_response :success
1326 assert_equal query, assigns(:query)
1350 assert_equal query, assigns(:query)
1327 # Previous and next issues for all projects
1351 # Previous and next issues for all projects
1328 assert_equal 8, assigns(:prev_issue_id)
1352 assert_equal 8, assigns(:prev_issue_id)
1329 assert_equal 12, assigns(:next_issue_id)
1353 assert_equal 12, assigns(:next_issue_id)
1330
1354
1331 assert_select 'div.next-prev-links' do
1355 assert_select 'div.next-prev-links' do
1332 assert_select 'a[href="/issues/8"]', :text => /Previous/
1356 assert_select 'a[href="/issues/8"]', :text => /Previous/
1333 assert_select 'a[href="/issues/12"]', :text => /Next/
1357 assert_select 'a[href="/issues/12"]', :text => /Next/
1334 end
1358 end
1335 end
1359 end
1336
1360
1337 def test_show_should_display_prev_next_links_with_query_and_sort_on_association
1361 def test_show_should_display_prev_next_links_with_query_and_sort_on_association
1338 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1362 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1339
1363
1340 %w(project tracker status priority author assigned_to category fixed_version).each do |assoc_sort|
1364 %w(project tracker status priority author assigned_to category fixed_version).each do |assoc_sort|
1341 @request.session['issues_index_sort'] = assoc_sort
1365 @request.session['issues_index_sort'] = assoc_sort
1342
1366
1343 get :show, :id => 3
1367 get :show, :id => 3
1344 assert_response :success, "Wrong response status for #{assoc_sort} sort"
1368 assert_response :success, "Wrong response status for #{assoc_sort} sort"
1345
1369
1346 assert_select 'div.next-prev-links' do
1370 assert_select 'div.next-prev-links' do
1347 assert_select 'a', :text => /(Previous|Next)/
1371 assert_select 'a', :text => /(Previous|Next)/
1348 end
1372 end
1349 end
1373 end
1350 end
1374 end
1351
1375
1352 def test_show_should_display_prev_next_links_with_project_query_in_session
1376 def test_show_should_display_prev_next_links_with_project_query_in_session
1353 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1377 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1354 @request.session['issues_index_sort'] = 'id'
1378 @request.session['issues_index_sort'] = 'id'
1355
1379
1356 with_settings :display_subprojects_issues => '0' do
1380 with_settings :display_subprojects_issues => '0' do
1357 get :show, :id => 3
1381 get :show, :id => 3
1358 end
1382 end
1359
1383
1360 assert_response :success
1384 assert_response :success
1361 # Previous and next issues inside project
1385 # Previous and next issues inside project
1362 assert_equal 2, assigns(:prev_issue_id)
1386 assert_equal 2, assigns(:prev_issue_id)
1363 assert_equal 7, assigns(:next_issue_id)
1387 assert_equal 7, assigns(:next_issue_id)
1364
1388
1365 assert_select 'div.next-prev-links' do
1389 assert_select 'div.next-prev-links' do
1366 assert_select 'a[href="/issues/2"]', :text => /Previous/
1390 assert_select 'a[href="/issues/2"]', :text => /Previous/
1367 assert_select 'a[href="/issues/7"]', :text => /Next/
1391 assert_select 'a[href="/issues/7"]', :text => /Next/
1368 end
1392 end
1369 end
1393 end
1370
1394
1371 def test_show_should_not_display_prev_link_for_first_issue
1395 def test_show_should_not_display_prev_link_for_first_issue
1372 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1396 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1373 @request.session['issues_index_sort'] = 'id'
1397 @request.session['issues_index_sort'] = 'id'
1374
1398
1375 with_settings :display_subprojects_issues => '0' do
1399 with_settings :display_subprojects_issues => '0' do
1376 get :show, :id => 1
1400 get :show, :id => 1
1377 end
1401 end
1378
1402
1379 assert_response :success
1403 assert_response :success
1380 assert_nil assigns(:prev_issue_id)
1404 assert_nil assigns(:prev_issue_id)
1381 assert_equal 2, assigns(:next_issue_id)
1405 assert_equal 2, assigns(:next_issue_id)
1382
1406
1383 assert_select 'div.next-prev-links' do
1407 assert_select 'div.next-prev-links' do
1384 assert_select 'a', :text => /Previous/, :count => 0
1408 assert_select 'a', :text => /Previous/, :count => 0
1385 assert_select 'a[href="/issues/2"]', :text => /Next/
1409 assert_select 'a[href="/issues/2"]', :text => /Next/
1386 end
1410 end
1387 end
1411 end
1388
1412
1389 def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
1413 def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
1390 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'c'}}, :project_id => 1}
1414 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'c'}}, :project_id => 1}
1391 @request.session['issues_index_sort'] = 'id'
1415 @request.session['issues_index_sort'] = 'id'
1392
1416
1393 get :show, :id => 1
1417 get :show, :id => 1
1394
1418
1395 assert_response :success
1419 assert_response :success
1396 assert_nil assigns(:prev_issue_id)
1420 assert_nil assigns(:prev_issue_id)
1397 assert_nil assigns(:next_issue_id)
1421 assert_nil assigns(:next_issue_id)
1398
1422
1399 assert_select 'a', :text => /Previous/, :count => 0
1423 assert_select 'a', :text => /Previous/, :count => 0
1400 assert_select 'a', :text => /Next/, :count => 0
1424 assert_select 'a', :text => /Next/, :count => 0
1401 end
1425 end
1402
1426
1403 def test_show_show_should_display_prev_next_links_with_query_sort_by_user_custom_field
1427 def test_show_show_should_display_prev_next_links_with_query_sort_by_user_custom_field
1404 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
1428 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
1405 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
1429 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
1406 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
1430 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
1407 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
1431 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
1408 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
1432 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
1409
1433
1410 query = IssueQuery.create!(:name => 'test', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user_id => 1, :filters => {},
1434 query = IssueQuery.create!(:name => 'test', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user_id => 1, :filters => {},
1411 :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']])
1435 :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']])
1412 @request.session[:query] = {:id => query.id, :project_id => nil}
1436 @request.session[:query] = {:id => query.id, :project_id => nil}
1413
1437
1414 get :show, :id => 3
1438 get :show, :id => 3
1415 assert_response :success
1439 assert_response :success
1416
1440
1417 assert_equal 2, assigns(:prev_issue_id)
1441 assert_equal 2, assigns(:prev_issue_id)
1418 assert_equal 1, assigns(:next_issue_id)
1442 assert_equal 1, assigns(:next_issue_id)
1419
1443
1420 assert_select 'div.next-prev-links' do
1444 assert_select 'div.next-prev-links' do
1421 assert_select 'a[href="/issues/2"]', :text => /Previous/
1445 assert_select 'a[href="/issues/2"]', :text => /Previous/
1422 assert_select 'a[href="/issues/1"]', :text => /Next/
1446 assert_select 'a[href="/issues/1"]', :text => /Next/
1423 end
1447 end
1424 end
1448 end
1425
1449
1426 def test_show_should_display_prev_next_links_when_request_has_previous_and_next_issue_ids_params
1450 def test_show_should_display_prev_next_links_when_request_has_previous_and_next_issue_ids_params
1427 get :show, :id => 1, :prev_issue_id => 1, :next_issue_id => 3, :issue_position => 2, :issue_count => 4
1451 get :show, :id => 1, :prev_issue_id => 1, :next_issue_id => 3, :issue_position => 2, :issue_count => 4
1428 assert_response :success
1452 assert_response :success
1429
1453
1430 assert_select 'div.next-prev-links' do
1454 assert_select 'div.next-prev-links' do
1431 assert_select 'a[href="/issues/1"]', :text => /Previous/
1455 assert_select 'a[href="/issues/1"]', :text => /Previous/
1432 assert_select 'a[href="/issues/3"]', :text => /Next/
1456 assert_select 'a[href="/issues/3"]', :text => /Next/
1433 assert_select 'span.position', :text => "2 of 4"
1457 assert_select 'span.position', :text => "2 of 4"
1434 end
1458 end
1435 end
1459 end
1436
1460
1437 def test_show_should_display_category_field_if_categories_are_defined
1461 def test_show_should_display_category_field_if_categories_are_defined
1438 Issue.update_all :category_id => nil
1462 Issue.update_all :category_id => nil
1439
1463
1440 get :show, :id => 1
1464 get :show, :id => 1
1441 assert_response :success
1465 assert_response :success
1442 assert_select '.attributes .category'
1466 assert_select '.attributes .category'
1443 end
1467 end
1444
1468
1445 def test_show_should_not_display_category_field_if_no_categories_are_defined
1469 def test_show_should_not_display_category_field_if_no_categories_are_defined
1446 Project.find(1).issue_categories.delete_all
1470 Project.find(1).issue_categories.delete_all
1447
1471
1448 get :show, :id => 1
1472 get :show, :id => 1
1449 assert_response :success
1473 assert_response :success
1450 assert_select 'table.attributes .category', 0
1474 assert_select 'table.attributes .category', 0
1451 end
1475 end
1452
1476
1453 def test_show_should_display_link_to_the_assignee
1477 def test_show_should_display_link_to_the_assignee
1454 get :show, :id => 2
1478 get :show, :id => 2
1455 assert_response :success
1479 assert_response :success
1456 assert_select '.assigned-to' do
1480 assert_select '.assigned-to' do
1457 assert_select 'a[href="/users/3"]'
1481 assert_select 'a[href="/users/3"]'
1458 end
1482 end
1459 end
1483 end
1460
1484
1461 def test_show_should_display_visible_changesets_from_other_projects
1485 def test_show_should_display_visible_changesets_from_other_projects
1462 project = Project.find(2)
1486 project = Project.find(2)
1463 issue = project.issues.first
1487 issue = project.issues.first
1464 issue.changeset_ids = [102]
1488 issue.changeset_ids = [102]
1465 issue.save!
1489 issue.save!
1466 # changesets from other projects should be displayed even if repository
1490 # changesets from other projects should be displayed even if repository
1467 # is disabled on issue's project
1491 # is disabled on issue's project
1468 project.disable_module! :repository
1492 project.disable_module! :repository
1469
1493
1470 @request.session[:user_id] = 2
1494 @request.session[:user_id] = 2
1471 get :show, :id => issue.id
1495 get :show, :id => issue.id
1472
1496
1473 assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/3'
1497 assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/3'
1474 end
1498 end
1475
1499
1476 def test_show_should_display_watchers
1500 def test_show_should_display_watchers
1477 @request.session[:user_id] = 2
1501 @request.session[:user_id] = 2
1478 Issue.find(1).add_watcher User.find(2)
1502 Issue.find(1).add_watcher User.find(2)
1479
1503
1480 get :show, :id => 1
1504 get :show, :id => 1
1481 assert_select 'div#watchers ul' do
1505 assert_select 'div#watchers ul' do
1482 assert_select 'li' do
1506 assert_select 'li' do
1483 assert_select 'a[href="/users/2"]'
1507 assert_select 'a[href="/users/2"]'
1484 assert_select 'a[class*=delete]'
1508 assert_select 'a[class*=delete]'
1485 end
1509 end
1486 end
1510 end
1487 end
1511 end
1488
1512
1489 def test_show_should_display_watchers_with_gravatars
1513 def test_show_should_display_watchers_with_gravatars
1490 @request.session[:user_id] = 2
1514 @request.session[:user_id] = 2
1491 Issue.find(1).add_watcher User.find(2)
1515 Issue.find(1).add_watcher User.find(2)
1492
1516
1493 with_settings :gravatar_enabled => '1' do
1517 with_settings :gravatar_enabled => '1' do
1494 get :show, :id => 1
1518 get :show, :id => 1
1495 end
1519 end
1496
1520
1497 assert_select 'div#watchers ul' do
1521 assert_select 'div#watchers ul' do
1498 assert_select 'li' do
1522 assert_select 'li' do
1499 assert_select 'img.gravatar'
1523 assert_select 'img.gravatar'
1500 assert_select 'a[href="/users/2"]'
1524 assert_select 'a[href="/users/2"]'
1501 assert_select 'a[class*=delete]'
1525 assert_select 'a[class*=delete]'
1502 end
1526 end
1503 end
1527 end
1504 end
1528 end
1505
1529
1506 def test_show_with_thumbnails_enabled_should_display_thumbnails
1530 def test_show_with_thumbnails_enabled_should_display_thumbnails
1507 @request.session[:user_id] = 2
1531 @request.session[:user_id] = 2
1508
1532
1509 with_settings :thumbnails_enabled => '1' do
1533 with_settings :thumbnails_enabled => '1' do
1510 get :show, :id => 14
1534 get :show, :id => 14
1511 assert_response :success
1535 assert_response :success
1512 end
1536 end
1513
1537
1514 assert_select 'div.thumbnails' do
1538 assert_select 'div.thumbnails' do
1515 assert_select 'a[href="/attachments/16/testfile.png"]' do
1539 assert_select 'a[href="/attachments/16/testfile.png"]' do
1516 assert_select 'img[src="/attachments/thumbnail/16"]'
1540 assert_select 'img[src="/attachments/thumbnail/16"]'
1517 end
1541 end
1518 end
1542 end
1519 end
1543 end
1520
1544
1521 def test_show_with_thumbnails_disabled_should_not_display_thumbnails
1545 def test_show_with_thumbnails_disabled_should_not_display_thumbnails
1522 @request.session[:user_id] = 2
1546 @request.session[:user_id] = 2
1523
1547
1524 with_settings :thumbnails_enabled => '0' do
1548 with_settings :thumbnails_enabled => '0' do
1525 get :show, :id => 14
1549 get :show, :id => 14
1526 assert_response :success
1550 assert_response :success
1527 end
1551 end
1528
1552
1529 assert_select 'div.thumbnails', 0
1553 assert_select 'div.thumbnails', 0
1530 end
1554 end
1531
1555
1532 def test_show_with_multi_custom_field
1556 def test_show_with_multi_custom_field
1533 field = CustomField.find(1)
1557 field = CustomField.find(1)
1534 field.update_attribute :multiple, true
1558 field.update_attribute :multiple, true
1535 issue = Issue.find(1)
1559 issue = Issue.find(1)
1536 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
1560 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
1537 issue.save!
1561 issue.save!
1538
1562
1539 get :show, :id => 1
1563 get :show, :id => 1
1540 assert_response :success
1564 assert_response :success
1541
1565
1542 assert_select ".cf_1 .value", :text => 'MySQL, Oracle'
1566 assert_select ".cf_1 .value", :text => 'MySQL, Oracle'
1543 end
1567 end
1544
1568
1545 def test_show_with_multi_user_custom_field
1569 def test_show_with_multi_user_custom_field
1546 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1570 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1547 :tracker_ids => [1], :is_for_all => true)
1571 :tracker_ids => [1], :is_for_all => true)
1548 issue = Issue.find(1)
1572 issue = Issue.find(1)
1549 issue.custom_field_values = {field.id => ['2', '3']}
1573 issue.custom_field_values = {field.id => ['2', '3']}
1550 issue.save!
1574 issue.save!
1551
1575
1552 get :show, :id => 1
1576 get :show, :id => 1
1553 assert_response :success
1577 assert_response :success
1554
1578
1555 assert_select ".cf_#{field.id} .value", :text => 'Dave Lopper, John Smith' do
1579 assert_select ".cf_#{field.id} .value", :text => 'Dave Lopper, John Smith' do
1556 assert_select 'a', :text => 'Dave Lopper'
1580 assert_select 'a', :text => 'Dave Lopper'
1557 assert_select 'a', :text => 'John Smith'
1581 assert_select 'a', :text => 'John Smith'
1558 end
1582 end
1559 end
1583 end
1560
1584
1561 def test_show_should_display_private_notes_with_permission_only
1585 def test_show_should_display_private_notes_with_permission_only
1562 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
1586 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
1563 @request.session[:user_id] = 2
1587 @request.session[:user_id] = 2
1564
1588
1565 get :show, :id => 2
1589 get :show, :id => 2
1566 assert_response :success
1590 assert_response :success
1567 assert_include journal, assigns(:journals)
1591 assert_include journal, assigns(:journals)
1568
1592
1569 Role.find(1).remove_permission! :view_private_notes
1593 Role.find(1).remove_permission! :view_private_notes
1570 get :show, :id => 2
1594 get :show, :id => 2
1571 assert_response :success
1595 assert_response :success
1572 assert_not_include journal, assigns(:journals)
1596 assert_not_include journal, assigns(:journals)
1573 end
1597 end
1574
1598
1575 def test_show_atom
1599 def test_show_atom
1576 get :show, :id => 2, :format => 'atom'
1600 get :show, :id => 2, :format => 'atom'
1577 assert_response :success
1601 assert_response :success
1578 assert_template 'journals/index'
1602 assert_template 'journals/index'
1579 # Inline image
1603 # Inline image
1580 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
1604 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
1581 end
1605 end
1582
1606
1583 def test_show_export_to_pdf
1607 def test_show_export_to_pdf
1584 issue = Issue.find(3)
1608 issue = Issue.find(3)
1585 assert issue.relations.select{|r| r.other_issue(issue).visible?}.present?
1609 assert issue.relations.select{|r| r.other_issue(issue).visible?}.present?
1586 get :show, :id => 3, :format => 'pdf'
1610 get :show, :id => 3, :format => 'pdf'
1587 assert_response :success
1611 assert_response :success
1588 assert_equal 'application/pdf', @response.content_type
1612 assert_equal 'application/pdf', @response.content_type
1589 assert @response.body.starts_with?('%PDF')
1613 assert @response.body.starts_with?('%PDF')
1590 assert_not_nil assigns(:issue)
1614 assert_not_nil assigns(:issue)
1591 end
1615 end
1592
1616
1593 def test_export_to_pdf_with_utf8_u_fffd
1617 def test_export_to_pdf_with_utf8_u_fffd
1594 # U+FFFD
1618 # U+FFFD
1595 s = "\xef\xbf\xbd"
1619 s = "\xef\xbf\xbd"
1596 s.force_encoding('UTF-8') if s.respond_to?(:force_encoding)
1620 s.force_encoding('UTF-8') if s.respond_to?(:force_encoding)
1597 issue = Issue.generate!(:subject => s)
1621 issue = Issue.generate!(:subject => s)
1598 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
1622 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
1599 with_settings :default_language => lang do
1623 with_settings :default_language => lang do
1600 get :show, :id => issue.id, :format => 'pdf'
1624 get :show, :id => issue.id, :format => 'pdf'
1601 assert_response :success
1625 assert_response :success
1602 assert_equal 'application/pdf', @response.content_type
1626 assert_equal 'application/pdf', @response.content_type
1603 assert @response.body.starts_with?('%PDF')
1627 assert @response.body.starts_with?('%PDF')
1604 assert_not_nil assigns(:issue)
1628 assert_not_nil assigns(:issue)
1605 end
1629 end
1606 end
1630 end
1607 end
1631 end
1608
1632
1609 def test_show_export_to_pdf_with_ancestors
1633 def test_show_export_to_pdf_with_ancestors
1610 issue = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1634 issue = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1611
1635
1612 get :show, :id => issue.id, :format => 'pdf'
1636 get :show, :id => issue.id, :format => 'pdf'
1613 assert_response :success
1637 assert_response :success
1614 assert_equal 'application/pdf', @response.content_type
1638 assert_equal 'application/pdf', @response.content_type
1615 assert @response.body.starts_with?('%PDF')
1639 assert @response.body.starts_with?('%PDF')
1616 end
1640 end
1617
1641
1618 def test_show_export_to_pdf_with_descendants
1642 def test_show_export_to_pdf_with_descendants
1619 c1 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1643 c1 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1620 c2 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1644 c2 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1621 c3 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => c1.id)
1645 c3 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => c1.id)
1622
1646
1623 get :show, :id => 1, :format => 'pdf'
1647 get :show, :id => 1, :format => 'pdf'
1624 assert_response :success
1648 assert_response :success
1625 assert_equal 'application/pdf', @response.content_type
1649 assert_equal 'application/pdf', @response.content_type
1626 assert @response.body.starts_with?('%PDF')
1650 assert @response.body.starts_with?('%PDF')
1627 end
1651 end
1628
1652
1629 def test_show_export_to_pdf_with_journals
1653 def test_show_export_to_pdf_with_journals
1630 get :show, :id => 1, :format => 'pdf'
1654 get :show, :id => 1, :format => 'pdf'
1631 assert_response :success
1655 assert_response :success
1632 assert_equal 'application/pdf', @response.content_type
1656 assert_equal 'application/pdf', @response.content_type
1633 assert @response.body.starts_with?('%PDF')
1657 assert @response.body.starts_with?('%PDF')
1634 end
1658 end
1635
1659
1636 def test_show_export_to_pdf_with_changesets
1660 def test_show_export_to_pdf_with_changesets
1637 [[100], [100, 101], [100, 101, 102]].each do |cs|
1661 [[100], [100, 101], [100, 101, 102]].each do |cs|
1638 issue1 = Issue.find(3)
1662 issue1 = Issue.find(3)
1639 issue1.changesets = Changeset.find(cs)
1663 issue1.changesets = Changeset.find(cs)
1640 issue1.save!
1664 issue1.save!
1641 issue = Issue.find(3)
1665 issue = Issue.find(3)
1642 assert_equal issue.changesets.count, cs.size
1666 assert_equal issue.changesets.count, cs.size
1643 get :show, :id => 3, :format => 'pdf'
1667 get :show, :id => 3, :format => 'pdf'
1644 assert_response :success
1668 assert_response :success
1645 assert_equal 'application/pdf', @response.content_type
1669 assert_equal 'application/pdf', @response.content_type
1646 assert @response.body.starts_with?('%PDF')
1670 assert @response.body.starts_with?('%PDF')
1647 end
1671 end
1648 end
1672 end
1649
1673
1650 def test_show_invalid_should_respond_with_404
1674 def test_show_invalid_should_respond_with_404
1651 get :show, :id => 999
1675 get :show, :id => 999
1652 assert_response 404
1676 assert_response 404
1653 end
1677 end
1654
1678
1655 def test_get_new
1679 def test_get_new
1656 @request.session[:user_id] = 2
1680 @request.session[:user_id] = 2
1657 get :new, :project_id => 1, :tracker_id => 1
1681 get :new, :project_id => 1, :tracker_id => 1
1658 assert_response :success
1682 assert_response :success
1659 assert_template 'new'
1683 assert_template 'new'
1660
1684
1661 assert_select 'form#issue-form[action=?]', '/projects/ecookbook/issues'
1685 assert_select 'form#issue-form[action=?]', '/projects/ecookbook/issues'
1662 assert_select 'form#issue-form' do
1686 assert_select 'form#issue-form' do
1663 assert_select 'input[name=?]', 'issue[is_private]'
1687 assert_select 'input[name=?]', 'issue[is_private]'
1664 assert_select 'select[name=?]', 'issue[project_id]', 0
1688 assert_select 'select[name=?]', 'issue[project_id]', 0
1665 assert_select 'select[name=?]', 'issue[tracker_id]'
1689 assert_select 'select[name=?]', 'issue[tracker_id]'
1666 assert_select 'input[name=?]', 'issue[subject]'
1690 assert_select 'input[name=?]', 'issue[subject]'
1667 assert_select 'textarea[name=?]', 'issue[description]'
1691 assert_select 'textarea[name=?]', 'issue[description]'
1668 assert_select 'select[name=?]', 'issue[status_id]'
1692 assert_select 'select[name=?]', 'issue[status_id]'
1669 assert_select 'select[name=?]', 'issue[priority_id]'
1693 assert_select 'select[name=?]', 'issue[priority_id]'
1670 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1694 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1671 assert_select 'select[name=?]', 'issue[category_id]'
1695 assert_select 'select[name=?]', 'issue[category_id]'
1672 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1696 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1673 assert_select 'input[name=?]', 'issue[parent_issue_id]'
1697 assert_select 'input[name=?]', 'issue[parent_issue_id]'
1674 assert_select 'input[name=?]', 'issue[start_date]'
1698 assert_select 'input[name=?]', 'issue[start_date]'
1675 assert_select 'input[name=?]', 'issue[due_date]'
1699 assert_select 'input[name=?]', 'issue[due_date]'
1676 assert_select 'select[name=?]', 'issue[done_ratio]'
1700 assert_select 'select[name=?]', 'issue[done_ratio]'
1677 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1701 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1678 assert_select 'input[name=?]', 'issue[watcher_user_ids][]'
1702 assert_select 'input[name=?]', 'issue[watcher_user_ids][]'
1679 end
1703 end
1680
1704
1681 # Be sure we don't display inactive IssuePriorities
1705 # Be sure we don't display inactive IssuePriorities
1682 assert ! IssuePriority.find(15).active?
1706 assert ! IssuePriority.find(15).active?
1683 assert_select 'select[name=?]', 'issue[priority_id]' do
1707 assert_select 'select[name=?]', 'issue[priority_id]' do
1684 assert_select 'option[value="15"]', 0
1708 assert_select 'option[value="15"]', 0
1685 end
1709 end
1686 end
1710 end
1687
1711
1688 def test_get_new_with_minimal_permissions
1712 def test_get_new_with_minimal_permissions
1689 Role.find(1).update_attribute :permissions, [:add_issues]
1713 Role.find(1).update_attribute :permissions, [:add_issues]
1690 WorkflowTransition.delete_all :role_id => 1
1714 WorkflowTransition.delete_all :role_id => 1
1691
1715
1692 @request.session[:user_id] = 2
1716 @request.session[:user_id] = 2
1693 get :new, :project_id => 1, :tracker_id => 1
1717 get :new, :project_id => 1, :tracker_id => 1
1694 assert_response :success
1718 assert_response :success
1695 assert_template 'new'
1719 assert_template 'new'
1696
1720
1697 assert_select 'form#issue-form' do
1721 assert_select 'form#issue-form' do
1698 assert_select 'input[name=?]', 'issue[is_private]', 0
1722 assert_select 'input[name=?]', 'issue[is_private]', 0
1699 assert_select 'select[name=?]', 'issue[project_id]', 0
1723 assert_select 'select[name=?]', 'issue[project_id]', 0
1700 assert_select 'select[name=?]', 'issue[tracker_id]'
1724 assert_select 'select[name=?]', 'issue[tracker_id]'
1701 assert_select 'input[name=?]', 'issue[subject]'
1725 assert_select 'input[name=?]', 'issue[subject]'
1702 assert_select 'textarea[name=?]', 'issue[description]'
1726 assert_select 'textarea[name=?]', 'issue[description]'
1703 assert_select 'select[name=?]', 'issue[status_id]'
1727 assert_select 'select[name=?]', 'issue[status_id]'
1704 assert_select 'select[name=?]', 'issue[priority_id]'
1728 assert_select 'select[name=?]', 'issue[priority_id]'
1705 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1729 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1706 assert_select 'select[name=?]', 'issue[category_id]'
1730 assert_select 'select[name=?]', 'issue[category_id]'
1707 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1731 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1708 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
1732 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
1709 assert_select 'input[name=?]', 'issue[start_date]'
1733 assert_select 'input[name=?]', 'issue[start_date]'
1710 assert_select 'input[name=?]', 'issue[due_date]'
1734 assert_select 'input[name=?]', 'issue[due_date]'
1711 assert_select 'select[name=?]', 'issue[done_ratio]'
1735 assert_select 'select[name=?]', 'issue[done_ratio]'
1712 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1736 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1713 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1737 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1714 end
1738 end
1715 end
1739 end
1716
1740
1717 def test_new_without_project_id
1741 def test_new_without_project_id
1718 @request.session[:user_id] = 2
1742 @request.session[:user_id] = 2
1719 get :new
1743 get :new
1720 assert_response :success
1744 assert_response :success
1721 assert_template 'new'
1745 assert_template 'new'
1722
1746
1723 assert_select 'form#issue-form[action=?]', '/issues'
1747 assert_select 'form#issue-form[action=?]', '/issues'
1724 assert_select 'form#issue-form' do
1748 assert_select 'form#issue-form' do
1725 assert_select 'select[name=?]', 'issue[project_id]'
1749 assert_select 'select[name=?]', 'issue[project_id]'
1726 end
1750 end
1727
1751
1728 assert_nil assigns(:project)
1752 assert_nil assigns(:project)
1729 assert_not_nil assigns(:issue)
1753 assert_not_nil assigns(:issue)
1730 end
1754 end
1731
1755
1732 def test_new_should_select_default_status
1756 def test_new_should_select_default_status
1733 @request.session[:user_id] = 2
1757 @request.session[:user_id] = 2
1734
1758
1735 get :new, :project_id => 1
1759 get :new, :project_id => 1
1736 assert_response :success
1760 assert_response :success
1737 assert_template 'new'
1761 assert_template 'new'
1738 assert_select 'select[name=?]', 'issue[status_id]' do
1762 assert_select 'select[name=?]', 'issue[status_id]' do
1739 assert_select 'option[value="1"][selected=selected]'
1763 assert_select 'option[value="1"][selected=selected]'
1740 end
1764 end
1741 assert_select 'input[name=was_default_status][value="1"]'
1765 assert_select 'input[name=was_default_status][value="1"]'
1742 end
1766 end
1743
1767
1744 def test_new_should_propose_allowed_statuses
1768 def test_new_should_propose_allowed_statuses
1745 WorkflowTransition.delete_all
1769 WorkflowTransition.delete_all
1746 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 1)
1770 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 1)
1747 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 3)
1771 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 3)
1748 @request.session[:user_id] = 2
1772 @request.session[:user_id] = 2
1749
1773
1750 get :new, :project_id => 1
1774 get :new, :project_id => 1
1751 assert_response :success
1775 assert_response :success
1752 assert_select 'select[name=?]', 'issue[status_id]' do
1776 assert_select 'select[name=?]', 'issue[status_id]' do
1753 assert_select 'option[value="1"]'
1777 assert_select 'option[value="1"]'
1754 assert_select 'option[value="3"]'
1778 assert_select 'option[value="3"]'
1755 assert_select 'option', 2
1779 assert_select 'option', 2
1756 assert_select 'option[value="1"][selected=selected]'
1780 assert_select 'option[value="1"][selected=selected]'
1757 end
1781 end
1758 end
1782 end
1759
1783
1760 def test_new_should_propose_allowed_statuses_without_default_status_allowed
1784 def test_new_should_propose_allowed_statuses_without_default_status_allowed
1761 WorkflowTransition.delete_all
1785 WorkflowTransition.delete_all
1762 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 2)
1786 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 2)
1763 assert_equal 1, Tracker.find(1).default_status_id
1787 assert_equal 1, Tracker.find(1).default_status_id
1764 @request.session[:user_id] = 2
1788 @request.session[:user_id] = 2
1765
1789
1766 get :new, :project_id => 1
1790 get :new, :project_id => 1
1767 assert_response :success
1791 assert_response :success
1768 assert_select 'select[name=?]', 'issue[status_id]' do
1792 assert_select 'select[name=?]', 'issue[status_id]' do
1769 assert_select 'option[value="2"]'
1793 assert_select 'option[value="2"]'
1770 assert_select 'option', 1
1794 assert_select 'option', 1
1771 assert_select 'option[value="2"][selected=selected]'
1795 assert_select 'option[value="2"][selected=selected]'
1772 end
1796 end
1773 end
1797 end
1774
1798
1775 def test_new_should_preselect_default_version
1799 def test_new_should_preselect_default_version
1776 version = Version.generate!(:project_id => 1)
1800 version = Version.generate!(:project_id => 1)
1777 Project.find(1).update_attribute :default_version_id, version.id
1801 Project.find(1).update_attribute :default_version_id, version.id
1778 @request.session[:user_id] = 2
1802 @request.session[:user_id] = 2
1779
1803
1780 get :new, :project_id => 1
1804 get :new, :project_id => 1
1781 assert_response :success
1805 assert_response :success
1782 assert_equal version, assigns(:issue).fixed_version
1806 assert_equal version, assigns(:issue).fixed_version
1783 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
1807 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
1784 assert_select 'option[value=?][selected=selected]', version.id.to_s
1808 assert_select 'option[value=?][selected=selected]', version.id.to_s
1785 end
1809 end
1786 end
1810 end
1787
1811
1788 def test_get_new_with_list_custom_field
1812 def test_get_new_with_list_custom_field
1789 @request.session[:user_id] = 2
1813 @request.session[:user_id] = 2
1790 get :new, :project_id => 1, :tracker_id => 1
1814 get :new, :project_id => 1, :tracker_id => 1
1791 assert_response :success
1815 assert_response :success
1792 assert_template 'new'
1816 assert_template 'new'
1793
1817
1794 assert_select 'select.list_cf[name=?]', 'issue[custom_field_values][1]' do
1818 assert_select 'select.list_cf[name=?]', 'issue[custom_field_values][1]' do
1795 assert_select 'option', 4
1819 assert_select 'option', 4
1796 assert_select 'option[value=MySQL]', :text => 'MySQL'
1820 assert_select 'option[value=MySQL]', :text => 'MySQL'
1797 end
1821 end
1798 end
1822 end
1799
1823
1800 def test_get_new_with_multi_custom_field
1824 def test_get_new_with_multi_custom_field
1801 field = IssueCustomField.find(1)
1825 field = IssueCustomField.find(1)
1802 field.update_attribute :multiple, true
1826 field.update_attribute :multiple, true
1803
1827
1804 @request.session[:user_id] = 2
1828 @request.session[:user_id] = 2
1805 get :new, :project_id => 1, :tracker_id => 1
1829 get :new, :project_id => 1, :tracker_id => 1
1806 assert_response :success
1830 assert_response :success
1807 assert_template 'new'
1831 assert_template 'new'
1808
1832
1809 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
1833 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
1810 assert_select 'option', 3
1834 assert_select 'option', 3
1811 assert_select 'option[value=MySQL]', :text => 'MySQL'
1835 assert_select 'option[value=MySQL]', :text => 'MySQL'
1812 end
1836 end
1813 assert_select 'input[name=?][type=hidden][value=?]', 'issue[custom_field_values][1][]', ''
1837 assert_select 'input[name=?][type=hidden][value=?]', 'issue[custom_field_values][1][]', ''
1814 end
1838 end
1815
1839
1816 def test_get_new_with_multi_user_custom_field
1840 def test_get_new_with_multi_user_custom_field
1817 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1841 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1818 :tracker_ids => [1], :is_for_all => true)
1842 :tracker_ids => [1], :is_for_all => true)
1819
1843
1820 @request.session[:user_id] = 2
1844 @request.session[:user_id] = 2
1821 get :new, :project_id => 1, :tracker_id => 1
1845 get :new, :project_id => 1, :tracker_id => 1
1822 assert_response :success
1846 assert_response :success
1823 assert_template 'new'
1847 assert_template 'new'
1824
1848
1825 assert_select 'select[name=?][multiple=multiple]', "issue[custom_field_values][#{field.id}][]" do
1849 assert_select 'select[name=?][multiple=multiple]', "issue[custom_field_values][#{field.id}][]" do
1826 assert_select 'option', Project.find(1).users.count
1850 assert_select 'option', Project.find(1).users.count
1827 assert_select 'option[value="2"]', :text => 'John Smith'
1851 assert_select 'option[value="2"]', :text => 'John Smith'
1828 end
1852 end
1829 assert_select 'input[name=?][type=hidden][value=?]', "issue[custom_field_values][#{field.id}][]", ''
1853 assert_select 'input[name=?][type=hidden][value=?]', "issue[custom_field_values][#{field.id}][]", ''
1830 end
1854 end
1831
1855
1832 def test_get_new_with_date_custom_field
1856 def test_get_new_with_date_custom_field
1833 field = IssueCustomField.create!(:name => 'Date', :field_format => 'date', :tracker_ids => [1], :is_for_all => true)
1857 field = IssueCustomField.create!(:name => 'Date', :field_format => 'date', :tracker_ids => [1], :is_for_all => true)
1834
1858
1835 @request.session[:user_id] = 2
1859 @request.session[:user_id] = 2
1836 get :new, :project_id => 1, :tracker_id => 1
1860 get :new, :project_id => 1, :tracker_id => 1
1837 assert_response :success
1861 assert_response :success
1838
1862
1839 assert_select 'input[name=?]', "issue[custom_field_values][#{field.id}]"
1863 assert_select 'input[name=?]', "issue[custom_field_values][#{field.id}]"
1840 end
1864 end
1841
1865
1842 def test_get_new_with_text_custom_field
1866 def test_get_new_with_text_custom_field
1843 field = IssueCustomField.create!(:name => 'Text', :field_format => 'text', :tracker_ids => [1], :is_for_all => true)
1867 field = IssueCustomField.create!(:name => 'Text', :field_format => 'text', :tracker_ids => [1], :is_for_all => true)
1844
1868
1845 @request.session[:user_id] = 2
1869 @request.session[:user_id] = 2
1846 get :new, :project_id => 1, :tracker_id => 1
1870 get :new, :project_id => 1, :tracker_id => 1
1847 assert_response :success
1871 assert_response :success
1848
1872
1849 assert_select 'textarea[name=?]', "issue[custom_field_values][#{field.id}]"
1873 assert_select 'textarea[name=?]', "issue[custom_field_values][#{field.id}]"
1850 end
1874 end
1851
1875
1852 def test_get_new_without_default_start_date_is_creation_date
1876 def test_get_new_without_default_start_date_is_creation_date
1853 with_settings :default_issue_start_date_to_creation_date => 0 do
1877 with_settings :default_issue_start_date_to_creation_date => 0 do
1854 @request.session[:user_id] = 2
1878 @request.session[:user_id] = 2
1855 get :new, :project_id => 1, :tracker_id => 1
1879 get :new, :project_id => 1, :tracker_id => 1
1856 assert_response :success
1880 assert_response :success
1857 assert_template 'new'
1881 assert_template 'new'
1858 assert_select 'input[name=?]', 'issue[start_date]'
1882 assert_select 'input[name=?]', 'issue[start_date]'
1859 assert_select 'input[name=?][value]', 'issue[start_date]', 0
1883 assert_select 'input[name=?][value]', 'issue[start_date]', 0
1860 end
1884 end
1861 end
1885 end
1862
1886
1863 def test_get_new_with_default_start_date_is_creation_date
1887 def test_get_new_with_default_start_date_is_creation_date
1864 with_settings :default_issue_start_date_to_creation_date => 1 do
1888 with_settings :default_issue_start_date_to_creation_date => 1 do
1865 @request.session[:user_id] = 2
1889 @request.session[:user_id] = 2
1866 get :new, :project_id => 1, :tracker_id => 1
1890 get :new, :project_id => 1, :tracker_id => 1
1867 assert_response :success
1891 assert_response :success
1868 assert_template 'new'
1892 assert_template 'new'
1869 assert_select 'input[name=?][value=?]', 'issue[start_date]',
1893 assert_select 'input[name=?][value=?]', 'issue[start_date]',
1870 Date.today.to_s
1894 Date.today.to_s
1871 end
1895 end
1872 end
1896 end
1873
1897
1874 def test_get_new_form_should_allow_attachment_upload
1898 def test_get_new_form_should_allow_attachment_upload
1875 @request.session[:user_id] = 2
1899 @request.session[:user_id] = 2
1876 get :new, :project_id => 1, :tracker_id => 1
1900 get :new, :project_id => 1, :tracker_id => 1
1877
1901
1878 assert_select 'form[id=issue-form][method=post][enctype="multipart/form-data"]' do
1902 assert_select 'form[id=issue-form][method=post][enctype="multipart/form-data"]' do
1879 assert_select 'input[name=?][type=file]', 'attachments[dummy][file]'
1903 assert_select 'input[name=?][type=file]', 'attachments[dummy][file]'
1880 end
1904 end
1881 end
1905 end
1882
1906
1883 def test_get_new_should_prefill_the_form_from_params
1907 def test_get_new_should_prefill_the_form_from_params
1884 @request.session[:user_id] = 2
1908 @request.session[:user_id] = 2
1885 get :new, :project_id => 1,
1909 get :new, :project_id => 1,
1886 :issue => {:tracker_id => 3, :description => 'Prefilled', :custom_field_values => {'2' => 'Custom field value'}}
1910 :issue => {:tracker_id => 3, :description => 'Prefilled', :custom_field_values => {'2' => 'Custom field value'}}
1887
1911
1888 issue = assigns(:issue)
1912 issue = assigns(:issue)
1889 assert_equal 3, issue.tracker_id
1913 assert_equal 3, issue.tracker_id
1890 assert_equal 'Prefilled', issue.description
1914 assert_equal 'Prefilled', issue.description
1891 assert_equal 'Custom field value', issue.custom_field_value(2)
1915 assert_equal 'Custom field value', issue.custom_field_value(2)
1892
1916
1893 assert_select 'select[name=?]', 'issue[tracker_id]' do
1917 assert_select 'select[name=?]', 'issue[tracker_id]' do
1894 assert_select 'option[value="3"][selected=selected]'
1918 assert_select 'option[value="3"][selected=selected]'
1895 end
1919 end
1896 assert_select 'textarea[name=?]', 'issue[description]', :text => /Prefilled/
1920 assert_select 'textarea[name=?]', 'issue[description]', :text => /Prefilled/
1897 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Custom field value'
1921 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Custom field value'
1898 end
1922 end
1899
1923
1900 def test_get_new_should_mark_required_fields
1924 def test_get_new_should_mark_required_fields
1901 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1925 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1902 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1926 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1903 WorkflowPermission.delete_all
1927 WorkflowPermission.delete_all
1904 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'required')
1928 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'required')
1905 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
1929 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
1906 @request.session[:user_id] = 2
1930 @request.session[:user_id] = 2
1907
1931
1908 get :new, :project_id => 1
1932 get :new, :project_id => 1
1909 assert_response :success
1933 assert_response :success
1910 assert_template 'new'
1934 assert_template 'new'
1911
1935
1912 assert_select 'label[for=issue_start_date]' do
1936 assert_select 'label[for=issue_start_date]' do
1913 assert_select 'span[class=required]', 0
1937 assert_select 'span[class=required]', 0
1914 end
1938 end
1915 assert_select 'label[for=issue_due_date]' do
1939 assert_select 'label[for=issue_due_date]' do
1916 assert_select 'span[class=required]'
1940 assert_select 'span[class=required]'
1917 end
1941 end
1918 assert_select 'label[for=?]', "issue_custom_field_values_#{cf1.id}" do
1942 assert_select 'label[for=?]', "issue_custom_field_values_#{cf1.id}" do
1919 assert_select 'span[class=required]', 0
1943 assert_select 'span[class=required]', 0
1920 end
1944 end
1921 assert_select 'label[for=?]', "issue_custom_field_values_#{cf2.id}" do
1945 assert_select 'label[for=?]', "issue_custom_field_values_#{cf2.id}" do
1922 assert_select 'span[class=required]'
1946 assert_select 'span[class=required]'
1923 end
1947 end
1924 end
1948 end
1925
1949
1926 def test_get_new_should_not_display_readonly_fields
1950 def test_get_new_should_not_display_readonly_fields
1927 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1951 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1928 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1952 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1929 WorkflowPermission.delete_all
1953 WorkflowPermission.delete_all
1930 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
1954 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
1931 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
1955 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
1932 @request.session[:user_id] = 2
1956 @request.session[:user_id] = 2
1933
1957
1934 get :new, :project_id => 1
1958 get :new, :project_id => 1
1935 assert_response :success
1959 assert_response :success
1936 assert_template 'new'
1960 assert_template 'new'
1937
1961
1938 assert_select 'input[name=?]', 'issue[start_date]'
1962 assert_select 'input[name=?]', 'issue[start_date]'
1939 assert_select 'input[name=?]', 'issue[due_date]', 0
1963 assert_select 'input[name=?]', 'issue[due_date]', 0
1940 assert_select 'input[name=?]', "issue[custom_field_values][#{cf1.id}]"
1964 assert_select 'input[name=?]', "issue[custom_field_values][#{cf1.id}]"
1941 assert_select 'input[name=?]', "issue[custom_field_values][#{cf2.id}]", 0
1965 assert_select 'input[name=?]', "issue[custom_field_values][#{cf2.id}]", 0
1942 end
1966 end
1943
1967
1944 def test_new_with_tracker_set_as_readonly_should_accept_status
1968 def test_new_with_tracker_set_as_readonly_should_accept_status
1945 WorkflowPermission.delete_all
1969 WorkflowPermission.delete_all
1946 [1, 2].each do |status_id|
1970 [1, 2].each do |status_id|
1947 WorkflowPermission.create!(:tracker_id => 1, :old_status_id => status_id, :role_id => 1, :field_name => 'tracker_id', :rule => 'readonly')
1971 WorkflowPermission.create!(:tracker_id => 1, :old_status_id => status_id, :role_id => 1, :field_name => 'tracker_id', :rule => 'readonly')
1948 end
1972 end
1949 @request.session[:user_id] = 2
1973 @request.session[:user_id] = 2
1950
1974
1951 get :new, :project_id => 1, :issue => {:status_id => 2}
1975 get :new, :project_id => 1, :issue => {:status_id => 2}
1952 assert_select 'select[name=?]', 'issue[tracker_id]', 0
1976 assert_select 'select[name=?]', 'issue[tracker_id]', 0
1953 assert_equal 2, assigns(:issue).status_id
1977 assert_equal 2, assigns(:issue).status_id
1954 end
1978 end
1955
1979
1956 def test_get_new_without_tracker_id
1980 def test_get_new_without_tracker_id
1957 @request.session[:user_id] = 2
1981 @request.session[:user_id] = 2
1958 get :new, :project_id => 1
1982 get :new, :project_id => 1
1959 assert_response :success
1983 assert_response :success
1960 assert_template 'new'
1984 assert_template 'new'
1961
1985
1962 issue = assigns(:issue)
1986 issue = assigns(:issue)
1963 assert_not_nil issue
1987 assert_not_nil issue
1964 assert_equal Project.find(1).trackers.first, issue.tracker
1988 assert_equal Project.find(1).trackers.first, issue.tracker
1965 end
1989 end
1966
1990
1967 def test_get_new_with_no_default_status_should_display_an_error
1991 def test_get_new_with_no_default_status_should_display_an_error
1968 @request.session[:user_id] = 2
1992 @request.session[:user_id] = 2
1969 IssueStatus.delete_all
1993 IssueStatus.delete_all
1970
1994
1971 get :new, :project_id => 1
1995 get :new, :project_id => 1
1972 assert_response 500
1996 assert_response 500
1973 assert_select_error /No default issue/
1997 assert_select_error /No default issue/
1974 end
1998 end
1975
1999
1976 def test_get_new_with_no_tracker_should_display_an_error
2000 def test_get_new_with_no_tracker_should_display_an_error
1977 @request.session[:user_id] = 2
2001 @request.session[:user_id] = 2
1978 Tracker.delete_all
2002 Tracker.delete_all
1979
2003
1980 get :new, :project_id => 1
2004 get :new, :project_id => 1
1981 assert_response 500
2005 assert_response 500
1982 assert_select_error /No tracker/
2006 assert_select_error /No tracker/
1983 end
2007 end
1984
2008
1985 def test_new_with_invalid_project_id
2009 def test_new_with_invalid_project_id
1986 @request.session[:user_id] = 1
2010 @request.session[:user_id] = 1
1987 get :new, :project_id => 'invalid'
2011 get :new, :project_id => 'invalid'
1988 assert_response 404
2012 assert_response 404
1989 end
2013 end
1990
2014
1991 def test_update_form_for_new_issue
2015 def test_update_form_for_new_issue
1992 @request.session[:user_id] = 2
2016 @request.session[:user_id] = 2
1993 xhr :post, :new, :project_id => 1,
2017 xhr :post, :new, :project_id => 1,
1994 :issue => {:tracker_id => 2,
2018 :issue => {:tracker_id => 2,
1995 :subject => 'This is the test_new issue',
2019 :subject => 'This is the test_new issue',
1996 :description => 'This is the description',
2020 :description => 'This is the description',
1997 :priority_id => 5}
2021 :priority_id => 5}
1998 assert_response :success
2022 assert_response :success
1999 assert_template 'new'
2023 assert_template 'new'
2000 assert_template :partial => '_form'
2024 assert_template :partial => '_form'
2001 assert_equal 'text/javascript', response.content_type
2025 assert_equal 'text/javascript', response.content_type
2002
2026
2003 issue = assigns(:issue)
2027 issue = assigns(:issue)
2004 assert_kind_of Issue, issue
2028 assert_kind_of Issue, issue
2005 assert_equal 1, issue.project_id
2029 assert_equal 1, issue.project_id
2006 assert_equal 2, issue.tracker_id
2030 assert_equal 2, issue.tracker_id
2007 assert_equal 'This is the test_new issue', issue.subject
2031 assert_equal 'This is the test_new issue', issue.subject
2008 end
2032 end
2009
2033
2010 def test_update_form_for_new_issue_should_propose_transitions_based_on_initial_status
2034 def test_update_form_for_new_issue_should_propose_transitions_based_on_initial_status
2011 @request.session[:user_id] = 2
2035 @request.session[:user_id] = 2
2012 WorkflowTransition.delete_all
2036 WorkflowTransition.delete_all
2013 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2)
2037 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2)
2014 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 5)
2038 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 5)
2015 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4)
2039 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4)
2016
2040
2017 xhr :post, :new, :project_id => 1,
2041 xhr :post, :new, :project_id => 1,
2018 :issue => {:tracker_id => 1,
2042 :issue => {:tracker_id => 1,
2019 :status_id => 5,
2043 :status_id => 5,
2020 :subject => 'This is an issue'}
2044 :subject => 'This is an issue'}
2021
2045
2022 assert_equal 5, assigns(:issue).status_id
2046 assert_equal 5, assigns(:issue).status_id
2023 assert_equal [2,5], assigns(:allowed_statuses).map(&:id).sort
2047 assert_equal [2,5], assigns(:allowed_statuses).map(&:id).sort
2024 end
2048 end
2025
2049
2026 def test_update_form_with_default_status_should_ignore_submitted_status_id_if_equals
2050 def test_update_form_with_default_status_should_ignore_submitted_status_id_if_equals
2027 @request.session[:user_id] = 2
2051 @request.session[:user_id] = 2
2028 tracker = Tracker.find(2)
2052 tracker = Tracker.find(2)
2029 tracker.update! :default_status_id => 2
2053 tracker.update! :default_status_id => 2
2030 tracker.generate_transitions! 2, 1, :clear => true
2054 tracker.generate_transitions! 2, 1, :clear => true
2031
2055
2032 xhr :post, :new, :project_id => 1,
2056 xhr :post, :new, :project_id => 1,
2033 :issue => {:tracker_id => 2,
2057 :issue => {:tracker_id => 2,
2034 :status_id => 1},
2058 :status_id => 1},
2035 :was_default_status => 1
2059 :was_default_status => 1
2036
2060
2037 assert_equal 2, assigns(:issue).status_id
2061 assert_equal 2, assigns(:issue).status_id
2038 end
2062 end
2039
2063
2040 def test_update_form_for_new_issue_should_ignore_version_when_changing_project
2064 def test_update_form_for_new_issue_should_ignore_version_when_changing_project
2041 version = Version.generate!(:project_id => 1)
2065 version = Version.generate!(:project_id => 1)
2042 Project.find(1).update_attribute :default_version_id, version.id
2066 Project.find(1).update_attribute :default_version_id, version.id
2043 @request.session[:user_id] = 2
2067 @request.session[:user_id] = 2
2044
2068
2045 xhr :post, :new, :issue => {:project_id => 1,
2069 xhr :post, :new, :issue => {:project_id => 1,
2046 :fixed_version_id => ''},
2070 :fixed_version_id => ''},
2047 :form_update_triggered_by => 'issue_project_id'
2071 :form_update_triggered_by => 'issue_project_id'
2048 assert_response :success
2072 assert_response :success
2049 assert_template 'new'
2073 assert_template 'new'
2050
2074
2051 issue = assigns(:issue)
2075 issue = assigns(:issue)
2052 assert_equal 1, issue.project_id
2076 assert_equal 1, issue.project_id
2053 assert_equal version, issue.fixed_version
2077 assert_equal version, issue.fixed_version
2054 end
2078 end
2055
2079
2056 def test_post_create
2080 def test_post_create
2057 @request.session[:user_id] = 2
2081 @request.session[:user_id] = 2
2058 assert_difference 'Issue.count' do
2082 assert_difference 'Issue.count' do
2059 assert_no_difference 'Journal.count' do
2083 assert_no_difference 'Journal.count' do
2060 post :create, :project_id => 1,
2084 post :create, :project_id => 1,
2061 :issue => {:tracker_id => 3,
2085 :issue => {:tracker_id => 3,
2062 :status_id => 2,
2086 :status_id => 2,
2063 :subject => 'This is the test_new issue',
2087 :subject => 'This is the test_new issue',
2064 :description => 'This is the description',
2088 :description => 'This is the description',
2065 :priority_id => 5,
2089 :priority_id => 5,
2066 :start_date => '2010-11-07',
2090 :start_date => '2010-11-07',
2067 :estimated_hours => '',
2091 :estimated_hours => '',
2068 :custom_field_values => {'2' => 'Value for field 2'}}
2092 :custom_field_values => {'2' => 'Value for field 2'}}
2069 end
2093 end
2070 end
2094 end
2071 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2095 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2072
2096
2073 issue = Issue.find_by_subject('This is the test_new issue')
2097 issue = Issue.find_by_subject('This is the test_new issue')
2074 assert_not_nil issue
2098 assert_not_nil issue
2075 assert_equal 2, issue.author_id
2099 assert_equal 2, issue.author_id
2076 assert_equal 3, issue.tracker_id
2100 assert_equal 3, issue.tracker_id
2077 assert_equal 2, issue.status_id
2101 assert_equal 2, issue.status_id
2078 assert_equal Date.parse('2010-11-07'), issue.start_date
2102 assert_equal Date.parse('2010-11-07'), issue.start_date
2079 assert_nil issue.estimated_hours
2103 assert_nil issue.estimated_hours
2080 v = issue.custom_values.where(:custom_field_id => 2).first
2104 v = issue.custom_values.where(:custom_field_id => 2).first
2081 assert_not_nil v
2105 assert_not_nil v
2082 assert_equal 'Value for field 2', v.value
2106 assert_equal 'Value for field 2', v.value
2083 end
2107 end
2084
2108
2085 def test_post_new_with_group_assignment
2109 def test_post_new_with_group_assignment
2086 group = Group.find(11)
2110 group = Group.find(11)
2087 project = Project.find(1)
2111 project = Project.find(1)
2088 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
2112 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
2089
2113
2090 with_settings :issue_group_assignment => '1' do
2114 with_settings :issue_group_assignment => '1' do
2091 @request.session[:user_id] = 2
2115 @request.session[:user_id] = 2
2092 assert_difference 'Issue.count' do
2116 assert_difference 'Issue.count' do
2093 post :create, :project_id => project.id,
2117 post :create, :project_id => project.id,
2094 :issue => {:tracker_id => 3,
2118 :issue => {:tracker_id => 3,
2095 :status_id => 1,
2119 :status_id => 1,
2096 :subject => 'This is the test_new_with_group_assignment issue',
2120 :subject => 'This is the test_new_with_group_assignment issue',
2097 :assigned_to_id => group.id}
2121 :assigned_to_id => group.id}
2098 end
2122 end
2099 end
2123 end
2100 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2124 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2101
2125
2102 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
2126 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
2103 assert_not_nil issue
2127 assert_not_nil issue
2104 assert_equal group, issue.assigned_to
2128 assert_equal group, issue.assigned_to
2105 end
2129 end
2106
2130
2107 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
2131 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
2108 with_settings :default_issue_start_date_to_creation_date => 0 do
2132 with_settings :default_issue_start_date_to_creation_date => 0 do
2109 @request.session[:user_id] = 2
2133 @request.session[:user_id] = 2
2110 assert_difference 'Issue.count' do
2134 assert_difference 'Issue.count' do
2111 post :create, :project_id => 1,
2135 post :create, :project_id => 1,
2112 :issue => {:tracker_id => 3,
2136 :issue => {:tracker_id => 3,
2113 :status_id => 2,
2137 :status_id => 2,
2114 :subject => 'This is the test_new issue',
2138 :subject => 'This is the test_new issue',
2115 :description => 'This is the description',
2139 :description => 'This is the description',
2116 :priority_id => 5,
2140 :priority_id => 5,
2117 :estimated_hours => '',
2141 :estimated_hours => '',
2118 :custom_field_values => {'2' => 'Value for field 2'}}
2142 :custom_field_values => {'2' => 'Value for field 2'}}
2119 end
2143 end
2120 assert_redirected_to :controller => 'issues', :action => 'show',
2144 assert_redirected_to :controller => 'issues', :action => 'show',
2121 :id => Issue.last.id
2145 :id => Issue.last.id
2122 issue = Issue.find_by_subject('This is the test_new issue')
2146 issue = Issue.find_by_subject('This is the test_new issue')
2123 assert_not_nil issue
2147 assert_not_nil issue
2124 assert_nil issue.start_date
2148 assert_nil issue.start_date
2125 end
2149 end
2126 end
2150 end
2127
2151
2128 def test_post_create_without_start_date_and_default_start_date_is_creation_date
2152 def test_post_create_without_start_date_and_default_start_date_is_creation_date
2129 with_settings :default_issue_start_date_to_creation_date => 1 do
2153 with_settings :default_issue_start_date_to_creation_date => 1 do
2130 @request.session[:user_id] = 2
2154 @request.session[:user_id] = 2
2131 assert_difference 'Issue.count' do
2155 assert_difference 'Issue.count' do
2132 post :create, :project_id => 1,
2156 post :create, :project_id => 1,
2133 :issue => {:tracker_id => 3,
2157 :issue => {:tracker_id => 3,
2134 :status_id => 2,
2158 :status_id => 2,
2135 :subject => 'This is the test_new issue',
2159 :subject => 'This is the test_new issue',
2136 :description => 'This is the description',
2160 :description => 'This is the description',
2137 :priority_id => 5,
2161 :priority_id => 5,
2138 :estimated_hours => '',
2162 :estimated_hours => '',
2139 :custom_field_values => {'2' => 'Value for field 2'}}
2163 :custom_field_values => {'2' => 'Value for field 2'}}
2140 end
2164 end
2141 assert_redirected_to :controller => 'issues', :action => 'show',
2165 assert_redirected_to :controller => 'issues', :action => 'show',
2142 :id => Issue.last.id
2166 :id => Issue.last.id
2143 issue = Issue.find_by_subject('This is the test_new issue')
2167 issue = Issue.find_by_subject('This is the test_new issue')
2144 assert_not_nil issue
2168 assert_not_nil issue
2145 assert_equal Date.today, issue.start_date
2169 assert_equal Date.today, issue.start_date
2146 end
2170 end
2147 end
2171 end
2148
2172
2149 def test_post_create_and_continue
2173 def test_post_create_and_continue
2150 @request.session[:user_id] = 2
2174 @request.session[:user_id] = 2
2151 assert_difference 'Issue.count' do
2175 assert_difference 'Issue.count' do
2152 post :create, :project_id => 1,
2176 post :create, :project_id => 1,
2153 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
2177 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
2154 :continue => ''
2178 :continue => ''
2155 end
2179 end
2156
2180
2157 issue = Issue.order('id DESC').first
2181 issue = Issue.order('id DESC').first
2158 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
2182 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
2159 assert_not_nil flash[:notice], "flash was not set"
2183 assert_not_nil flash[:notice], "flash was not set"
2160 assert_select_in flash[:notice],
2184 assert_select_in flash[:notice],
2161 'a[href=?][title=?]', "/issues/#{issue.id}", "This is first issue", :text => "##{issue.id}"
2185 'a[href=?][title=?]', "/issues/#{issue.id}", "This is first issue", :text => "##{issue.id}"
2162 end
2186 end
2163
2187
2164 def test_post_create_without_custom_fields_param
2188 def test_post_create_without_custom_fields_param
2165 @request.session[:user_id] = 2
2189 @request.session[:user_id] = 2
2166 assert_difference 'Issue.count' do
2190 assert_difference 'Issue.count' do
2167 post :create, :project_id => 1,
2191 post :create, :project_id => 1,
2168 :issue => {:tracker_id => 1,
2192 :issue => {:tracker_id => 1,
2169 :subject => 'This is the test_new issue',
2193 :subject => 'This is the test_new issue',
2170 :description => 'This is the description',
2194 :description => 'This is the description',
2171 :priority_id => 5}
2195 :priority_id => 5}
2172 end
2196 end
2173 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2197 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2174 end
2198 end
2175
2199
2176 def test_post_create_with_multi_custom_field
2200 def test_post_create_with_multi_custom_field
2177 field = IssueCustomField.find_by_name('Database')
2201 field = IssueCustomField.find_by_name('Database')
2178 field.update_attribute(:multiple, true)
2202 field.update_attribute(:multiple, true)
2179
2203
2180 @request.session[:user_id] = 2
2204 @request.session[:user_id] = 2
2181 assert_difference 'Issue.count' do
2205 assert_difference 'Issue.count' do
2182 post :create, :project_id => 1,
2206 post :create, :project_id => 1,
2183 :issue => {:tracker_id => 1,
2207 :issue => {:tracker_id => 1,
2184 :subject => 'This is the test_new issue',
2208 :subject => 'This is the test_new issue',
2185 :description => 'This is the description',
2209 :description => 'This is the description',
2186 :priority_id => 5,
2210 :priority_id => 5,
2187 :custom_field_values => {'1' => ['', 'MySQL', 'Oracle']}}
2211 :custom_field_values => {'1' => ['', 'MySQL', 'Oracle']}}
2188 end
2212 end
2189 assert_response 302
2213 assert_response 302
2190 issue = Issue.order('id DESC').first
2214 issue = Issue.order('id DESC').first
2191 assert_equal ['MySQL', 'Oracle'], issue.custom_field_value(1).sort
2215 assert_equal ['MySQL', 'Oracle'], issue.custom_field_value(1).sort
2192 end
2216 end
2193
2217
2194 def test_post_create_with_empty_multi_custom_field
2218 def test_post_create_with_empty_multi_custom_field
2195 field = IssueCustomField.find_by_name('Database')
2219 field = IssueCustomField.find_by_name('Database')
2196 field.update_attribute(:multiple, true)
2220 field.update_attribute(:multiple, true)
2197
2221
2198 @request.session[:user_id] = 2
2222 @request.session[:user_id] = 2
2199 assert_difference 'Issue.count' do
2223 assert_difference 'Issue.count' do
2200 post :create, :project_id => 1,
2224 post :create, :project_id => 1,
2201 :issue => {:tracker_id => 1,
2225 :issue => {:tracker_id => 1,
2202 :subject => 'This is the test_new issue',
2226 :subject => 'This is the test_new issue',
2203 :description => 'This is the description',
2227 :description => 'This is the description',
2204 :priority_id => 5,
2228 :priority_id => 5,
2205 :custom_field_values => {'1' => ['']}}
2229 :custom_field_values => {'1' => ['']}}
2206 end
2230 end
2207 assert_response 302
2231 assert_response 302
2208 issue = Issue.order('id DESC').first
2232 issue = Issue.order('id DESC').first
2209 assert_equal [''], issue.custom_field_value(1).sort
2233 assert_equal [''], issue.custom_field_value(1).sort
2210 end
2234 end
2211
2235
2212 def test_post_create_with_multi_user_custom_field
2236 def test_post_create_with_multi_user_custom_field
2213 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
2237 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
2214 :tracker_ids => [1], :is_for_all => true)
2238 :tracker_ids => [1], :is_for_all => true)
2215
2239
2216 @request.session[:user_id] = 2
2240 @request.session[:user_id] = 2
2217 assert_difference 'Issue.count' do
2241 assert_difference 'Issue.count' do
2218 post :create, :project_id => 1,
2242 post :create, :project_id => 1,
2219 :issue => {:tracker_id => 1,
2243 :issue => {:tracker_id => 1,
2220 :subject => 'This is the test_new issue',
2244 :subject => 'This is the test_new issue',
2221 :description => 'This is the description',
2245 :description => 'This is the description',
2222 :priority_id => 5,
2246 :priority_id => 5,
2223 :custom_field_values => {field.id.to_s => ['', '2', '3']}}
2247 :custom_field_values => {field.id.to_s => ['', '2', '3']}}
2224 end
2248 end
2225 assert_response 302
2249 assert_response 302
2226 issue = Issue.order('id DESC').first
2250 issue = Issue.order('id DESC').first
2227 assert_equal ['2', '3'], issue.custom_field_value(field).sort
2251 assert_equal ['2', '3'], issue.custom_field_value(field).sort
2228 end
2252 end
2229
2253
2230 def test_post_create_with_required_custom_field_and_without_custom_fields_param
2254 def test_post_create_with_required_custom_field_and_without_custom_fields_param
2231 field = IssueCustomField.find_by_name('Database')
2255 field = IssueCustomField.find_by_name('Database')
2232 field.update_attribute(:is_required, true)
2256 field.update_attribute(:is_required, true)
2233
2257
2234 @request.session[:user_id] = 2
2258 @request.session[:user_id] = 2
2235 assert_no_difference 'Issue.count' do
2259 assert_no_difference 'Issue.count' do
2236 post :create, :project_id => 1,
2260 post :create, :project_id => 1,
2237 :issue => {:tracker_id => 1,
2261 :issue => {:tracker_id => 1,
2238 :subject => 'This is the test_new issue',
2262 :subject => 'This is the test_new issue',
2239 :description => 'This is the description',
2263 :description => 'This is the description',
2240 :priority_id => 5}
2264 :priority_id => 5}
2241 end
2265 end
2242 assert_response :success
2266 assert_response :success
2243 assert_template 'new'
2267 assert_template 'new'
2244 issue = assigns(:issue)
2268 issue = assigns(:issue)
2245 assert_not_nil issue
2269 assert_not_nil issue
2246 assert_select_error /Database cannot be blank/
2270 assert_select_error /Database cannot be blank/
2247 end
2271 end
2248
2272
2249 def test_create_should_validate_required_fields
2273 def test_create_should_validate_required_fields
2250 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2274 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2251 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2275 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2252 WorkflowPermission.delete_all
2276 WorkflowPermission.delete_all
2253 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'required')
2277 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'required')
2254 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
2278 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
2255 @request.session[:user_id] = 2
2279 @request.session[:user_id] = 2
2256
2280
2257 assert_no_difference 'Issue.count' do
2281 assert_no_difference 'Issue.count' do
2258 post :create, :project_id => 1, :issue => {
2282 post :create, :project_id => 1, :issue => {
2259 :tracker_id => 2,
2283 :tracker_id => 2,
2260 :status_id => 1,
2284 :status_id => 1,
2261 :subject => 'Test',
2285 :subject => 'Test',
2262 :start_date => '',
2286 :start_date => '',
2263 :due_date => '',
2287 :due_date => '',
2264 :custom_field_values => {cf1.id.to_s => '', cf2.id.to_s => ''}
2288 :custom_field_values => {cf1.id.to_s => '', cf2.id.to_s => ''}
2265 }
2289 }
2266 assert_response :success
2290 assert_response :success
2267 assert_template 'new'
2291 assert_template 'new'
2268 end
2292 end
2269
2293
2270 assert_select_error /Due date cannot be blank/i
2294 assert_select_error /Due date cannot be blank/i
2271 assert_select_error /Bar cannot be blank/i
2295 assert_select_error /Bar cannot be blank/i
2272 end
2296 end
2273
2297
2274 def test_create_should_validate_required_list_fields
2298 def test_create_should_validate_required_list_fields
2275 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'list', :is_for_all => true, :tracker_ids => [1, 2], :multiple => false, :possible_values => ['a', 'b'])
2299 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'list', :is_for_all => true, :tracker_ids => [1, 2], :multiple => false, :possible_values => ['a', 'b'])
2276 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'list', :is_for_all => true, :tracker_ids => [1, 2], :multiple => true, :possible_values => ['a', 'b'])
2300 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'list', :is_for_all => true, :tracker_ids => [1, 2], :multiple => true, :possible_values => ['a', 'b'])
2277 WorkflowPermission.delete_all
2301 WorkflowPermission.delete_all
2278 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf1.id.to_s, :rule => 'required')
2302 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf1.id.to_s, :rule => 'required')
2279 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
2303 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
2280 @request.session[:user_id] = 2
2304 @request.session[:user_id] = 2
2281
2305
2282 assert_no_difference 'Issue.count' do
2306 assert_no_difference 'Issue.count' do
2283 post :create, :project_id => 1, :issue => {
2307 post :create, :project_id => 1, :issue => {
2284 :tracker_id => 2,
2308 :tracker_id => 2,
2285 :status_id => 1,
2309 :status_id => 1,
2286 :subject => 'Test',
2310 :subject => 'Test',
2287 :start_date => '',
2311 :start_date => '',
2288 :due_date => '',
2312 :due_date => '',
2289 :custom_field_values => {cf1.id.to_s => '', cf2.id.to_s => ['']}
2313 :custom_field_values => {cf1.id.to_s => '', cf2.id.to_s => ['']}
2290 }
2314 }
2291 assert_response :success
2315 assert_response :success
2292 assert_template 'new'
2316 assert_template 'new'
2293 end
2317 end
2294
2318
2295 assert_select_error /Foo cannot be blank/i
2319 assert_select_error /Foo cannot be blank/i
2296 assert_select_error /Bar cannot be blank/i
2320 assert_select_error /Bar cannot be blank/i
2297 end
2321 end
2298
2322
2299 def test_create_should_ignore_readonly_fields
2323 def test_create_should_ignore_readonly_fields
2300 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2324 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2301 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2325 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2302 WorkflowPermission.delete_all
2326 WorkflowPermission.delete_all
2303 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
2327 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
2304 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
2328 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
2305 @request.session[:user_id] = 2
2329 @request.session[:user_id] = 2
2306
2330
2307 assert_difference 'Issue.count' do
2331 assert_difference 'Issue.count' do
2308 post :create, :project_id => 1, :issue => {
2332 post :create, :project_id => 1, :issue => {
2309 :tracker_id => 2,
2333 :tracker_id => 2,
2310 :status_id => 1,
2334 :status_id => 1,
2311 :subject => 'Test',
2335 :subject => 'Test',
2312 :start_date => '2012-07-14',
2336 :start_date => '2012-07-14',
2313 :due_date => '2012-07-16',
2337 :due_date => '2012-07-16',
2314 :custom_field_values => {cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'}
2338 :custom_field_values => {cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'}
2315 }
2339 }
2316 assert_response 302
2340 assert_response 302
2317 end
2341 end
2318
2342
2319 issue = Issue.order('id DESC').first
2343 issue = Issue.order('id DESC').first
2320 assert_equal Date.parse('2012-07-14'), issue.start_date
2344 assert_equal Date.parse('2012-07-14'), issue.start_date
2321 assert_nil issue.due_date
2345 assert_nil issue.due_date
2322 assert_equal 'value1', issue.custom_field_value(cf1)
2346 assert_equal 'value1', issue.custom_field_value(cf1)
2323 assert_nil issue.custom_field_value(cf2)
2347 assert_nil issue.custom_field_value(cf2)
2324 end
2348 end
2325
2349
2326 def test_post_create_with_watchers
2350 def test_post_create_with_watchers
2327 @request.session[:user_id] = 2
2351 @request.session[:user_id] = 2
2328 ActionMailer::Base.deliveries.clear
2352 ActionMailer::Base.deliveries.clear
2329
2353
2330 with_settings :notified_events => %w(issue_added) do
2354 with_settings :notified_events => %w(issue_added) do
2331 assert_difference 'Watcher.count', 2 do
2355 assert_difference 'Watcher.count', 2 do
2332 post :create, :project_id => 1,
2356 post :create, :project_id => 1,
2333 :issue => {:tracker_id => 1,
2357 :issue => {:tracker_id => 1,
2334 :subject => 'This is a new issue with watchers',
2358 :subject => 'This is a new issue with watchers',
2335 :description => 'This is the description',
2359 :description => 'This is the description',
2336 :priority_id => 5,
2360 :priority_id => 5,
2337 :watcher_user_ids => ['2', '3']}
2361 :watcher_user_ids => ['2', '3']}
2338 end
2362 end
2339 end
2363 end
2340 issue = Issue.find_by_subject('This is a new issue with watchers')
2364 issue = Issue.find_by_subject('This is a new issue with watchers')
2341 assert_not_nil issue
2365 assert_not_nil issue
2342 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
2366 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
2343
2367
2344 # Watchers added
2368 # Watchers added
2345 assert_equal [2, 3], issue.watcher_user_ids.sort
2369 assert_equal [2, 3], issue.watcher_user_ids.sort
2346 assert issue.watched_by?(User.find(3))
2370 assert issue.watched_by?(User.find(3))
2347 # Watchers notified
2371 # Watchers notified
2348 mail = ActionMailer::Base.deliveries.last
2372 mail = ActionMailer::Base.deliveries.last
2349 assert_not_nil mail
2373 assert_not_nil mail
2350 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
2374 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
2351 end
2375 end
2352
2376
2353 def test_post_create_subissue
2377 def test_post_create_subissue
2354 @request.session[:user_id] = 2
2378 @request.session[:user_id] = 2
2355
2379
2356 assert_difference 'Issue.count' do
2380 assert_difference 'Issue.count' do
2357 post :create, :project_id => 1,
2381 post :create, :project_id => 1,
2358 :issue => {:tracker_id => 1,
2382 :issue => {:tracker_id => 1,
2359 :subject => 'This is a child issue',
2383 :subject => 'This is a child issue',
2360 :parent_issue_id => '2'}
2384 :parent_issue_id => '2'}
2361 assert_response 302
2385 assert_response 302
2362 end
2386 end
2363 issue = Issue.order('id DESC').first
2387 issue = Issue.order('id DESC').first
2364 assert_equal Issue.find(2), issue.parent
2388 assert_equal Issue.find(2), issue.parent
2365 end
2389 end
2366
2390
2367 def test_post_create_subissue_with_sharp_parent_id
2391 def test_post_create_subissue_with_sharp_parent_id
2368 @request.session[:user_id] = 2
2392 @request.session[:user_id] = 2
2369
2393
2370 assert_difference 'Issue.count' do
2394 assert_difference 'Issue.count' do
2371 post :create, :project_id => 1,
2395 post :create, :project_id => 1,
2372 :issue => {:tracker_id => 1,
2396 :issue => {:tracker_id => 1,
2373 :subject => 'This is a child issue',
2397 :subject => 'This is a child issue',
2374 :parent_issue_id => '#2'}
2398 :parent_issue_id => '#2'}
2375 assert_response 302
2399 assert_response 302
2376 end
2400 end
2377 issue = Issue.order('id DESC').first
2401 issue = Issue.order('id DESC').first
2378 assert_equal Issue.find(2), issue.parent
2402 assert_equal Issue.find(2), issue.parent
2379 end
2403 end
2380
2404
2381 def test_post_create_subissue_with_non_visible_parent_id_should_not_validate
2405 def test_post_create_subissue_with_non_visible_parent_id_should_not_validate
2382 @request.session[:user_id] = 2
2406 @request.session[:user_id] = 2
2383
2407
2384 assert_no_difference 'Issue.count' do
2408 assert_no_difference 'Issue.count' do
2385 post :create, :project_id => 1,
2409 post :create, :project_id => 1,
2386 :issue => {:tracker_id => 1,
2410 :issue => {:tracker_id => 1,
2387 :subject => 'This is a child issue',
2411 :subject => 'This is a child issue',
2388 :parent_issue_id => '4'}
2412 :parent_issue_id => '4'}
2389
2413
2390 assert_response :success
2414 assert_response :success
2391 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '4'
2415 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '4'
2392 assert_select_error /Parent task is invalid/i
2416 assert_select_error /Parent task is invalid/i
2393 end
2417 end
2394 end
2418 end
2395
2419
2396 def test_post_create_subissue_with_non_numeric_parent_id_should_not_validate
2420 def test_post_create_subissue_with_non_numeric_parent_id_should_not_validate
2397 @request.session[:user_id] = 2
2421 @request.session[:user_id] = 2
2398
2422
2399 assert_no_difference 'Issue.count' do
2423 assert_no_difference 'Issue.count' do
2400 post :create, :project_id => 1,
2424 post :create, :project_id => 1,
2401 :issue => {:tracker_id => 1,
2425 :issue => {:tracker_id => 1,
2402 :subject => 'This is a child issue',
2426 :subject => 'This is a child issue',
2403 :parent_issue_id => '01ABC'}
2427 :parent_issue_id => '01ABC'}
2404
2428
2405 assert_response :success
2429 assert_response :success
2406 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '01ABC'
2430 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '01ABC'
2407 assert_select_error /Parent task is invalid/i
2431 assert_select_error /Parent task is invalid/i
2408 end
2432 end
2409 end
2433 end
2410
2434
2411 def test_post_create_private
2435 def test_post_create_private
2412 @request.session[:user_id] = 2
2436 @request.session[:user_id] = 2
2413
2437
2414 assert_difference 'Issue.count' do
2438 assert_difference 'Issue.count' do
2415 post :create, :project_id => 1,
2439 post :create, :project_id => 1,
2416 :issue => {:tracker_id => 1,
2440 :issue => {:tracker_id => 1,
2417 :subject => 'This is a private issue',
2441 :subject => 'This is a private issue',
2418 :is_private => '1'}
2442 :is_private => '1'}
2419 end
2443 end
2420 issue = Issue.order('id DESC').first
2444 issue = Issue.order('id DESC').first
2421 assert issue.is_private?
2445 assert issue.is_private?
2422 end
2446 end
2423
2447
2424 def test_post_create_private_with_set_own_issues_private_permission
2448 def test_post_create_private_with_set_own_issues_private_permission
2425 role = Role.find(1)
2449 role = Role.find(1)
2426 role.remove_permission! :set_issues_private
2450 role.remove_permission! :set_issues_private
2427 role.add_permission! :set_own_issues_private
2451 role.add_permission! :set_own_issues_private
2428
2452
2429 @request.session[:user_id] = 2
2453 @request.session[:user_id] = 2
2430
2454
2431 assert_difference 'Issue.count' do
2455 assert_difference 'Issue.count' do
2432 post :create, :project_id => 1,
2456 post :create, :project_id => 1,
2433 :issue => {:tracker_id => 1,
2457 :issue => {:tracker_id => 1,
2434 :subject => 'This is a private issue',
2458 :subject => 'This is a private issue',
2435 :is_private => '1'}
2459 :is_private => '1'}
2436 end
2460 end
2437 issue = Issue.order('id DESC').first
2461 issue = Issue.order('id DESC').first
2438 assert issue.is_private?
2462 assert issue.is_private?
2439 end
2463 end
2440
2464
2441 def test_create_without_project_id
2465 def test_create_without_project_id
2442 @request.session[:user_id] = 2
2466 @request.session[:user_id] = 2
2443
2467
2444 assert_difference 'Issue.count' do
2468 assert_difference 'Issue.count' do
2445 post :create,
2469 post :create,
2446 :issue => {:project_id => 3,
2470 :issue => {:project_id => 3,
2447 :tracker_id => 2,
2471 :tracker_id => 2,
2448 :subject => 'Foo'}
2472 :subject => 'Foo'}
2449 assert_response 302
2473 assert_response 302
2450 end
2474 end
2451 issue = Issue.order('id DESC').first
2475 issue = Issue.order('id DESC').first
2452 assert_equal 3, issue.project_id
2476 assert_equal 3, issue.project_id
2453 assert_equal 2, issue.tracker_id
2477 assert_equal 2, issue.tracker_id
2454 end
2478 end
2455
2479
2456 def test_create_without_project_id_and_continue_should_redirect_without_project_id
2480 def test_create_without_project_id_and_continue_should_redirect_without_project_id
2457 @request.session[:user_id] = 2
2481 @request.session[:user_id] = 2
2458
2482
2459 assert_difference 'Issue.count' do
2483 assert_difference 'Issue.count' do
2460 post :create,
2484 post :create,
2461 :issue => {:project_id => 3,
2485 :issue => {:project_id => 3,
2462 :tracker_id => 2,
2486 :tracker_id => 2,
2463 :subject => 'Foo'},
2487 :subject => 'Foo'},
2464 :continue => '1'
2488 :continue => '1'
2465 assert_redirected_to '/issues/new?issue%5Bproject_id%5D=3&issue%5Btracker_id%5D=2'
2489 assert_redirected_to '/issues/new?issue%5Bproject_id%5D=3&issue%5Btracker_id%5D=2'
2466 end
2490 end
2467 end
2491 end
2468
2492
2469 def test_create_without_project_id_should_be_denied_without_permission
2493 def test_create_without_project_id_should_be_denied_without_permission
2470 Role.non_member.remove_permission! :add_issues
2494 Role.non_member.remove_permission! :add_issues
2471 Role.anonymous.remove_permission! :add_issues
2495 Role.anonymous.remove_permission! :add_issues
2472 @request.session[:user_id] = 2
2496 @request.session[:user_id] = 2
2473
2497
2474 assert_no_difference 'Issue.count' do
2498 assert_no_difference 'Issue.count' do
2475 post :create,
2499 post :create,
2476 :issue => {:project_id => 3,
2500 :issue => {:project_id => 3,
2477 :tracker_id => 2,
2501 :tracker_id => 2,
2478 :subject => 'Foo'}
2502 :subject => 'Foo'}
2479 assert_response 422
2503 assert_response 422
2480 end
2504 end
2481 end
2505 end
2482
2506
2483 def test_create_without_project_id_with_failure
2507 def test_create_without_project_id_with_failure
2484 @request.session[:user_id] = 2
2508 @request.session[:user_id] = 2
2485
2509
2486 post :create,
2510 post :create,
2487 :issue => {:project_id => 3,
2511 :issue => {:project_id => 3,
2488 :tracker_id => 2,
2512 :tracker_id => 2,
2489 :subject => ''}
2513 :subject => ''}
2490 assert_response :success
2514 assert_response :success
2491 assert_nil assigns(:project)
2515 assert_nil assigns(:project)
2492 end
2516 end
2493
2517
2494 def test_post_create_should_send_a_notification
2518 def test_post_create_should_send_a_notification
2495 ActionMailer::Base.deliveries.clear
2519 ActionMailer::Base.deliveries.clear
2496 @request.session[:user_id] = 2
2520 @request.session[:user_id] = 2
2497 with_settings :notified_events => %w(issue_added) do
2521 with_settings :notified_events => %w(issue_added) do
2498 assert_difference 'Issue.count' do
2522 assert_difference 'Issue.count' do
2499 post :create, :project_id => 1,
2523 post :create, :project_id => 1,
2500 :issue => {:tracker_id => 3,
2524 :issue => {:tracker_id => 3,
2501 :subject => 'This is the test_new issue',
2525 :subject => 'This is the test_new issue',
2502 :description => 'This is the description',
2526 :description => 'This is the description',
2503 :priority_id => 5,
2527 :priority_id => 5,
2504 :estimated_hours => '',
2528 :estimated_hours => '',
2505 :custom_field_values => {'2' => 'Value for field 2'}}
2529 :custom_field_values => {'2' => 'Value for field 2'}}
2506 end
2530 end
2507 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2531 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2508
2532
2509 assert_equal 1, ActionMailer::Base.deliveries.size
2533 assert_equal 1, ActionMailer::Base.deliveries.size
2510 end
2534 end
2511 end
2535 end
2512
2536
2513 def test_post_create_should_preserve_fields_values_on_validation_failure
2537 def test_post_create_should_preserve_fields_values_on_validation_failure
2514 @request.session[:user_id] = 2
2538 @request.session[:user_id] = 2
2515 post :create, :project_id => 1,
2539 post :create, :project_id => 1,
2516 :issue => {:tracker_id => 1,
2540 :issue => {:tracker_id => 1,
2517 # empty subject
2541 # empty subject
2518 :subject => '',
2542 :subject => '',
2519 :description => 'This is a description',
2543 :description => 'This is a description',
2520 :priority_id => 6,
2544 :priority_id => 6,
2521 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
2545 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
2522 assert_response :success
2546 assert_response :success
2523 assert_template 'new'
2547 assert_template 'new'
2524
2548
2525 assert_select 'textarea[name=?]', 'issue[description]', :text => 'This is a description'
2549 assert_select 'textarea[name=?]', 'issue[description]', :text => 'This is a description'
2526 assert_select 'select[name=?]', 'issue[priority_id]' do
2550 assert_select 'select[name=?]', 'issue[priority_id]' do
2527 assert_select 'option[value="6"][selected=selected]', :text => 'High'
2551 assert_select 'option[value="6"][selected=selected]', :text => 'High'
2528 end
2552 end
2529 # Custom fields
2553 # Custom fields
2530 assert_select 'select[name=?]', 'issue[custom_field_values][1]' do
2554 assert_select 'select[name=?]', 'issue[custom_field_values][1]' do
2531 assert_select 'option[value=Oracle][selected=selected]', :text => 'Oracle'
2555 assert_select 'option[value=Oracle][selected=selected]', :text => 'Oracle'
2532 end
2556 end
2533 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Value for field 2'
2557 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Value for field 2'
2534 end
2558 end
2535
2559
2536 def test_post_create_with_failure_should_preserve_watchers
2560 def test_post_create_with_failure_should_preserve_watchers
2537 assert !User.find(8).member_of?(Project.find(1))
2561 assert !User.find(8).member_of?(Project.find(1))
2538
2562
2539 @request.session[:user_id] = 2
2563 @request.session[:user_id] = 2
2540 post :create, :project_id => 1,
2564 post :create, :project_id => 1,
2541 :issue => {:tracker_id => 1,
2565 :issue => {:tracker_id => 1,
2542 :watcher_user_ids => ['3', '8']}
2566 :watcher_user_ids => ['3', '8']}
2543 assert_response :success
2567 assert_response :success
2544 assert_template 'new'
2568 assert_template 'new'
2545
2569
2546 assert_select 'input[name=?][value="2"]:not(checked)', 'issue[watcher_user_ids][]'
2570 assert_select 'input[name=?][value="2"]:not(checked)', 'issue[watcher_user_ids][]'
2547 assert_select 'input[name=?][value="3"][checked=checked]', 'issue[watcher_user_ids][]'
2571 assert_select 'input[name=?][value="3"][checked=checked]', 'issue[watcher_user_ids][]'
2548 assert_select 'input[name=?][value="8"][checked=checked]', 'issue[watcher_user_ids][]'
2572 assert_select 'input[name=?][value="8"][checked=checked]', 'issue[watcher_user_ids][]'
2549 end
2573 end
2550
2574
2551 def test_post_create_should_ignore_non_safe_attributes
2575 def test_post_create_should_ignore_non_safe_attributes
2552 @request.session[:user_id] = 2
2576 @request.session[:user_id] = 2
2553 assert_nothing_raised do
2577 assert_nothing_raised do
2554 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
2578 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
2555 end
2579 end
2556 end
2580 end
2557
2581
2558 def test_post_create_with_attachment
2582 def test_post_create_with_attachment
2559 set_tmp_attachments_directory
2583 set_tmp_attachments_directory
2560 @request.session[:user_id] = 2
2584 @request.session[:user_id] = 2
2561
2585
2562 assert_difference 'Issue.count' do
2586 assert_difference 'Issue.count' do
2563 assert_difference 'Attachment.count' do
2587 assert_difference 'Attachment.count' do
2564 assert_no_difference 'Journal.count' do
2588 assert_no_difference 'Journal.count' do
2565 post :create, :project_id => 1,
2589 post :create, :project_id => 1,
2566 :issue => { :tracker_id => '1', :subject => 'With attachment' },
2590 :issue => { :tracker_id => '1', :subject => 'With attachment' },
2567 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2591 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2568 end
2592 end
2569 end
2593 end
2570 end
2594 end
2571
2595
2572 issue = Issue.order('id DESC').first
2596 issue = Issue.order('id DESC').first
2573 attachment = Attachment.order('id DESC').first
2597 attachment = Attachment.order('id DESC').first
2574
2598
2575 assert_equal issue, attachment.container
2599 assert_equal issue, attachment.container
2576 assert_equal 2, attachment.author_id
2600 assert_equal 2, attachment.author_id
2577 assert_equal 'testfile.txt', attachment.filename
2601 assert_equal 'testfile.txt', attachment.filename
2578 assert_equal 'text/plain', attachment.content_type
2602 assert_equal 'text/plain', attachment.content_type
2579 assert_equal 'test file', attachment.description
2603 assert_equal 'test file', attachment.description
2580 assert_equal 59, attachment.filesize
2604 assert_equal 59, attachment.filesize
2581 assert File.exists?(attachment.diskfile)
2605 assert File.exists?(attachment.diskfile)
2582 assert_equal 59, File.size(attachment.diskfile)
2606 assert_equal 59, File.size(attachment.diskfile)
2583 end
2607 end
2584
2608
2585 def test_post_create_with_attachment_should_notify_with_attachments
2609 def test_post_create_with_attachment_should_notify_with_attachments
2586 ActionMailer::Base.deliveries.clear
2610 ActionMailer::Base.deliveries.clear
2587 set_tmp_attachments_directory
2611 set_tmp_attachments_directory
2588 @request.session[:user_id] = 2
2612 @request.session[:user_id] = 2
2589
2613
2590 with_settings :notified_events => %w(issue_added) do
2614 with_settings :notified_events => %w(issue_added) do
2591 assert_difference 'Issue.count' do
2615 assert_difference 'Issue.count' do
2592 post :create, :project_id => 1,
2616 post :create, :project_id => 1,
2593 :issue => { :tracker_id => '1', :subject => 'With attachment' },
2617 :issue => { :tracker_id => '1', :subject => 'With attachment' },
2594 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2618 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2595 end
2619 end
2596 end
2620 end
2597
2621
2598 assert_not_nil ActionMailer::Base.deliveries.last
2622 assert_not_nil ActionMailer::Base.deliveries.last
2599 assert_select_email do
2623 assert_select_email do
2600 assert_select 'a[href^=?]', 'http://localhost:3000/attachments/download', 'testfile.txt'
2624 assert_select 'a[href^=?]', 'http://localhost:3000/attachments/download', 'testfile.txt'
2601 end
2625 end
2602 end
2626 end
2603
2627
2604 def test_post_create_with_failure_should_save_attachments
2628 def test_post_create_with_failure_should_save_attachments
2605 set_tmp_attachments_directory
2629 set_tmp_attachments_directory
2606 @request.session[:user_id] = 2
2630 @request.session[:user_id] = 2
2607
2631
2608 assert_no_difference 'Issue.count' do
2632 assert_no_difference 'Issue.count' do
2609 assert_difference 'Attachment.count' do
2633 assert_difference 'Attachment.count' do
2610 post :create, :project_id => 1,
2634 post :create, :project_id => 1,
2611 :issue => { :tracker_id => '1', :subject => '' },
2635 :issue => { :tracker_id => '1', :subject => '' },
2612 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2636 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2613 assert_response :success
2637 assert_response :success
2614 assert_template 'new'
2638 assert_template 'new'
2615 end
2639 end
2616 end
2640 end
2617
2641
2618 attachment = Attachment.order('id DESC').first
2642 attachment = Attachment.order('id DESC').first
2619 assert_equal 'testfile.txt', attachment.filename
2643 assert_equal 'testfile.txt', attachment.filename
2620 assert File.exists?(attachment.diskfile)
2644 assert File.exists?(attachment.diskfile)
2621 assert_nil attachment.container
2645 assert_nil attachment.container
2622
2646
2623 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2647 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2624 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2648 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2625 end
2649 end
2626
2650
2627 def test_post_create_with_failure_should_keep_saved_attachments
2651 def test_post_create_with_failure_should_keep_saved_attachments
2628 set_tmp_attachments_directory
2652 set_tmp_attachments_directory
2629 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2653 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2630 @request.session[:user_id] = 2
2654 @request.session[:user_id] = 2
2631
2655
2632 assert_no_difference 'Issue.count' do
2656 assert_no_difference 'Issue.count' do
2633 assert_no_difference 'Attachment.count' do
2657 assert_no_difference 'Attachment.count' do
2634 post :create, :project_id => 1,
2658 post :create, :project_id => 1,
2635 :issue => { :tracker_id => '1', :subject => '' },
2659 :issue => { :tracker_id => '1', :subject => '' },
2636 :attachments => {'p0' => {'token' => attachment.token}}
2660 :attachments => {'p0' => {'token' => attachment.token}}
2637 assert_response :success
2661 assert_response :success
2638 assert_template 'new'
2662 assert_template 'new'
2639 end
2663 end
2640 end
2664 end
2641
2665
2642 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2666 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2643 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2667 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2644 end
2668 end
2645
2669
2646 def test_post_create_should_attach_saved_attachments
2670 def test_post_create_should_attach_saved_attachments
2647 set_tmp_attachments_directory
2671 set_tmp_attachments_directory
2648 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2672 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2649 @request.session[:user_id] = 2
2673 @request.session[:user_id] = 2
2650
2674
2651 assert_difference 'Issue.count' do
2675 assert_difference 'Issue.count' do
2652 assert_no_difference 'Attachment.count' do
2676 assert_no_difference 'Attachment.count' do
2653 post :create, :project_id => 1,
2677 post :create, :project_id => 1,
2654 :issue => { :tracker_id => '1', :subject => 'Saved attachments' },
2678 :issue => { :tracker_id => '1', :subject => 'Saved attachments' },
2655 :attachments => {'p0' => {'token' => attachment.token}}
2679 :attachments => {'p0' => {'token' => attachment.token}}
2656 assert_response 302
2680 assert_response 302
2657 end
2681 end
2658 end
2682 end
2659
2683
2660 issue = Issue.order('id DESC').first
2684 issue = Issue.order('id DESC').first
2661 assert_equal 1, issue.attachments.count
2685 assert_equal 1, issue.attachments.count
2662
2686
2663 attachment.reload
2687 attachment.reload
2664 assert_equal issue, attachment.container
2688 assert_equal issue, attachment.container
2665 end
2689 end
2666
2690
2667 def setup_without_workflow_privilege
2691 def setup_without_workflow_privilege
2668 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2692 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2669 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2693 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2670 end
2694 end
2671 private :setup_without_workflow_privilege
2695 private :setup_without_workflow_privilege
2672
2696
2673 test "without workflow privilege #new should propose default status only" do
2697 test "without workflow privilege #new should propose default status only" do
2674 setup_without_workflow_privilege
2698 setup_without_workflow_privilege
2675 get :new, :project_id => 1
2699 get :new, :project_id => 1
2676 assert_response :success
2700 assert_response :success
2677 assert_template 'new'
2701 assert_template 'new'
2678
2702
2679 issue = assigns(:issue)
2703 issue = assigns(:issue)
2680 assert_not_nil issue.default_status
2704 assert_not_nil issue.default_status
2681
2705
2682 assert_select 'select[name=?]', 'issue[status_id]' do
2706 assert_select 'select[name=?]', 'issue[status_id]' do
2683 assert_select 'option', 1
2707 assert_select 'option', 1
2684 assert_select 'option[value=?]', issue.default_status.id.to_s
2708 assert_select 'option[value=?]', issue.default_status.id.to_s
2685 end
2709 end
2686 end
2710 end
2687
2711
2688 test "without workflow privilege #create should accept default status" do
2712 test "without workflow privilege #create should accept default status" do
2689 setup_without_workflow_privilege
2713 setup_without_workflow_privilege
2690 assert_difference 'Issue.count' do
2714 assert_difference 'Issue.count' do
2691 post :create, :project_id => 1,
2715 post :create, :project_id => 1,
2692 :issue => {:tracker_id => 1,
2716 :issue => {:tracker_id => 1,
2693 :subject => 'This is an issue',
2717 :subject => 'This is an issue',
2694 :status_id => 1}
2718 :status_id => 1}
2695 end
2719 end
2696 issue = Issue.order('id').last
2720 issue = Issue.order('id').last
2697 assert_not_nil issue.default_status
2721 assert_not_nil issue.default_status
2698 assert_equal issue.default_status, issue.status
2722 assert_equal issue.default_status, issue.status
2699 end
2723 end
2700
2724
2701 test "without workflow privilege #create should ignore unauthorized status" do
2725 test "without workflow privilege #create should ignore unauthorized status" do
2702 setup_without_workflow_privilege
2726 setup_without_workflow_privilege
2703 assert_difference 'Issue.count' do
2727 assert_difference 'Issue.count' do
2704 post :create, :project_id => 1,
2728 post :create, :project_id => 1,
2705 :issue => {:tracker_id => 1,
2729 :issue => {:tracker_id => 1,
2706 :subject => 'This is an issue',
2730 :subject => 'This is an issue',
2707 :status_id => 3}
2731 :status_id => 3}
2708 end
2732 end
2709 issue = Issue.order('id').last
2733 issue = Issue.order('id').last
2710 assert_not_nil issue.default_status
2734 assert_not_nil issue.default_status
2711 assert_equal issue.default_status, issue.status
2735 assert_equal issue.default_status, issue.status
2712 end
2736 end
2713
2737
2714 test "without workflow privilege #update should ignore status change" do
2738 test "without workflow privilege #update should ignore status change" do
2715 setup_without_workflow_privilege
2739 setup_without_workflow_privilege
2716 assert_difference 'Journal.count' do
2740 assert_difference 'Journal.count' do
2717 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2741 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2718 end
2742 end
2719 assert_equal 1, Issue.find(1).status_id
2743 assert_equal 1, Issue.find(1).status_id
2720 end
2744 end
2721
2745
2722 test "without workflow privilege #update ignore attributes changes" do
2746 test "without workflow privilege #update ignore attributes changes" do
2723 setup_without_workflow_privilege
2747 setup_without_workflow_privilege
2724 assert_difference 'Journal.count' do
2748 assert_difference 'Journal.count' do
2725 put :update, :id => 1,
2749 put :update, :id => 1,
2726 :issue => {:subject => 'changed', :assigned_to_id => 2,
2750 :issue => {:subject => 'changed', :assigned_to_id => 2,
2727 :notes => 'just trying'}
2751 :notes => 'just trying'}
2728 end
2752 end
2729 issue = Issue.find(1)
2753 issue = Issue.find(1)
2730 assert_equal "Cannot print recipes", issue.subject
2754 assert_equal "Cannot print recipes", issue.subject
2731 assert_nil issue.assigned_to
2755 assert_nil issue.assigned_to
2732 end
2756 end
2733
2757
2734 def setup_with_workflow_privilege
2758 def setup_with_workflow_privilege
2735 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2759 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2736 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
2760 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
2737 :old_status_id => 1, :new_status_id => 3)
2761 :old_status_id => 1, :new_status_id => 3)
2738 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
2762 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
2739 :old_status_id => 1, :new_status_id => 4)
2763 :old_status_id => 1, :new_status_id => 4)
2740 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2764 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2741 end
2765 end
2742 private :setup_with_workflow_privilege
2766 private :setup_with_workflow_privilege
2743
2767
2744 def setup_with_workflow_privilege_and_edit_issues_permission
2768 def setup_with_workflow_privilege_and_edit_issues_permission
2745 setup_with_workflow_privilege
2769 setup_with_workflow_privilege
2746 Role.anonymous.add_permission! :add_issues, :edit_issues
2770 Role.anonymous.add_permission! :add_issues, :edit_issues
2747 end
2771 end
2748 private :setup_with_workflow_privilege_and_edit_issues_permission
2772 private :setup_with_workflow_privilege_and_edit_issues_permission
2749
2773
2750 test "with workflow privilege and :edit_issues permission should accept authorized status" do
2774 test "with workflow privilege and :edit_issues permission should accept authorized status" do
2751 setup_with_workflow_privilege_and_edit_issues_permission
2775 setup_with_workflow_privilege_and_edit_issues_permission
2752 assert_difference 'Journal.count' do
2776 assert_difference 'Journal.count' do
2753 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2777 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2754 end
2778 end
2755 assert_equal 3, Issue.find(1).status_id
2779 assert_equal 3, Issue.find(1).status_id
2756 end
2780 end
2757
2781
2758 test "with workflow privilege and :edit_issues permission should ignore unauthorized status" do
2782 test "with workflow privilege and :edit_issues permission should ignore unauthorized status" do
2759 setup_with_workflow_privilege_and_edit_issues_permission
2783 setup_with_workflow_privilege_and_edit_issues_permission
2760 assert_difference 'Journal.count' do
2784 assert_difference 'Journal.count' do
2761 put :update, :id => 1, :issue => {:status_id => 2, :notes => 'just trying'}
2785 put :update, :id => 1, :issue => {:status_id => 2, :notes => 'just trying'}
2762 end
2786 end
2763 assert_equal 1, Issue.find(1).status_id
2787 assert_equal 1, Issue.find(1).status_id
2764 end
2788 end
2765
2789
2766 test "with workflow privilege and :edit_issues permission should accept authorized attributes changes" do
2790 test "with workflow privilege and :edit_issues permission should accept authorized attributes changes" do
2767 setup_with_workflow_privilege_and_edit_issues_permission
2791 setup_with_workflow_privilege_and_edit_issues_permission
2768 assert_difference 'Journal.count' do
2792 assert_difference 'Journal.count' do
2769 put :update, :id => 1,
2793 put :update, :id => 1,
2770 :issue => {:subject => 'changed', :assigned_to_id => 2,
2794 :issue => {:subject => 'changed', :assigned_to_id => 2,
2771 :notes => 'just trying'}
2795 :notes => 'just trying'}
2772 end
2796 end
2773 issue = Issue.find(1)
2797 issue = Issue.find(1)
2774 assert_equal "changed", issue.subject
2798 assert_equal "changed", issue.subject
2775 assert_equal 2, issue.assigned_to_id
2799 assert_equal 2, issue.assigned_to_id
2776 end
2800 end
2777
2801
2778 def test_new_as_copy
2802 def test_new_as_copy
2779 @request.session[:user_id] = 2
2803 @request.session[:user_id] = 2
2780 get :new, :project_id => 1, :copy_from => 1
2804 get :new, :project_id => 1, :copy_from => 1
2781
2805
2782 assert_response :success
2806 assert_response :success
2783 assert_template 'new'
2807 assert_template 'new'
2784
2808
2785 assert_not_nil assigns(:issue)
2809 assert_not_nil assigns(:issue)
2786 orig = Issue.find(1)
2810 orig = Issue.find(1)
2787 assert_equal 1, assigns(:issue).project_id
2811 assert_equal 1, assigns(:issue).project_id
2788 assert_equal orig.subject, assigns(:issue).subject
2812 assert_equal orig.subject, assigns(:issue).subject
2789 assert assigns(:issue).copy?
2813 assert assigns(:issue).copy?
2790
2814
2791 assert_select 'form[id=issue-form][action="/projects/ecookbook/issues"]' do
2815 assert_select 'form[id=issue-form][action="/projects/ecookbook/issues"]' do
2792 assert_select 'select[name=?]', 'issue[project_id]' do
2816 assert_select 'select[name=?]', 'issue[project_id]' do
2793 assert_select 'option[value="1"][selected=selected]', :text => 'eCookbook'
2817 assert_select 'option[value="1"][selected=selected]', :text => 'eCookbook'
2794 assert_select 'option[value="2"]:not([selected])', :text => 'OnlineStore'
2818 assert_select 'option[value="2"]:not([selected])', :text => 'OnlineStore'
2795 end
2819 end
2796 assert_select 'input[name=copy_from][value="1"]'
2820 assert_select 'input[name=copy_from][value="1"]'
2797 end
2821 end
2798
2799 # "New issue" menu item should not link to copy
2800 assert_select '#main-menu a.new-issue[href="/projects/ecookbook/issues/new"]'
2801 end
2822 end
2802
2823
2803 def test_new_as_copy_without_add_issues_permission_should_not_propose_current_project_as_target
2824 def test_new_as_copy_without_add_issues_permission_should_not_propose_current_project_as_target
2804 user = setup_user_with_copy_but_not_add_permission
2825 user = setup_user_with_copy_but_not_add_permission
2805
2826
2806 @request.session[:user_id] = user.id
2827 @request.session[:user_id] = user.id
2807 get :new, :project_id => 1, :copy_from => 1
2828 get :new, :project_id => 1, :copy_from => 1
2808
2829
2809 assert_response :success
2830 assert_response :success
2810 assert_template 'new'
2831 assert_template 'new'
2811 assert_select 'select[name=?]', 'issue[project_id]' do
2832 assert_select 'select[name=?]', 'issue[project_id]' do
2812 assert_select 'option[value="1"]', 0
2833 assert_select 'option[value="1"]', 0
2813 assert_select 'option[value="2"]', :text => 'OnlineStore'
2834 assert_select 'option[value="2"]', :text => 'OnlineStore'
2814 end
2835 end
2815 end
2836 end
2816
2837
2817 def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
2838 def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
2818 @request.session[:user_id] = 2
2839 @request.session[:user_id] = 2
2819 issue = Issue.find(3)
2840 issue = Issue.find(3)
2820 assert issue.attachments.count > 0
2841 assert issue.attachments.count > 0
2821 get :new, :project_id => 1, :copy_from => 3
2842 get :new, :project_id => 1, :copy_from => 3
2822
2843
2823 assert_select 'input[name=copy_attachments][type=checkbox][checked=checked][value="1"]'
2844 assert_select 'input[name=copy_attachments][type=checkbox][checked=checked][value="1"]'
2824 end
2845 end
2825
2846
2826 def test_new_as_copy_without_attachments_should_not_show_copy_attachments_checkbox
2847 def test_new_as_copy_without_attachments_should_not_show_copy_attachments_checkbox
2827 @request.session[:user_id] = 2
2848 @request.session[:user_id] = 2
2828 issue = Issue.find(3)
2849 issue = Issue.find(3)
2829 issue.attachments.delete_all
2850 issue.attachments.delete_all
2830 get :new, :project_id => 1, :copy_from => 3
2851 get :new, :project_id => 1, :copy_from => 3
2831
2852
2832 assert_select 'input[name=copy_attachments]', 0
2853 assert_select 'input[name=copy_attachments]', 0
2833 end
2854 end
2834
2855
2835 def test_new_as_copy_should_preserve_parent_id
2856 def test_new_as_copy_should_preserve_parent_id
2836 @request.session[:user_id] = 2
2857 @request.session[:user_id] = 2
2837 issue = Issue.generate!(:parent_issue_id => 2)
2858 issue = Issue.generate!(:parent_issue_id => 2)
2838 get :new, :project_id => 1, :copy_from => issue.id
2859 get :new, :project_id => 1, :copy_from => issue.id
2839
2860
2840 assert_select 'input[name=?][value="2"]', 'issue[parent_issue_id]'
2861 assert_select 'input[name=?][value="2"]', 'issue[parent_issue_id]'
2841 end
2862 end
2842
2863
2843 def test_new_as_copy_with_subtasks_should_show_copy_subtasks_checkbox
2864 def test_new_as_copy_with_subtasks_should_show_copy_subtasks_checkbox
2844 @request.session[:user_id] = 2
2865 @request.session[:user_id] = 2
2845 issue = Issue.generate_with_descendants!
2866 issue = Issue.generate_with_descendants!
2846 get :new, :project_id => 1, :copy_from => issue.id
2867 get :new, :project_id => 1, :copy_from => issue.id
2847
2868
2848 assert_select 'input[type=checkbox][name=copy_subtasks][checked=checked][value="1"]'
2869 assert_select 'input[type=checkbox][name=copy_subtasks][checked=checked][value="1"]'
2849 end
2870 end
2850
2871
2851 def test_new_as_copy_with_invalid_issue_should_respond_with_404
2872 def test_new_as_copy_with_invalid_issue_should_respond_with_404
2852 @request.session[:user_id] = 2
2873 @request.session[:user_id] = 2
2853 get :new, :project_id => 1, :copy_from => 99999
2874 get :new, :project_id => 1, :copy_from => 99999
2854 assert_response 404
2875 assert_response 404
2855 end
2876 end
2856
2877
2857 def test_create_as_copy_on_different_project
2878 def test_create_as_copy_on_different_project
2858 @request.session[:user_id] = 2
2879 @request.session[:user_id] = 2
2859 assert_difference 'Issue.count' do
2880 assert_difference 'Issue.count' do
2860 post :create, :project_id => 1, :copy_from => 1,
2881 post :create, :project_id => 1, :copy_from => 1,
2861 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2882 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2862
2883
2863 assert_not_nil assigns(:issue)
2884 assert_not_nil assigns(:issue)
2864 assert assigns(:issue).copy?
2885 assert assigns(:issue).copy?
2865 end
2886 end
2866 issue = Issue.order('id DESC').first
2887 issue = Issue.order('id DESC').first
2867 assert_redirected_to "/issues/#{issue.id}"
2888 assert_redirected_to "/issues/#{issue.id}"
2868
2889
2869 assert_equal 2, issue.project_id
2890 assert_equal 2, issue.project_id
2870 assert_equal 3, issue.tracker_id
2891 assert_equal 3, issue.tracker_id
2871 assert_equal 'Copy', issue.subject
2892 assert_equal 'Copy', issue.subject
2872 end
2893 end
2873
2894
2874 def test_create_as_copy_should_allow_status_to_be_set_to_default
2895 def test_create_as_copy_should_allow_status_to_be_set_to_default
2875 copied = Issue.generate! :status_id => 2
2896 copied = Issue.generate! :status_id => 2
2876 assert_equal 2, copied.reload.status_id
2897 assert_equal 2, copied.reload.status_id
2877
2898
2878 @request.session[:user_id] = 2
2899 @request.session[:user_id] = 2
2879 assert_difference 'Issue.count' do
2900 assert_difference 'Issue.count' do
2880 post :create, :project_id => 1, :copy_from => copied.id,
2901 post :create, :project_id => 1, :copy_from => copied.id,
2881 :issue => {:project_id => '1', :tracker_id => '1', :status_id => '1'},
2902 :issue => {:project_id => '1', :tracker_id => '1', :status_id => '1'},
2882 :was_default_status => '1'
2903 :was_default_status => '1'
2883 end
2904 end
2884 issue = Issue.order('id DESC').first
2905 issue = Issue.order('id DESC').first
2885 assert_equal 1, issue.status_id
2906 assert_equal 1, issue.status_id
2886 end
2907 end
2887
2908
2888 def test_create_as_copy_should_copy_attachments
2909 def test_create_as_copy_should_copy_attachments
2889 @request.session[:user_id] = 2
2910 @request.session[:user_id] = 2
2890 issue = Issue.find(3)
2911 issue = Issue.find(3)
2891 count = issue.attachments.count
2912 count = issue.attachments.count
2892 assert count > 0
2913 assert count > 0
2893 assert_difference 'Issue.count' do
2914 assert_difference 'Issue.count' do
2894 assert_difference 'Attachment.count', count do
2915 assert_difference 'Attachment.count', count do
2895 post :create, :project_id => 1, :copy_from => 3,
2916 post :create, :project_id => 1, :copy_from => 3,
2896 :issue => {:project_id => '1', :tracker_id => '3',
2917 :issue => {:project_id => '1', :tracker_id => '3',
2897 :status_id => '1', :subject => 'Copy with attachments'},
2918 :status_id => '1', :subject => 'Copy with attachments'},
2898 :copy_attachments => '1'
2919 :copy_attachments => '1'
2899 end
2920 end
2900 end
2921 end
2901 copy = Issue.order('id DESC').first
2922 copy = Issue.order('id DESC').first
2902 assert_equal count, copy.attachments.count
2923 assert_equal count, copy.attachments.count
2903 assert_equal issue.attachments.map(&:filename).sort, copy.attachments.map(&:filename).sort
2924 assert_equal issue.attachments.map(&:filename).sort, copy.attachments.map(&:filename).sort
2904 end
2925 end
2905
2926
2906 def test_create_as_copy_without_copy_attachments_option_should_not_copy_attachments
2927 def test_create_as_copy_without_copy_attachments_option_should_not_copy_attachments
2907 @request.session[:user_id] = 2
2928 @request.session[:user_id] = 2
2908 issue = Issue.find(3)
2929 issue = Issue.find(3)
2909 count = issue.attachments.count
2930 count = issue.attachments.count
2910 assert count > 0
2931 assert count > 0
2911 assert_difference 'Issue.count' do
2932 assert_difference 'Issue.count' do
2912 assert_no_difference 'Attachment.count' do
2933 assert_no_difference 'Attachment.count' do
2913 post :create, :project_id => 1, :copy_from => 3,
2934 post :create, :project_id => 1, :copy_from => 3,
2914 :issue => {:project_id => '1', :tracker_id => '3',
2935 :issue => {:project_id => '1', :tracker_id => '3',
2915 :status_id => '1', :subject => 'Copy with attachments'}
2936 :status_id => '1', :subject => 'Copy with attachments'}
2916 end
2937 end
2917 end
2938 end
2918 copy = Issue.order('id DESC').first
2939 copy = Issue.order('id DESC').first
2919 assert_equal 0, copy.attachments.count
2940 assert_equal 0, copy.attachments.count
2920 end
2941 end
2921
2942
2922 def test_create_as_copy_with_attachments_should_also_add_new_files
2943 def test_create_as_copy_with_attachments_should_also_add_new_files
2923 @request.session[:user_id] = 2
2944 @request.session[:user_id] = 2
2924 issue = Issue.find(3)
2945 issue = Issue.find(3)
2925 count = issue.attachments.count
2946 count = issue.attachments.count
2926 assert count > 0
2947 assert count > 0
2927 assert_difference 'Issue.count' do
2948 assert_difference 'Issue.count' do
2928 assert_difference 'Attachment.count', count + 1 do
2949 assert_difference 'Attachment.count', count + 1 do
2929 post :create, :project_id => 1, :copy_from => 3,
2950 post :create, :project_id => 1, :copy_from => 3,
2930 :issue => {:project_id => '1', :tracker_id => '3',
2951 :issue => {:project_id => '1', :tracker_id => '3',
2931 :status_id => '1', :subject => 'Copy with attachments'},
2952 :status_id => '1', :subject => 'Copy with attachments'},
2932 :copy_attachments => '1',
2953 :copy_attachments => '1',
2933 :attachments => {'1' =>
2954 :attachments => {'1' =>
2934 {'file' => uploaded_test_file('testfile.txt', 'text/plain'),
2955 {'file' => uploaded_test_file('testfile.txt', 'text/plain'),
2935 'description' => 'test file'}}
2956 'description' => 'test file'}}
2936 end
2957 end
2937 end
2958 end
2938 copy = Issue.order('id DESC').first
2959 copy = Issue.order('id DESC').first
2939 assert_equal count + 1, copy.attachments.count
2960 assert_equal count + 1, copy.attachments.count
2940 end
2961 end
2941
2962
2942 def test_create_as_copy_should_add_relation_with_copied_issue
2963 def test_create_as_copy_should_add_relation_with_copied_issue
2943 @request.session[:user_id] = 2
2964 @request.session[:user_id] = 2
2944 assert_difference 'Issue.count' do
2965 assert_difference 'Issue.count' do
2945 assert_difference 'IssueRelation.count' do
2966 assert_difference 'IssueRelation.count' do
2946 post :create, :project_id => 1, :copy_from => 1, :link_copy => '1',
2967 post :create, :project_id => 1, :copy_from => 1, :link_copy => '1',
2947 :issue => {:project_id => '1', :tracker_id => '3',
2968 :issue => {:project_id => '1', :tracker_id => '3',
2948 :status_id => '1', :subject => 'Copy'}
2969 :status_id => '1', :subject => 'Copy'}
2949 end
2970 end
2950 end
2971 end
2951 copy = Issue.order('id DESC').first
2972 copy = Issue.order('id DESC').first
2952 assert_equal 1, copy.relations.size
2973 assert_equal 1, copy.relations.size
2953 end
2974 end
2954
2975
2955 def test_create_as_copy_should_allow_not_to_add_relation_with_copied_issue
2976 def test_create_as_copy_should_allow_not_to_add_relation_with_copied_issue
2956 @request.session[:user_id] = 2
2977 @request.session[:user_id] = 2
2957 assert_difference 'Issue.count' do
2978 assert_difference 'Issue.count' do
2958 assert_no_difference 'IssueRelation.count' do
2979 assert_no_difference 'IssueRelation.count' do
2959 post :create, :project_id => 1, :copy_from => 1,
2980 post :create, :project_id => 1, :copy_from => 1,
2960 :issue => {:subject => 'Copy'}
2981 :issue => {:subject => 'Copy'}
2961 end
2982 end
2962 end
2983 end
2963 end
2984 end
2964
2985
2965 def test_create_as_copy_should_always_add_relation_with_copied_issue_by_setting
2986 def test_create_as_copy_should_always_add_relation_with_copied_issue_by_setting
2966 with_settings :link_copied_issue => 'yes' do
2987 with_settings :link_copied_issue => 'yes' do
2967 @request.session[:user_id] = 2
2988 @request.session[:user_id] = 2
2968 assert_difference 'Issue.count' do
2989 assert_difference 'Issue.count' do
2969 assert_difference 'IssueRelation.count' do
2990 assert_difference 'IssueRelation.count' do
2970 post :create, :project_id => 1, :copy_from => 1,
2991 post :create, :project_id => 1, :copy_from => 1,
2971 :issue => {:subject => 'Copy'}
2992 :issue => {:subject => 'Copy'}
2972 end
2993 end
2973 end
2994 end
2974 end
2995 end
2975 end
2996 end
2976
2997
2977 def test_create_as_copy_should_never_add_relation_with_copied_issue_by_setting
2998 def test_create_as_copy_should_never_add_relation_with_copied_issue_by_setting
2978 with_settings :link_copied_issue => 'no' do
2999 with_settings :link_copied_issue => 'no' do
2979 @request.session[:user_id] = 2
3000 @request.session[:user_id] = 2
2980 assert_difference 'Issue.count' do
3001 assert_difference 'Issue.count' do
2981 assert_no_difference 'IssueRelation.count' do
3002 assert_no_difference 'IssueRelation.count' do
2982 post :create, :project_id => 1, :copy_from => 1, :link_copy => '1',
3003 post :create, :project_id => 1, :copy_from => 1, :link_copy => '1',
2983 :issue => {:subject => 'Copy'}
3004 :issue => {:subject => 'Copy'}
2984 end
3005 end
2985 end
3006 end
2986 end
3007 end
2987 end
3008 end
2988
3009
2989 def test_create_as_copy_should_copy_subtasks
3010 def test_create_as_copy_should_copy_subtasks
2990 @request.session[:user_id] = 2
3011 @request.session[:user_id] = 2
2991 issue = Issue.generate_with_descendants!
3012 issue = Issue.generate_with_descendants!
2992 count = issue.descendants.count
3013 count = issue.descendants.count
2993 assert_difference 'Issue.count', count + 1 do
3014 assert_difference 'Issue.count', count + 1 do
2994 post :create, :project_id => 1, :copy_from => issue.id,
3015 post :create, :project_id => 1, :copy_from => issue.id,
2995 :issue => {:project_id => '1', :tracker_id => '3',
3016 :issue => {:project_id => '1', :tracker_id => '3',
2996 :status_id => '1', :subject => 'Copy with subtasks'},
3017 :status_id => '1', :subject => 'Copy with subtasks'},
2997 :copy_subtasks => '1'
3018 :copy_subtasks => '1'
2998 end
3019 end
2999 copy = Issue.where(:parent_id => nil).order('id DESC').first
3020 copy = Issue.where(:parent_id => nil).order('id DESC').first
3000 assert_equal count, copy.descendants.count
3021 assert_equal count, copy.descendants.count
3001 assert_equal issue.descendants.map(&:subject).sort, copy.descendants.map(&:subject).sort
3022 assert_equal issue.descendants.map(&:subject).sort, copy.descendants.map(&:subject).sort
3002 end
3023 end
3003
3024
3004 def test_create_as_copy_to_a_different_project_should_copy_subtask_custom_fields
3025 def test_create_as_copy_to_a_different_project_should_copy_subtask_custom_fields
3005 issue = Issue.generate! {|i| i.custom_field_values = {'2' => 'Foo'}}
3026 issue = Issue.generate! {|i| i.custom_field_values = {'2' => 'Foo'}}
3006 child = Issue.generate!(:parent_issue_id => issue.id) {|i| i.custom_field_values = {'2' => 'Bar'}}
3027 child = Issue.generate!(:parent_issue_id => issue.id) {|i| i.custom_field_values = {'2' => 'Bar'}}
3007 @request.session[:user_id] = 1
3028 @request.session[:user_id] = 1
3008
3029
3009 assert_difference 'Issue.count', 2 do
3030 assert_difference 'Issue.count', 2 do
3010 post :create, :project_id => 'ecookbook', :copy_from => issue.id,
3031 post :create, :project_id => 'ecookbook', :copy_from => issue.id,
3011 :issue => {:project_id => '2', :tracker_id => 1, :status_id => '1',
3032 :issue => {:project_id => '2', :tracker_id => 1, :status_id => '1',
3012 :subject => 'Copy with subtasks', :custom_field_values => {'2' => 'Foo'}},
3033 :subject => 'Copy with subtasks', :custom_field_values => {'2' => 'Foo'}},
3013 :copy_subtasks => '1'
3034 :copy_subtasks => '1'
3014 end
3035 end
3015
3036
3016 child_copy, issue_copy = Issue.order(:id => :desc).limit(2).to_a
3037 child_copy, issue_copy = Issue.order(:id => :desc).limit(2).to_a
3017 assert_equal 2, issue_copy.project_id
3038 assert_equal 2, issue_copy.project_id
3018 assert_equal 'Foo', issue_copy.custom_field_value(2)
3039 assert_equal 'Foo', issue_copy.custom_field_value(2)
3019 assert_equal 'Bar', child_copy.custom_field_value(2)
3040 assert_equal 'Bar', child_copy.custom_field_value(2)
3020 end
3041 end
3021
3042
3022 def test_create_as_copy_without_copy_subtasks_option_should_not_copy_subtasks
3043 def test_create_as_copy_without_copy_subtasks_option_should_not_copy_subtasks
3023 @request.session[:user_id] = 2
3044 @request.session[:user_id] = 2
3024 issue = Issue.generate_with_descendants!
3045 issue = Issue.generate_with_descendants!
3025 assert_difference 'Issue.count', 1 do
3046 assert_difference 'Issue.count', 1 do
3026 post :create, :project_id => 1, :copy_from => 3,
3047 post :create, :project_id => 1, :copy_from => 3,
3027 :issue => {:project_id => '1', :tracker_id => '3',
3048 :issue => {:project_id => '1', :tracker_id => '3',
3028 :status_id => '1', :subject => 'Copy with subtasks'}
3049 :status_id => '1', :subject => 'Copy with subtasks'}
3029 end
3050 end
3030 copy = Issue.where(:parent_id => nil).order('id DESC').first
3051 copy = Issue.where(:parent_id => nil).order('id DESC').first
3031 assert_equal 0, copy.descendants.count
3052 assert_equal 0, copy.descendants.count
3032 end
3053 end
3033
3054
3034 def test_create_as_copy_with_failure
3055 def test_create_as_copy_with_failure
3035 @request.session[:user_id] = 2
3056 @request.session[:user_id] = 2
3036 post :create, :project_id => 1, :copy_from => 1,
3057 post :create, :project_id => 1, :copy_from => 1,
3037 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => ''}
3058 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => ''}
3038
3059
3039 assert_response :success
3060 assert_response :success
3040 assert_template 'new'
3061 assert_template 'new'
3041
3062
3042 assert_not_nil assigns(:issue)
3063 assert_not_nil assigns(:issue)
3043 assert assigns(:issue).copy?
3064 assert assigns(:issue).copy?
3044
3065
3045 assert_select 'form#issue-form[action="/projects/ecookbook/issues"]' do
3066 assert_select 'form#issue-form[action="/projects/ecookbook/issues"]' do
3046 assert_select 'select[name=?]', 'issue[project_id]' do
3067 assert_select 'select[name=?]', 'issue[project_id]' do
3047 assert_select 'option[value="1"]:not([selected])', :text => 'eCookbook'
3068 assert_select 'option[value="1"]:not([selected])', :text => 'eCookbook'
3048 assert_select 'option[value="2"][selected=selected]', :text => 'OnlineStore'
3069 assert_select 'option[value="2"][selected=selected]', :text => 'OnlineStore'
3049 end
3070 end
3050 assert_select 'input[name=copy_from][value="1"]'
3071 assert_select 'input[name=copy_from][value="1"]'
3051 end
3072 end
3052 end
3073 end
3053
3074
3054 def test_create_as_copy_on_project_without_permission_should_ignore_target_project
3075 def test_create_as_copy_on_project_without_permission_should_ignore_target_project
3055 @request.session[:user_id] = 2
3076 @request.session[:user_id] = 2
3056 assert !User.find(2).member_of?(Project.find(4))
3077 assert !User.find(2).member_of?(Project.find(4))
3057
3078
3058 assert_difference 'Issue.count' do
3079 assert_difference 'Issue.count' do
3059 post :create, :project_id => 1, :copy_from => 1,
3080 post :create, :project_id => 1, :copy_from => 1,
3060 :issue => {:project_id => '4', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
3081 :issue => {:project_id => '4', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
3061 end
3082 end
3062 issue = Issue.order('id DESC').first
3083 issue = Issue.order('id DESC').first
3063 assert_equal 1, issue.project_id
3084 assert_equal 1, issue.project_id
3064 end
3085 end
3065
3086
3066 def test_get_edit
3087 def test_get_edit
3067 @request.session[:user_id] = 2
3088 @request.session[:user_id] = 2
3068 get :edit, :id => 1
3089 get :edit, :id => 1
3069 assert_response :success
3090 assert_response :success
3070 assert_template 'edit'
3091 assert_template 'edit'
3071 assert_not_nil assigns(:issue)
3092 assert_not_nil assigns(:issue)
3072 assert_equal Issue.find(1), assigns(:issue)
3093 assert_equal Issue.find(1), assigns(:issue)
3073
3094
3074 # Be sure we don't display inactive IssuePriorities
3095 # Be sure we don't display inactive IssuePriorities
3075 assert ! IssuePriority.find(15).active?
3096 assert ! IssuePriority.find(15).active?
3076 assert_select 'select[name=?]', 'issue[priority_id]' do
3097 assert_select 'select[name=?]', 'issue[priority_id]' do
3077 assert_select 'option[value="15"]', 0
3098 assert_select 'option[value="15"]', 0
3078 end
3099 end
3079 end
3100 end
3080
3101
3081 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
3102 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
3082 @request.session[:user_id] = 2
3103 @request.session[:user_id] = 2
3083 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
3104 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
3084
3105
3085 get :edit, :id => 1
3106 get :edit, :id => 1
3086 assert_select 'input[name=?]', 'time_entry[hours]'
3107 assert_select 'input[name=?]', 'time_entry[hours]'
3087 end
3108 end
3088
3109
3089 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
3110 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
3090 @request.session[:user_id] = 2
3111 @request.session[:user_id] = 2
3091 Role.find_by_name('Manager').remove_permission! :log_time
3112 Role.find_by_name('Manager').remove_permission! :log_time
3092
3113
3093 get :edit, :id => 1
3114 get :edit, :id => 1
3094 assert_select 'input[name=?]', 'time_entry[hours]', 0
3115 assert_select 'input[name=?]', 'time_entry[hours]', 0
3095 end
3116 end
3096
3117
3097 def test_get_edit_with_params
3118 def test_get_edit_with_params
3098 @request.session[:user_id] = 2
3119 @request.session[:user_id] = 2
3099 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
3120 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
3100 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => 10 }
3121 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => 10 }
3101 assert_response :success
3122 assert_response :success
3102 assert_template 'edit'
3123 assert_template 'edit'
3103
3124
3104 issue = assigns(:issue)
3125 issue = assigns(:issue)
3105 assert_not_nil issue
3126 assert_not_nil issue
3106
3127
3107 assert_equal 5, issue.status_id
3128 assert_equal 5, issue.status_id
3108 assert_select 'select[name=?]', 'issue[status_id]' do
3129 assert_select 'select[name=?]', 'issue[status_id]' do
3109 assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
3130 assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
3110 end
3131 end
3111
3132
3112 assert_equal 7, issue.priority_id
3133 assert_equal 7, issue.priority_id
3113 assert_select 'select[name=?]', 'issue[priority_id]' do
3134 assert_select 'select[name=?]', 'issue[priority_id]' do
3114 assert_select 'option[value="7"][selected=selected]', :text => 'Urgent'
3135 assert_select 'option[value="7"][selected=selected]', :text => 'Urgent'
3115 end
3136 end
3116
3137
3117 assert_select 'input[name=?][value="2.5"]', 'time_entry[hours]'
3138 assert_select 'input[name=?][value="2.5"]', 'time_entry[hours]'
3118 assert_select 'select[name=?]', 'time_entry[activity_id]' do
3139 assert_select 'select[name=?]', 'time_entry[activity_id]' do
3119 assert_select 'option[value="10"][selected=selected]', :text => 'Development'
3140 assert_select 'option[value="10"][selected=selected]', :text => 'Development'
3120 end
3141 end
3121 assert_select 'input[name=?][value=test_get_edit_with_params]', 'time_entry[comments]'
3142 assert_select 'input[name=?][value=test_get_edit_with_params]', 'time_entry[comments]'
3122 end
3143 end
3123
3144
3124 def test_get_edit_with_multi_custom_field
3145 def test_get_edit_with_multi_custom_field
3125 field = CustomField.find(1)
3146 field = CustomField.find(1)
3126 field.update_attribute :multiple, true
3147 field.update_attribute :multiple, true
3127 issue = Issue.find(1)
3148 issue = Issue.find(1)
3128 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
3149 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
3129 issue.save!
3150 issue.save!
3130
3151
3131 @request.session[:user_id] = 2
3152 @request.session[:user_id] = 2
3132 get :edit, :id => 1
3153 get :edit, :id => 1
3133 assert_response :success
3154 assert_response :success
3134 assert_template 'edit'
3155 assert_template 'edit'
3135
3156
3136 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
3157 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
3137 assert_select 'option', 3
3158 assert_select 'option', 3
3138 assert_select 'option[value=MySQL][selected=selected]'
3159 assert_select 'option[value=MySQL][selected=selected]'
3139 assert_select 'option[value=Oracle][selected=selected]'
3160 assert_select 'option[value=Oracle][selected=selected]'
3140 assert_select 'option[value=PostgreSQL]:not([selected])'
3161 assert_select 'option[value=PostgreSQL]:not([selected])'
3141 end
3162 end
3142 end
3163 end
3143
3164
3144 def test_update_form_for_existing_issue
3165 def test_update_form_for_existing_issue
3145 @request.session[:user_id] = 2
3166 @request.session[:user_id] = 2
3146 xhr :patch, :edit, :id => 1,
3167 xhr :patch, :edit, :id => 1,
3147 :issue => {:tracker_id => 2,
3168 :issue => {:tracker_id => 2,
3148 :subject => 'This is the test_new issue',
3169 :subject => 'This is the test_new issue',
3149 :description => 'This is the description',
3170 :description => 'This is the description',
3150 :priority_id => 5}
3171 :priority_id => 5}
3151 assert_response :success
3172 assert_response :success
3152 assert_equal 'text/javascript', response.content_type
3173 assert_equal 'text/javascript', response.content_type
3153 assert_template 'edit'
3174 assert_template 'edit'
3154 assert_template :partial => '_form'
3175 assert_template :partial => '_form'
3155
3176
3156 issue = assigns(:issue)
3177 issue = assigns(:issue)
3157 assert_kind_of Issue, issue
3178 assert_kind_of Issue, issue
3158 assert_equal 1, issue.id
3179 assert_equal 1, issue.id
3159 assert_equal 1, issue.project_id
3180 assert_equal 1, issue.project_id
3160 assert_equal 2, issue.tracker_id
3181 assert_equal 2, issue.tracker_id
3161 assert_equal 'This is the test_new issue', issue.subject
3182 assert_equal 'This is the test_new issue', issue.subject
3162 end
3183 end
3163
3184
3164 def test_update_form_for_existing_issue_should_keep_issue_author
3185 def test_update_form_for_existing_issue_should_keep_issue_author
3165 @request.session[:user_id] = 3
3186 @request.session[:user_id] = 3
3166 xhr :patch, :edit, :id => 1, :issue => {:subject => 'Changed'}
3187 xhr :patch, :edit, :id => 1, :issue => {:subject => 'Changed'}
3167 assert_response :success
3188 assert_response :success
3168 assert_equal 'text/javascript', response.content_type
3189 assert_equal 'text/javascript', response.content_type
3169
3190
3170 issue = assigns(:issue)
3191 issue = assigns(:issue)
3171 assert_equal User.find(2), issue.author
3192 assert_equal User.find(2), issue.author
3172 assert_equal 2, issue.author_id
3193 assert_equal 2, issue.author_id
3173 assert_not_equal User.current, issue.author
3194 assert_not_equal User.current, issue.author
3174 end
3195 end
3175
3196
3176 def test_update_form_for_existing_issue_should_propose_transitions_based_on_initial_status
3197 def test_update_form_for_existing_issue_should_propose_transitions_based_on_initial_status
3177 @request.session[:user_id] = 2
3198 @request.session[:user_id] = 2
3178 WorkflowTransition.delete_all
3199 WorkflowTransition.delete_all
3179 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
3200 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
3180 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
3201 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
3181 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 5, :new_status_id => 4)
3202 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 5, :new_status_id => 4)
3182
3203
3183 xhr :patch, :edit, :id => 2,
3204 xhr :patch, :edit, :id => 2,
3184 :issue => {:tracker_id => 2,
3205 :issue => {:tracker_id => 2,
3185 :status_id => 5,
3206 :status_id => 5,
3186 :subject => 'This is an issue'}
3207 :subject => 'This is an issue'}
3187
3208
3188 assert_equal 5, assigns(:issue).status_id
3209 assert_equal 5, assigns(:issue).status_id
3189 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
3210 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
3190 end
3211 end
3191
3212
3192 def test_update_form_for_existing_issue_with_project_change
3213 def test_update_form_for_existing_issue_with_project_change
3193 @request.session[:user_id] = 2
3214 @request.session[:user_id] = 2
3194 xhr :patch, :edit, :id => 1,
3215 xhr :patch, :edit, :id => 1,
3195 :issue => {:project_id => 2,
3216 :issue => {:project_id => 2,
3196 :tracker_id => 2,
3217 :tracker_id => 2,
3197 :subject => 'This is the test_new issue',
3218 :subject => 'This is the test_new issue',
3198 :description => 'This is the description',
3219 :description => 'This is the description',
3199 :priority_id => 5}
3220 :priority_id => 5}
3200 assert_response :success
3221 assert_response :success
3201 assert_template :partial => '_form'
3222 assert_template :partial => '_form'
3202
3223
3203 issue = assigns(:issue)
3224 issue = assigns(:issue)
3204 assert_kind_of Issue, issue
3225 assert_kind_of Issue, issue
3205 assert_equal 1, issue.id
3226 assert_equal 1, issue.id
3206 assert_equal 2, issue.project_id
3227 assert_equal 2, issue.project_id
3207 assert_equal 2, issue.tracker_id
3228 assert_equal 2, issue.tracker_id
3208 assert_equal 'This is the test_new issue', issue.subject
3229 assert_equal 'This is the test_new issue', issue.subject
3209 end
3230 end
3210
3231
3211 def test_update_form_should_keep_category_with_same_when_changing_project
3232 def test_update_form_should_keep_category_with_same_when_changing_project
3212 source = Project.generate!
3233 source = Project.generate!
3213 target = Project.generate!
3234 target = Project.generate!
3214 source_category = IssueCategory.create!(:name => 'Foo', :project => source)
3235 source_category = IssueCategory.create!(:name => 'Foo', :project => source)
3215 target_category = IssueCategory.create!(:name => 'Foo', :project => target)
3236 target_category = IssueCategory.create!(:name => 'Foo', :project => target)
3216 issue = Issue.generate!(:project => source, :category => source_category)
3237 issue = Issue.generate!(:project => source, :category => source_category)
3217
3238
3218 @request.session[:user_id] = 1
3239 @request.session[:user_id] = 1
3219 patch :edit, :id => issue.id,
3240 patch :edit, :id => issue.id,
3220 :issue => {:project_id => target.id, :category_id => source_category.id}
3241 :issue => {:project_id => target.id, :category_id => source_category.id}
3221 assert_response :success
3242 assert_response :success
3222
3243
3223 issue = assigns(:issue)
3244 issue = assigns(:issue)
3224 assert_equal target_category, issue.category
3245 assert_equal target_category, issue.category
3225 end
3246 end
3226
3247
3227 def test_update_form_should_propose_default_status_for_existing_issue
3248 def test_update_form_should_propose_default_status_for_existing_issue
3228 @request.session[:user_id] = 2
3249 @request.session[:user_id] = 2
3229 WorkflowTransition.delete_all
3250 WorkflowTransition.delete_all
3230 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3)
3251 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3)
3231
3252
3232 xhr :patch, :edit, :id => 2
3253 xhr :patch, :edit, :id => 2
3233 assert_response :success
3254 assert_response :success
3234 assert_equal [2,3], assigns(:allowed_statuses).map(&:id).sort
3255 assert_equal [2,3], assigns(:allowed_statuses).map(&:id).sort
3235 end
3256 end
3236
3257
3237 def test_put_update_without_custom_fields_param
3258 def test_put_update_without_custom_fields_param
3238 @request.session[:user_id] = 2
3259 @request.session[:user_id] = 2
3239
3260
3240 issue = Issue.find(1)
3261 issue = Issue.find(1)
3241 assert_equal '125', issue.custom_value_for(2).value
3262 assert_equal '125', issue.custom_value_for(2).value
3242
3263
3243 assert_difference('Journal.count') do
3264 assert_difference('Journal.count') do
3244 assert_difference('JournalDetail.count') do
3265 assert_difference('JournalDetail.count') do
3245 put :update, :id => 1, :issue => {:subject => 'New subject'}
3266 put :update, :id => 1, :issue => {:subject => 'New subject'}
3246 end
3267 end
3247 end
3268 end
3248 assert_redirected_to :action => 'show', :id => '1'
3269 assert_redirected_to :action => 'show', :id => '1'
3249 issue.reload
3270 issue.reload
3250 assert_equal 'New subject', issue.subject
3271 assert_equal 'New subject', issue.subject
3251 # Make sure custom fields were not cleared
3272 # Make sure custom fields were not cleared
3252 assert_equal '125', issue.custom_value_for(2).value
3273 assert_equal '125', issue.custom_value_for(2).value
3253 end
3274 end
3254
3275
3255 def test_put_update_with_project_change
3276 def test_put_update_with_project_change
3256 @request.session[:user_id] = 2
3277 @request.session[:user_id] = 2
3257 ActionMailer::Base.deliveries.clear
3278 ActionMailer::Base.deliveries.clear
3258
3279
3259 with_settings :notified_events => %w(issue_updated) do
3280 with_settings :notified_events => %w(issue_updated) do
3260 assert_difference('Journal.count') do
3281 assert_difference('Journal.count') do
3261 assert_difference('JournalDetail.count', 3) do
3282 assert_difference('JournalDetail.count', 3) do
3262 put :update, :id => 1, :issue => {:project_id => '2',
3283 put :update, :id => 1, :issue => {:project_id => '2',
3263 :tracker_id => '1', # no change
3284 :tracker_id => '1', # no change
3264 :priority_id => '6',
3285 :priority_id => '6',
3265 :category_id => '3'
3286 :category_id => '3'
3266 }
3287 }
3267 end
3288 end
3268 end
3289 end
3269 end
3290 end
3270 assert_redirected_to :action => 'show', :id => '1'
3291 assert_redirected_to :action => 'show', :id => '1'
3271 issue = Issue.find(1)
3292 issue = Issue.find(1)
3272 assert_equal 2, issue.project_id
3293 assert_equal 2, issue.project_id
3273 assert_equal 1, issue.tracker_id
3294 assert_equal 1, issue.tracker_id
3274 assert_equal 6, issue.priority_id
3295 assert_equal 6, issue.priority_id
3275 assert_equal 3, issue.category_id
3296 assert_equal 3, issue.category_id
3276
3297
3277 mail = ActionMailer::Base.deliveries.last
3298 mail = ActionMailer::Base.deliveries.last
3278 assert_not_nil mail
3299 assert_not_nil mail
3279 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
3300 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
3280 assert_mail_body_match "Project changed from eCookbook to OnlineStore", mail
3301 assert_mail_body_match "Project changed from eCookbook to OnlineStore", mail
3281 end
3302 end
3282
3303
3283 def test_put_update_trying_to_move_issue_to_project_without_tracker_should_not_error
3304 def test_put_update_trying_to_move_issue_to_project_without_tracker_should_not_error
3284 target = Project.generate!(:tracker_ids => [])
3305 target = Project.generate!(:tracker_ids => [])
3285 assert target.trackers.empty?
3306 assert target.trackers.empty?
3286 issue = Issue.generate!
3307 issue = Issue.generate!
3287 @request.session[:user_id] = 1
3308 @request.session[:user_id] = 1
3288
3309
3289 put :update, :id => issue.id, :issue => {:project_id => target.id}
3310 put :update, :id => issue.id, :issue => {:project_id => target.id}
3290 assert_response 302
3311 assert_response 302
3291 end
3312 end
3292
3313
3293 def test_put_update_with_tracker_change
3314 def test_put_update_with_tracker_change
3294 @request.session[:user_id] = 2
3315 @request.session[:user_id] = 2
3295 ActionMailer::Base.deliveries.clear
3316 ActionMailer::Base.deliveries.clear
3296
3317
3297 with_settings :notified_events => %w(issue_updated) do
3318 with_settings :notified_events => %w(issue_updated) do
3298 assert_difference('Journal.count') do
3319 assert_difference('Journal.count') do
3299 assert_difference('JournalDetail.count', 2) do
3320 assert_difference('JournalDetail.count', 2) do
3300 put :update, :id => 1, :issue => {:project_id => '1',
3321 put :update, :id => 1, :issue => {:project_id => '1',
3301 :tracker_id => '2',
3322 :tracker_id => '2',
3302 :priority_id => '6'
3323 :priority_id => '6'
3303 }
3324 }
3304 end
3325 end
3305 end
3326 end
3306 end
3327 end
3307 assert_redirected_to :action => 'show', :id => '1'
3328 assert_redirected_to :action => 'show', :id => '1'
3308 issue = Issue.find(1)
3329 issue = Issue.find(1)
3309 assert_equal 1, issue.project_id
3330 assert_equal 1, issue.project_id
3310 assert_equal 2, issue.tracker_id
3331 assert_equal 2, issue.tracker_id
3311 assert_equal 6, issue.priority_id
3332 assert_equal 6, issue.priority_id
3312 assert_equal 1, issue.category_id
3333 assert_equal 1, issue.category_id
3313
3334
3314 mail = ActionMailer::Base.deliveries.last
3335 mail = ActionMailer::Base.deliveries.last
3315 assert_not_nil mail
3336 assert_not_nil mail
3316 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
3337 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
3317 assert_mail_body_match "Tracker changed from Bug to Feature request", mail
3338 assert_mail_body_match "Tracker changed from Bug to Feature request", mail
3318 end
3339 end
3319
3340
3320 def test_put_update_with_custom_field_change
3341 def test_put_update_with_custom_field_change
3321 @request.session[:user_id] = 2
3342 @request.session[:user_id] = 2
3322 issue = Issue.find(1)
3343 issue = Issue.find(1)
3323 assert_equal '125', issue.custom_value_for(2).value
3344 assert_equal '125', issue.custom_value_for(2).value
3324
3345
3325 with_settings :notified_events => %w(issue_updated) do
3346 with_settings :notified_events => %w(issue_updated) do
3326 assert_difference('Journal.count') do
3347 assert_difference('Journal.count') do
3327 assert_difference('JournalDetail.count', 3) do
3348 assert_difference('JournalDetail.count', 3) do
3328 put :update, :id => 1, :issue => {:subject => 'Custom field change',
3349 put :update, :id => 1, :issue => {:subject => 'Custom field change',
3329 :priority_id => '6',
3350 :priority_id => '6',
3330 :category_id => '1', # no change
3351 :category_id => '1', # no change
3331 :custom_field_values => { '2' => 'New custom value' }
3352 :custom_field_values => { '2' => 'New custom value' }
3332 }
3353 }
3333 end
3354 end
3334 end
3355 end
3335 end
3356 end
3336 assert_redirected_to :action => 'show', :id => '1'
3357 assert_redirected_to :action => 'show', :id => '1'
3337 issue.reload
3358 issue.reload
3338 assert_equal 'New custom value', issue.custom_value_for(2).value
3359 assert_equal 'New custom value', issue.custom_value_for(2).value
3339
3360
3340 mail = ActionMailer::Base.deliveries.last
3361 mail = ActionMailer::Base.deliveries.last
3341 assert_not_nil mail
3362 assert_not_nil mail
3342 assert_mail_body_match "Searchable field changed from 125 to New custom value", mail
3363 assert_mail_body_match "Searchable field changed from 125 to New custom value", mail
3343 end
3364 end
3344
3365
3345 def test_put_update_with_multi_custom_field_change
3366 def test_put_update_with_multi_custom_field_change
3346 field = CustomField.find(1)
3367 field = CustomField.find(1)
3347 field.update_attribute :multiple, true
3368 field.update_attribute :multiple, true
3348 issue = Issue.find(1)
3369 issue = Issue.find(1)
3349 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
3370 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
3350 issue.save!
3371 issue.save!
3351
3372
3352 @request.session[:user_id] = 2
3373 @request.session[:user_id] = 2
3353 assert_difference('Journal.count') do
3374 assert_difference('Journal.count') do
3354 assert_difference('JournalDetail.count', 3) do
3375 assert_difference('JournalDetail.count', 3) do
3355 put :update, :id => 1,
3376 put :update, :id => 1,
3356 :issue => {
3377 :issue => {
3357 :subject => 'Custom field change',
3378 :subject => 'Custom field change',
3358 :custom_field_values => { '1' => ['', 'Oracle', 'PostgreSQL'] }
3379 :custom_field_values => { '1' => ['', 'Oracle', 'PostgreSQL'] }
3359 }
3380 }
3360 end
3381 end
3361 end
3382 end
3362 assert_redirected_to :action => 'show', :id => '1'
3383 assert_redirected_to :action => 'show', :id => '1'
3363 assert_equal ['Oracle', 'PostgreSQL'], Issue.find(1).custom_field_value(1).sort
3384 assert_equal ['Oracle', 'PostgreSQL'], Issue.find(1).custom_field_value(1).sort
3364 end
3385 end
3365
3386
3366 def test_put_update_with_status_and_assignee_change
3387 def test_put_update_with_status_and_assignee_change
3367 issue = Issue.find(1)
3388 issue = Issue.find(1)
3368 assert_equal 1, issue.status_id
3389 assert_equal 1, issue.status_id
3369 @request.session[:user_id] = 2
3390 @request.session[:user_id] = 2
3370
3391
3371 with_settings :notified_events => %w(issue_updated) do
3392 with_settings :notified_events => %w(issue_updated) do
3372 assert_difference('TimeEntry.count', 0) do
3393 assert_difference('TimeEntry.count', 0) do
3373 put :update,
3394 put :update,
3374 :id => 1,
3395 :id => 1,
3375 :issue => { :status_id => 2, :assigned_to_id => 3, :notes => 'Assigned to dlopper' },
3396 :issue => { :status_id => 2, :assigned_to_id => 3, :notes => 'Assigned to dlopper' },
3376 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
3397 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
3377 end
3398 end
3378 end
3399 end
3379 assert_redirected_to :action => 'show', :id => '1'
3400 assert_redirected_to :action => 'show', :id => '1'
3380 issue.reload
3401 issue.reload
3381 assert_equal 2, issue.status_id
3402 assert_equal 2, issue.status_id
3382 j = Journal.order('id DESC').first
3403 j = Journal.order('id DESC').first
3383 assert_equal 'Assigned to dlopper', j.notes
3404 assert_equal 'Assigned to dlopper', j.notes
3384 assert_equal 2, j.details.size
3405 assert_equal 2, j.details.size
3385
3406
3386 mail = ActionMailer::Base.deliveries.last
3407 mail = ActionMailer::Base.deliveries.last
3387 assert_mail_body_match "Status changed from New to Assigned", mail
3408 assert_mail_body_match "Status changed from New to Assigned", mail
3388 # subject should contain the new status
3409 # subject should contain the new status
3389 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
3410 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
3390 end
3411 end
3391
3412
3392 def test_put_update_with_note_only
3413 def test_put_update_with_note_only
3393 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
3414 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
3394
3415
3395 with_settings :notified_events => %w(issue_updated) do
3416 with_settings :notified_events => %w(issue_updated) do
3396 # anonymous user
3417 # anonymous user
3397 put :update,
3418 put :update,
3398 :id => 1,
3419 :id => 1,
3399 :issue => { :notes => notes }
3420 :issue => { :notes => notes }
3400 end
3421 end
3401 assert_redirected_to :action => 'show', :id => '1'
3422 assert_redirected_to :action => 'show', :id => '1'
3402 j = Journal.order('id DESC').first
3423 j = Journal.order('id DESC').first
3403 assert_equal notes, j.notes
3424 assert_equal notes, j.notes
3404 assert_equal 0, j.details.size
3425 assert_equal 0, j.details.size
3405 assert_equal User.anonymous, j.user
3426 assert_equal User.anonymous, j.user
3406
3427
3407 mail = ActionMailer::Base.deliveries.last
3428 mail = ActionMailer::Base.deliveries.last
3408 assert_mail_body_match notes, mail
3429 assert_mail_body_match notes, mail
3409 end
3430 end
3410
3431
3411 def test_put_update_with_private_note_only
3432 def test_put_update_with_private_note_only
3412 notes = 'Private note'
3433 notes = 'Private note'
3413 @request.session[:user_id] = 2
3434 @request.session[:user_id] = 2
3414
3435
3415 assert_difference 'Journal.count' do
3436 assert_difference 'Journal.count' do
3416 put :update, :id => 1, :issue => {:notes => notes, :private_notes => '1'}
3437 put :update, :id => 1, :issue => {:notes => notes, :private_notes => '1'}
3417 assert_redirected_to :action => 'show', :id => '1'
3438 assert_redirected_to :action => 'show', :id => '1'
3418 end
3439 end
3419
3440
3420 j = Journal.order('id DESC').first
3441 j = Journal.order('id DESC').first
3421 assert_equal notes, j.notes
3442 assert_equal notes, j.notes
3422 assert_equal true, j.private_notes
3443 assert_equal true, j.private_notes
3423 end
3444 end
3424
3445
3425 def test_put_update_with_private_note_and_changes
3446 def test_put_update_with_private_note_and_changes
3426 notes = 'Private note'
3447 notes = 'Private note'
3427 @request.session[:user_id] = 2
3448 @request.session[:user_id] = 2
3428
3449
3429 assert_difference 'Journal.count', 2 do
3450 assert_difference 'Journal.count', 2 do
3430 put :update, :id => 1, :issue => {:subject => 'New subject', :notes => notes, :private_notes => '1'}
3451 put :update, :id => 1, :issue => {:subject => 'New subject', :notes => notes, :private_notes => '1'}
3431 assert_redirected_to :action => 'show', :id => '1'
3452 assert_redirected_to :action => 'show', :id => '1'
3432 end
3453 end
3433
3454
3434 j = Journal.order('id DESC').first
3455 j = Journal.order('id DESC').first
3435 assert_equal notes, j.notes
3456 assert_equal notes, j.notes
3436 assert_equal true, j.private_notes
3457 assert_equal true, j.private_notes
3437 assert_equal 0, j.details.count
3458 assert_equal 0, j.details.count
3438
3459
3439 j = Journal.order('id DESC').offset(1).first
3460 j = Journal.order('id DESC').offset(1).first
3440 assert_nil j.notes
3461 assert_nil j.notes
3441 assert_equal false, j.private_notes
3462 assert_equal false, j.private_notes
3442 assert_equal 1, j.details.count
3463 assert_equal 1, j.details.count
3443 end
3464 end
3444
3465
3445 def test_put_update_with_note_and_spent_time
3466 def test_put_update_with_note_and_spent_time
3446 @request.session[:user_id] = 2
3467 @request.session[:user_id] = 2
3447 spent_hours_before = Issue.find(1).spent_hours
3468 spent_hours_before = Issue.find(1).spent_hours
3448 assert_difference('TimeEntry.count') do
3469 assert_difference('TimeEntry.count') do
3449 put :update,
3470 put :update,
3450 :id => 1,
3471 :id => 1,
3451 :issue => { :notes => '2.5 hours added' },
3472 :issue => { :notes => '2.5 hours added' },
3452 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
3473 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
3453 end
3474 end
3454 assert_redirected_to :action => 'show', :id => '1'
3475 assert_redirected_to :action => 'show', :id => '1'
3455
3476
3456 issue = Issue.find(1)
3477 issue = Issue.find(1)
3457
3478
3458 j = Journal.order('id DESC').first
3479 j = Journal.order('id DESC').first
3459 assert_equal '2.5 hours added', j.notes
3480 assert_equal '2.5 hours added', j.notes
3460 assert_equal 0, j.details.size
3481 assert_equal 0, j.details.size
3461
3482
3462 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
3483 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
3463 assert_not_nil t
3484 assert_not_nil t
3464 assert_equal 2.5, t.hours
3485 assert_equal 2.5, t.hours
3465 assert_equal spent_hours_before + 2.5, issue.spent_hours
3486 assert_equal spent_hours_before + 2.5, issue.spent_hours
3466 end
3487 end
3467
3488
3468 def test_put_update_should_preserve_parent_issue_even_if_not_visible
3489 def test_put_update_should_preserve_parent_issue_even_if_not_visible
3469 parent = Issue.generate!(:project_id => 1, :is_private => true)
3490 parent = Issue.generate!(:project_id => 1, :is_private => true)
3470 issue = Issue.generate!(:parent_issue_id => parent.id)
3491 issue = Issue.generate!(:parent_issue_id => parent.id)
3471 assert !parent.visible?(User.find(3))
3492 assert !parent.visible?(User.find(3))
3472 @request.session[:user_id] = 3
3493 @request.session[:user_id] = 3
3473
3494
3474 get :edit, :id => issue.id
3495 get :edit, :id => issue.id
3475 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', parent.id.to_s
3496 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', parent.id.to_s
3476
3497
3477 put :update, :id => issue.id, :issue => {:subject => 'New subject', :parent_issue_id => parent.id.to_s}
3498 put :update, :id => issue.id, :issue => {:subject => 'New subject', :parent_issue_id => parent.id.to_s}
3478 assert_response 302
3499 assert_response 302
3479 assert_equal parent, issue.parent
3500 assert_equal parent, issue.parent
3480 end
3501 end
3481
3502
3482 def test_put_update_with_attachment_only
3503 def test_put_update_with_attachment_only
3483 set_tmp_attachments_directory
3504 set_tmp_attachments_directory
3484
3505
3485 # Delete all fixtured journals, a race condition can occur causing the wrong
3506 # Delete all fixtured journals, a race condition can occur causing the wrong
3486 # journal to get fetched in the next find.
3507 # journal to get fetched in the next find.
3487 Journal.delete_all
3508 Journal.delete_all
3488
3509
3489 with_settings :notified_events => %w(issue_updated) do
3510 with_settings :notified_events => %w(issue_updated) do
3490 # anonymous user
3511 # anonymous user
3491 assert_difference 'Attachment.count' do
3512 assert_difference 'Attachment.count' do
3492 put :update, :id => 1,
3513 put :update, :id => 1,
3493 :issue => {:notes => ''},
3514 :issue => {:notes => ''},
3494 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
3515 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
3495 end
3516 end
3496 end
3517 end
3497
3518
3498 assert_redirected_to :action => 'show', :id => '1'
3519 assert_redirected_to :action => 'show', :id => '1'
3499 j = Issue.find(1).journals.reorder('id DESC').first
3520 j = Issue.find(1).journals.reorder('id DESC').first
3500 assert j.notes.blank?
3521 assert j.notes.blank?
3501 assert_equal 1, j.details.size
3522 assert_equal 1, j.details.size
3502 assert_equal 'testfile.txt', j.details.first.value
3523 assert_equal 'testfile.txt', j.details.first.value
3503 assert_equal User.anonymous, j.user
3524 assert_equal User.anonymous, j.user
3504
3525
3505 attachment = Attachment.order('id DESC').first
3526 attachment = Attachment.order('id DESC').first
3506 assert_equal Issue.find(1), attachment.container
3527 assert_equal Issue.find(1), attachment.container
3507 assert_equal User.anonymous, attachment.author
3528 assert_equal User.anonymous, attachment.author
3508 assert_equal 'testfile.txt', attachment.filename
3529 assert_equal 'testfile.txt', attachment.filename
3509 assert_equal 'text/plain', attachment.content_type
3530 assert_equal 'text/plain', attachment.content_type
3510 assert_equal 'test file', attachment.description
3531 assert_equal 'test file', attachment.description
3511 assert_equal 59, attachment.filesize
3532 assert_equal 59, attachment.filesize
3512 assert File.exists?(attachment.diskfile)
3533 assert File.exists?(attachment.diskfile)
3513 assert_equal 59, File.size(attachment.diskfile)
3534 assert_equal 59, File.size(attachment.diskfile)
3514
3535
3515 mail = ActionMailer::Base.deliveries.last
3536 mail = ActionMailer::Base.deliveries.last
3516 assert_mail_body_match 'testfile.txt', mail
3537 assert_mail_body_match 'testfile.txt', mail
3517 end
3538 end
3518
3539
3519 def test_put_update_with_failure_should_save_attachments
3540 def test_put_update_with_failure_should_save_attachments
3520 set_tmp_attachments_directory
3541 set_tmp_attachments_directory
3521 @request.session[:user_id] = 2
3542 @request.session[:user_id] = 2
3522
3543
3523 assert_no_difference 'Journal.count' do
3544 assert_no_difference 'Journal.count' do
3524 assert_difference 'Attachment.count' do
3545 assert_difference 'Attachment.count' do
3525 put :update, :id => 1,
3546 put :update, :id => 1,
3526 :issue => { :subject => '' },
3547 :issue => { :subject => '' },
3527 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
3548 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
3528 assert_response :success
3549 assert_response :success
3529 assert_template 'edit'
3550 assert_template 'edit'
3530 end
3551 end
3531 end
3552 end
3532
3553
3533 attachment = Attachment.order('id DESC').first
3554 attachment = Attachment.order('id DESC').first
3534 assert_equal 'testfile.txt', attachment.filename
3555 assert_equal 'testfile.txt', attachment.filename
3535 assert File.exists?(attachment.diskfile)
3556 assert File.exists?(attachment.diskfile)
3536 assert_nil attachment.container
3557 assert_nil attachment.container
3537
3558
3538 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
3559 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
3539 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
3560 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
3540 end
3561 end
3541
3562
3542 def test_put_update_with_failure_should_keep_saved_attachments
3563 def test_put_update_with_failure_should_keep_saved_attachments
3543 set_tmp_attachments_directory
3564 set_tmp_attachments_directory
3544 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
3565 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
3545 @request.session[:user_id] = 2
3566 @request.session[:user_id] = 2
3546
3567
3547 assert_no_difference 'Journal.count' do
3568 assert_no_difference 'Journal.count' do
3548 assert_no_difference 'Attachment.count' do
3569 assert_no_difference 'Attachment.count' do
3549 put :update, :id => 1,
3570 put :update, :id => 1,
3550 :issue => { :subject => '' },
3571 :issue => { :subject => '' },
3551 :attachments => {'p0' => {'token' => attachment.token}}
3572 :attachments => {'p0' => {'token' => attachment.token}}
3552 assert_response :success
3573 assert_response :success
3553 assert_template 'edit'
3574 assert_template 'edit'
3554 end
3575 end
3555 end
3576 end
3556
3577
3557 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
3578 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
3558 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
3579 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
3559 end
3580 end
3560
3581
3561 def test_put_update_should_attach_saved_attachments
3582 def test_put_update_should_attach_saved_attachments
3562 set_tmp_attachments_directory
3583 set_tmp_attachments_directory
3563 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
3584 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
3564 @request.session[:user_id] = 2
3585 @request.session[:user_id] = 2
3565
3586
3566 assert_difference 'Journal.count' do
3587 assert_difference 'Journal.count' do
3567 assert_difference 'JournalDetail.count' do
3588 assert_difference 'JournalDetail.count' do
3568 assert_no_difference 'Attachment.count' do
3589 assert_no_difference 'Attachment.count' do
3569 put :update, :id => 1,
3590 put :update, :id => 1,
3570 :issue => {:notes => 'Attachment added'},
3591 :issue => {:notes => 'Attachment added'},
3571 :attachments => {'p0' => {'token' => attachment.token}}
3592 :attachments => {'p0' => {'token' => attachment.token}}
3572 assert_redirected_to '/issues/1'
3593 assert_redirected_to '/issues/1'
3573 end
3594 end
3574 end
3595 end
3575 end
3596 end
3576
3597
3577 attachment.reload
3598 attachment.reload
3578 assert_equal Issue.find(1), attachment.container
3599 assert_equal Issue.find(1), attachment.container
3579
3600
3580 journal = Journal.order('id DESC').first
3601 journal = Journal.order('id DESC').first
3581 assert_equal 1, journal.details.size
3602 assert_equal 1, journal.details.size
3582 assert_equal 'testfile.txt', journal.details.first.value
3603 assert_equal 'testfile.txt', journal.details.first.value
3583 end
3604 end
3584
3605
3585 def test_put_update_with_attachment_that_fails_to_save
3606 def test_put_update_with_attachment_that_fails_to_save
3586 set_tmp_attachments_directory
3607 set_tmp_attachments_directory
3587
3608
3588 # anonymous user
3609 # anonymous user
3589 with_settings :attachment_max_size => 0 do
3610 with_settings :attachment_max_size => 0 do
3590 put :update,
3611 put :update,
3591 :id => 1,
3612 :id => 1,
3592 :issue => {:notes => ''},
3613 :issue => {:notes => ''},
3593 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
3614 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
3594 assert_redirected_to :action => 'show', :id => '1'
3615 assert_redirected_to :action => 'show', :id => '1'
3595 assert_equal '1 file(s) could not be saved.', flash[:warning]
3616 assert_equal '1 file(s) could not be saved.', flash[:warning]
3596 end
3617 end
3597 end
3618 end
3598
3619
3599 def test_put_update_with_no_change
3620 def test_put_update_with_no_change
3600 issue = Issue.find(1)
3621 issue = Issue.find(1)
3601 issue.journals.clear
3622 issue.journals.clear
3602 ActionMailer::Base.deliveries.clear
3623 ActionMailer::Base.deliveries.clear
3603
3624
3604 put :update,
3625 put :update,
3605 :id => 1,
3626 :id => 1,
3606 :issue => {:notes => ''}
3627 :issue => {:notes => ''}
3607 assert_redirected_to :action => 'show', :id => '1'
3628 assert_redirected_to :action => 'show', :id => '1'
3608
3629
3609 issue.reload
3630 issue.reload
3610 assert issue.journals.empty?
3631 assert issue.journals.empty?
3611 # No email should be sent
3632 # No email should be sent
3612 assert ActionMailer::Base.deliveries.empty?
3633 assert ActionMailer::Base.deliveries.empty?
3613 end
3634 end
3614
3635
3615 def test_put_update_should_send_a_notification
3636 def test_put_update_should_send_a_notification
3616 @request.session[:user_id] = 2
3637 @request.session[:user_id] = 2
3617 ActionMailer::Base.deliveries.clear
3638 ActionMailer::Base.deliveries.clear
3618 issue = Issue.find(1)
3639 issue = Issue.find(1)
3619 old_subject = issue.subject
3640 old_subject = issue.subject
3620 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
3641 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
3621
3642
3622 with_settings :notified_events => %w(issue_updated) do
3643 with_settings :notified_events => %w(issue_updated) do
3623 put :update, :id => 1, :issue => {:subject => new_subject,
3644 put :update, :id => 1, :issue => {:subject => new_subject,
3624 :priority_id => '6',
3645 :priority_id => '6',
3625 :category_id => '1' # no change
3646 :category_id => '1' # no change
3626 }
3647 }
3627 assert_equal 1, ActionMailer::Base.deliveries.size
3648 assert_equal 1, ActionMailer::Base.deliveries.size
3628 end
3649 end
3629 end
3650 end
3630
3651
3631 def test_put_update_with_invalid_spent_time_hours_only
3652 def test_put_update_with_invalid_spent_time_hours_only
3632 @request.session[:user_id] = 2
3653 @request.session[:user_id] = 2
3633 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3654 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3634
3655
3635 assert_no_difference('Journal.count') do
3656 assert_no_difference('Journal.count') do
3636 put :update,
3657 put :update,
3637 :id => 1,
3658 :id => 1,
3638 :issue => {:notes => notes},
3659 :issue => {:notes => notes},
3639 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
3660 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
3640 end
3661 end
3641 assert_response :success
3662 assert_response :success
3642 assert_template 'edit'
3663 assert_template 'edit'
3643
3664
3644 assert_select_error /Activity cannot be blank/
3665 assert_select_error /Activity cannot be blank/
3645 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3666 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3646 assert_select 'input[name=?][value=?]', 'time_entry[hours]', '2z'
3667 assert_select 'input[name=?][value=?]', 'time_entry[hours]', '2z'
3647 end
3668 end
3648
3669
3649 def test_put_update_with_invalid_spent_time_comments_only
3670 def test_put_update_with_invalid_spent_time_comments_only
3650 @request.session[:user_id] = 2
3671 @request.session[:user_id] = 2
3651 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3672 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3652
3673
3653 assert_no_difference('Journal.count') do
3674 assert_no_difference('Journal.count') do
3654 put :update,
3675 put :update,
3655 :id => 1,
3676 :id => 1,
3656 :issue => {:notes => notes},
3677 :issue => {:notes => notes},
3657 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
3678 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
3658 end
3679 end
3659 assert_response :success
3680 assert_response :success
3660 assert_template 'edit'
3681 assert_template 'edit'
3661
3682
3662 assert_select_error /Activity cannot be blank/
3683 assert_select_error /Activity cannot be blank/
3663 assert_select_error /Hours cannot be blank/
3684 assert_select_error /Hours cannot be blank/
3664 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3685 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3665 assert_select 'input[name=?][value=?]', 'time_entry[comments]', 'this is my comment'
3686 assert_select 'input[name=?][value=?]', 'time_entry[comments]', 'this is my comment'
3666 end
3687 end
3667
3688
3668 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
3689 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
3669 issue = Issue.find(2)
3690 issue = Issue.find(2)
3670 @request.session[:user_id] = 2
3691 @request.session[:user_id] = 2
3671
3692
3672 put :update,
3693 put :update,
3673 :id => issue.id,
3694 :id => issue.id,
3674 :issue => {
3695 :issue => {
3675 :fixed_version_id => 4
3696 :fixed_version_id => 4
3676 }
3697 }
3677
3698
3678 assert_response :redirect
3699 assert_response :redirect
3679 issue.reload
3700 issue.reload
3680 assert_equal 4, issue.fixed_version_id
3701 assert_equal 4, issue.fixed_version_id
3681 assert_not_equal issue.project_id, issue.fixed_version.project_id
3702 assert_not_equal issue.project_id, issue.fixed_version.project_id
3682 end
3703 end
3683
3704
3684 def test_put_update_should_redirect_back_using_the_back_url_parameter
3705 def test_put_update_should_redirect_back_using_the_back_url_parameter
3685 issue = Issue.find(2)
3706 issue = Issue.find(2)
3686 @request.session[:user_id] = 2
3707 @request.session[:user_id] = 2
3687
3708
3688 put :update,
3709 put :update,
3689 :id => issue.id,
3710 :id => issue.id,
3690 :issue => {
3711 :issue => {
3691 :fixed_version_id => 4
3712 :fixed_version_id => 4
3692 },
3713 },
3693 :back_url => '/issues'
3714 :back_url => '/issues'
3694
3715
3695 assert_response :redirect
3716 assert_response :redirect
3696 assert_redirected_to '/issues'
3717 assert_redirected_to '/issues'
3697 end
3718 end
3698
3719
3699 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
3720 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
3700 issue = Issue.find(2)
3721 issue = Issue.find(2)
3701 @request.session[:user_id] = 2
3722 @request.session[:user_id] = 2
3702
3723
3703 put :update,
3724 put :update,
3704 :id => issue.id,
3725 :id => issue.id,
3705 :issue => {
3726 :issue => {
3706 :fixed_version_id => 4
3727 :fixed_version_id => 4
3707 },
3728 },
3708 :back_url => 'http://google.com'
3729 :back_url => 'http://google.com'
3709
3730
3710 assert_response :redirect
3731 assert_response :redirect
3711 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
3732 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
3712 end
3733 end
3713
3734
3714 def test_put_update_should_redirect_with_previous_and_next_issue_ids_params
3735 def test_put_update_should_redirect_with_previous_and_next_issue_ids_params
3715 @request.session[:user_id] = 2
3736 @request.session[:user_id] = 2
3716
3737
3717 put :update, :id => 11,
3738 put :update, :id => 11,
3718 :issue => {:status_id => 6, :notes => 'Notes'},
3739 :issue => {:status_id => 6, :notes => 'Notes'},
3719 :prev_issue_id => 8,
3740 :prev_issue_id => 8,
3720 :next_issue_id => 12,
3741 :next_issue_id => 12,
3721 :issue_position => 2,
3742 :issue_position => 2,
3722 :issue_count => 3
3743 :issue_count => 3
3723
3744
3724 assert_redirected_to '/issues/11?issue_count=3&issue_position=2&next_issue_id=12&prev_issue_id=8'
3745 assert_redirected_to '/issues/11?issue_count=3&issue_position=2&next_issue_id=12&prev_issue_id=8'
3725 end
3746 end
3726
3747
3727 def test_get_bulk_edit
3748 def test_get_bulk_edit
3728 @request.session[:user_id] = 2
3749 @request.session[:user_id] = 2
3729 get :bulk_edit, :ids => [1, 3]
3750 get :bulk_edit, :ids => [1, 3]
3730 assert_response :success
3751 assert_response :success
3731 assert_template 'bulk_edit'
3752 assert_template 'bulk_edit'
3732
3753
3733 assert_select 'ul#bulk-selection' do
3754 assert_select 'ul#bulk-selection' do
3734 assert_select 'li', 2
3755 assert_select 'li', 2
3735 assert_select 'li a', :text => 'Bug #1'
3756 assert_select 'li a', :text => 'Bug #1'
3736 end
3757 end
3737
3758
3738 assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
3759 assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
3739 assert_select 'input[name=?]', 'ids[]', 2
3760 assert_select 'input[name=?]', 'ids[]', 2
3740 assert_select 'input[name=?][value="1"][type=hidden]', 'ids[]'
3761 assert_select 'input[name=?][value="1"][type=hidden]', 'ids[]'
3741
3762
3742 assert_select 'select[name=?]', 'issue[project_id]'
3763 assert_select 'select[name=?]', 'issue[project_id]'
3743 assert_select 'input[name=?]', 'issue[parent_issue_id]'
3764 assert_select 'input[name=?]', 'issue[parent_issue_id]'
3744
3765
3745 # Project specific custom field, date type
3766 # Project specific custom field, date type
3746 field = CustomField.find(9)
3767 field = CustomField.find(9)
3747 assert !field.is_for_all?
3768 assert !field.is_for_all?
3748 assert_equal 'date', field.field_format
3769 assert_equal 'date', field.field_format
3749 assert_select 'input[name=?]', 'issue[custom_field_values][9]'
3770 assert_select 'input[name=?]', 'issue[custom_field_values][9]'
3750
3771
3751 # System wide custom field
3772 # System wide custom field
3752 assert CustomField.find(1).is_for_all?
3773 assert CustomField.find(1).is_for_all?
3753 assert_select 'select[name=?]', 'issue[custom_field_values][1]'
3774 assert_select 'select[name=?]', 'issue[custom_field_values][1]'
3754
3775
3755 # Be sure we don't display inactive IssuePriorities
3776 # Be sure we don't display inactive IssuePriorities
3756 assert ! IssuePriority.find(15).active?
3777 assert ! IssuePriority.find(15).active?
3757 assert_select 'select[name=?]', 'issue[priority_id]' do
3778 assert_select 'select[name=?]', 'issue[priority_id]' do
3758 assert_select 'option[value="15"]', 0
3779 assert_select 'option[value="15"]', 0
3759 end
3780 end
3760 end
3781 end
3761 end
3782 end
3762
3783
3763 def test_get_bulk_edit_on_different_projects
3784 def test_get_bulk_edit_on_different_projects
3764 @request.session[:user_id] = 2
3785 @request.session[:user_id] = 2
3765 get :bulk_edit, :ids => [1, 2, 6]
3786 get :bulk_edit, :ids => [1, 2, 6]
3766 assert_response :success
3787 assert_response :success
3767 assert_template 'bulk_edit'
3788 assert_template 'bulk_edit'
3768
3789
3769 # Can not set issues from different projects as children of an issue
3790 # Can not set issues from different projects as children of an issue
3770 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
3791 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
3771
3792
3772 # Project specific custom field, date type
3793 # Project specific custom field, date type
3773 field = CustomField.find(9)
3794 field = CustomField.find(9)
3774 assert !field.is_for_all?
3795 assert !field.is_for_all?
3775 assert !field.project_ids.include?(Issue.find(6).project_id)
3796 assert !field.project_ids.include?(Issue.find(6).project_id)
3776 assert_select 'input[name=?]', 'issue[custom_field_values][9]', 0
3797 assert_select 'input[name=?]', 'issue[custom_field_values][9]', 0
3777 end
3798 end
3778
3799
3779 def test_get_bulk_edit_with_user_custom_field
3800 def test_get_bulk_edit_with_user_custom_field
3780 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :tracker_ids => [1,2,3])
3801 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :tracker_ids => [1,2,3])
3781
3802
3782 @request.session[:user_id] = 2
3803 @request.session[:user_id] = 2
3783 get :bulk_edit, :ids => [1, 2]
3804 get :bulk_edit, :ids => [1, 2]
3784 assert_response :success
3805 assert_response :success
3785 assert_template 'bulk_edit'
3806 assert_template 'bulk_edit'
3786
3807
3787 assert_select 'select.user_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3808 assert_select 'select.user_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3788 assert_select 'option', Project.find(1).users.count + 2 # "no change" + "none" options
3809 assert_select 'option', Project.find(1).users.count + 2 # "no change" + "none" options
3789 end
3810 end
3790 end
3811 end
3791
3812
3792 def test_get_bulk_edit_with_version_custom_field
3813 def test_get_bulk_edit_with_version_custom_field
3793 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3])
3814 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3])
3794
3815
3795 @request.session[:user_id] = 2
3816 @request.session[:user_id] = 2
3796 get :bulk_edit, :ids => [1, 2]
3817 get :bulk_edit, :ids => [1, 2]
3797 assert_response :success
3818 assert_response :success
3798 assert_template 'bulk_edit'
3819 assert_template 'bulk_edit'
3799
3820
3800 assert_select 'select.version_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3821 assert_select 'select.version_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3801 assert_select 'option', Project.find(1).shared_versions.count + 2 # "no change" + "none" options
3822 assert_select 'option', Project.find(1).shared_versions.count + 2 # "no change" + "none" options
3802 end
3823 end
3803 end
3824 end
3804
3825
3805 def test_get_bulk_edit_with_multi_custom_field
3826 def test_get_bulk_edit_with_multi_custom_field
3806 field = CustomField.find(1)
3827 field = CustomField.find(1)
3807 field.update_attribute :multiple, true
3828 field.update_attribute :multiple, true
3808
3829
3809 @request.session[:user_id] = 2
3830 @request.session[:user_id] = 2
3810 get :bulk_edit, :ids => [1, 3]
3831 get :bulk_edit, :ids => [1, 3]
3811 assert_response :success
3832 assert_response :success
3812 assert_template 'bulk_edit'
3833 assert_template 'bulk_edit'
3813
3834
3814 assert_select 'select[name=?]', 'issue[custom_field_values][1][]' do
3835 assert_select 'select[name=?]', 'issue[custom_field_values][1][]' do
3815 assert_select 'option', field.possible_values.size + 1 # "none" options
3836 assert_select 'option', field.possible_values.size + 1 # "none" options
3816 end
3837 end
3817 end
3838 end
3818
3839
3819 def test_bulk_edit_should_propose_to_clear_text_custom_fields
3840 def test_bulk_edit_should_propose_to_clear_text_custom_fields
3820 @request.session[:user_id] = 2
3841 @request.session[:user_id] = 2
3821 get :bulk_edit, :ids => [1, 3]
3842 get :bulk_edit, :ids => [1, 3]
3822 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', '__none__'
3843 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', '__none__'
3823 end
3844 end
3824
3845
3825 def test_bulk_edit_should_only_propose_statuses_allowed_for_all_issues
3846 def test_bulk_edit_should_only_propose_statuses_allowed_for_all_issues
3826 WorkflowTransition.delete_all
3847 WorkflowTransition.delete_all
3827 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3848 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3828 :old_status_id => 1, :new_status_id => 1)
3849 :old_status_id => 1, :new_status_id => 1)
3829 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3850 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3830 :old_status_id => 1, :new_status_id => 3)
3851 :old_status_id => 1, :new_status_id => 3)
3831 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3852 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3832 :old_status_id => 1, :new_status_id => 4)
3853 :old_status_id => 1, :new_status_id => 4)
3833 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3854 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3834 :old_status_id => 2, :new_status_id => 1)
3855 :old_status_id => 2, :new_status_id => 1)
3835 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3856 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3836 :old_status_id => 2, :new_status_id => 3)
3857 :old_status_id => 2, :new_status_id => 3)
3837 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3858 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3838 :old_status_id => 2, :new_status_id => 5)
3859 :old_status_id => 2, :new_status_id => 5)
3839 @request.session[:user_id] = 2
3860 @request.session[:user_id] = 2
3840 get :bulk_edit, :ids => [1, 2]
3861 get :bulk_edit, :ids => [1, 2]
3841
3862
3842 assert_response :success
3863 assert_response :success
3843 statuses = assigns(:available_statuses)
3864 statuses = assigns(:available_statuses)
3844 assert_not_nil statuses
3865 assert_not_nil statuses
3845 assert_equal [1, 3], statuses.map(&:id).sort
3866 assert_equal [1, 3], statuses.map(&:id).sort
3846
3867
3847 assert_select 'select[name=?]', 'issue[status_id]' do
3868 assert_select 'select[name=?]', 'issue[status_id]' do
3848 assert_select 'option', 3 # 2 statuses + "no change" option
3869 assert_select 'option', 3 # 2 statuses + "no change" option
3849 end
3870 end
3850 end
3871 end
3851
3872
3852 def test_bulk_edit_should_propose_target_project_open_shared_versions
3873 def test_bulk_edit_should_propose_target_project_open_shared_versions
3853 @request.session[:user_id] = 2
3874 @request.session[:user_id] = 2
3854 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3875 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3855 assert_response :success
3876 assert_response :success
3856 assert_template 'bulk_edit'
3877 assert_template 'bulk_edit'
3857 assert_equal Project.find(1).shared_versions.open.to_a.sort, assigns(:versions).sort
3878 assert_equal Project.find(1).shared_versions.open.to_a.sort, assigns(:versions).sort
3858
3879
3859 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
3880 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
3860 assert_select 'option', :text => '2.0'
3881 assert_select 'option', :text => '2.0'
3861 end
3882 end
3862 end
3883 end
3863
3884
3864 def test_bulk_edit_should_propose_target_project_categories
3885 def test_bulk_edit_should_propose_target_project_categories
3865 @request.session[:user_id] = 2
3886 @request.session[:user_id] = 2
3866 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3887 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3867 assert_response :success
3888 assert_response :success
3868 assert_template 'bulk_edit'
3889 assert_template 'bulk_edit'
3869 assert_equal Project.find(1).issue_categories.sort, assigns(:categories).sort
3890 assert_equal Project.find(1).issue_categories.sort, assigns(:categories).sort
3870
3891
3871 assert_select 'select[name=?]', 'issue[category_id]' do
3892 assert_select 'select[name=?]', 'issue[category_id]' do
3872 assert_select 'option', :text => 'Recipes'
3893 assert_select 'option', :text => 'Recipes'
3873 end
3894 end
3874 end
3895 end
3875
3896
3876 def test_bulk_edit_should_only_propose_issues_trackers_custom_fields
3897 def test_bulk_edit_should_only_propose_issues_trackers_custom_fields
3877 IssueCustomField.delete_all
3898 IssueCustomField.delete_all
3878 field = IssueCustomField.generate!(:tracker_ids => [1], :is_for_all => true)
3899 field = IssueCustomField.generate!(:tracker_ids => [1], :is_for_all => true)
3879 IssueCustomField.generate!(:tracker_ids => [2], :is_for_all => true)
3900 IssueCustomField.generate!(:tracker_ids => [2], :is_for_all => true)
3880 @request.session[:user_id] = 2
3901 @request.session[:user_id] = 2
3881
3902
3882 issue_ids = Issue.where(:project_id => 1, :tracker_id => 1).limit(2).ids
3903 issue_ids = Issue.where(:project_id => 1, :tracker_id => 1).limit(2).ids
3883 get :bulk_edit, :ids => issue_ids
3904 get :bulk_edit, :ids => issue_ids
3884 assert_equal [field], assigns(:custom_fields)
3905 assert_equal [field], assigns(:custom_fields)
3885 end
3906 end
3886
3907
3887 def test_bulk_update
3908 def test_bulk_update
3888 @request.session[:user_id] = 2
3909 @request.session[:user_id] = 2
3889 # update issues priority
3910 # update issues priority
3890 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3911 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3891 :issue => {:priority_id => 7,
3912 :issue => {:priority_id => 7,
3892 :assigned_to_id => '',
3913 :assigned_to_id => '',
3893 :custom_field_values => {'2' => ''}}
3914 :custom_field_values => {'2' => ''}}
3894
3915
3895 assert_response 302
3916 assert_response 302
3896 # check that the issues were updated
3917 # check that the issues were updated
3897 assert_equal [7, 7], Issue.where(:id =>[1, 2]).collect {|i| i.priority.id}
3918 assert_equal [7, 7], Issue.where(:id =>[1, 2]).collect {|i| i.priority.id}
3898
3919
3899 issue = Issue.find(1)
3920 issue = Issue.find(1)
3900 journal = issue.journals.reorder('created_on DESC').first
3921 journal = issue.journals.reorder('created_on DESC').first
3901 assert_equal '125', issue.custom_value_for(2).value
3922 assert_equal '125', issue.custom_value_for(2).value
3902 assert_equal 'Bulk editing', journal.notes
3923 assert_equal 'Bulk editing', journal.notes
3903 assert_equal 1, journal.details.size
3924 assert_equal 1, journal.details.size
3904 end
3925 end
3905
3926
3906 def test_bulk_update_with_group_assignee
3927 def test_bulk_update_with_group_assignee
3907 group = Group.find(11)
3928 group = Group.find(11)
3908 project = Project.find(1)
3929 project = Project.find(1)
3909 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
3930 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
3910
3931
3911 @request.session[:user_id] = 2
3932 @request.session[:user_id] = 2
3912 # update issues assignee
3933 # update issues assignee
3913 with_settings :issue_group_assignment => '1' do
3934 with_settings :issue_group_assignment => '1' do
3914 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3935 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3915 :issue => {:priority_id => '',
3936 :issue => {:priority_id => '',
3916 :assigned_to_id => group.id,
3937 :assigned_to_id => group.id,
3917 :custom_field_values => {'2' => ''}}
3938 :custom_field_values => {'2' => ''}}
3918
3939
3919 assert_response 302
3940 assert_response 302
3920 assert_equal [group, group], Issue.where(:id => [1, 2]).collect {|i| i.assigned_to}
3941 assert_equal [group, group], Issue.where(:id => [1, 2]).collect {|i| i.assigned_to}
3921 end
3942 end
3922 end
3943 end
3923
3944
3924 def test_bulk_update_on_different_projects
3945 def test_bulk_update_on_different_projects
3925 @request.session[:user_id] = 2
3946 @request.session[:user_id] = 2
3926 # update issues priority
3947 # update issues priority
3927 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
3948 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
3928 :issue => {:priority_id => 7,
3949 :issue => {:priority_id => 7,
3929 :assigned_to_id => '',
3950 :assigned_to_id => '',
3930 :custom_field_values => {'2' => ''}}
3951 :custom_field_values => {'2' => ''}}
3931
3952
3932 assert_response 302
3953 assert_response 302
3933 # check that the issues were updated
3954 # check that the issues were updated
3934 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
3955 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
3935
3956
3936 issue = Issue.find(1)
3957 issue = Issue.find(1)
3937 journal = issue.journals.reorder('created_on DESC').first
3958 journal = issue.journals.reorder('created_on DESC').first
3938 assert_equal '125', issue.custom_value_for(2).value
3959 assert_equal '125', issue.custom_value_for(2).value
3939 assert_equal 'Bulk editing', journal.notes
3960 assert_equal 'Bulk editing', journal.notes
3940 assert_equal 1, journal.details.size
3961 assert_equal 1, journal.details.size
3941 end
3962 end
3942
3963
3943 def test_bulk_update_on_different_projects_without_rights
3964 def test_bulk_update_on_different_projects_without_rights
3944 @request.session[:user_id] = 3
3965 @request.session[:user_id] = 3
3945 user = User.find(3)
3966 user = User.find(3)
3946 action = { :controller => "issues", :action => "bulk_update" }
3967 action = { :controller => "issues", :action => "bulk_update" }
3947 assert user.allowed_to?(action, Issue.find(1).project)
3968 assert user.allowed_to?(action, Issue.find(1).project)
3948 assert ! user.allowed_to?(action, Issue.find(6).project)
3969 assert ! user.allowed_to?(action, Issue.find(6).project)
3949 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
3970 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
3950 :issue => {:priority_id => 7,
3971 :issue => {:priority_id => 7,
3951 :assigned_to_id => '',
3972 :assigned_to_id => '',
3952 :custom_field_values => {'2' => ''}}
3973 :custom_field_values => {'2' => ''}}
3953 assert_response 403
3974 assert_response 403
3954 assert_not_equal "Bulk should fail", Journal.last.notes
3975 assert_not_equal "Bulk should fail", Journal.last.notes
3955 end
3976 end
3956
3977
3957 def test_bullk_update_should_send_a_notification
3978 def test_bullk_update_should_send_a_notification
3958 @request.session[:user_id] = 2
3979 @request.session[:user_id] = 2
3959 ActionMailer::Base.deliveries.clear
3980 ActionMailer::Base.deliveries.clear
3960 with_settings :notified_events => %w(issue_updated) do
3981 with_settings :notified_events => %w(issue_updated) do
3961 post(:bulk_update,
3982 post(:bulk_update,
3962 {
3983 {
3963 :ids => [1, 2],
3984 :ids => [1, 2],
3964 :notes => 'Bulk editing',
3985 :notes => 'Bulk editing',
3965 :issue => {
3986 :issue => {
3966 :priority_id => 7,
3987 :priority_id => 7,
3967 :assigned_to_id => '',
3988 :assigned_to_id => '',
3968 :custom_field_values => {'2' => ''}
3989 :custom_field_values => {'2' => ''}
3969 }
3990 }
3970 })
3991 })
3971 assert_response 302
3992 assert_response 302
3972 assert_equal 2, ActionMailer::Base.deliveries.size
3993 assert_equal 2, ActionMailer::Base.deliveries.size
3973 end
3994 end
3974 end
3995 end
3975
3996
3976 def test_bulk_update_project
3997 def test_bulk_update_project
3977 @request.session[:user_id] = 2
3998 @request.session[:user_id] = 2
3978 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}
3999 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}
3979 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4000 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3980 # Issues moved to project 2
4001 # Issues moved to project 2
3981 assert_equal 2, Issue.find(1).project_id
4002 assert_equal 2, Issue.find(1).project_id
3982 assert_equal 2, Issue.find(2).project_id
4003 assert_equal 2, Issue.find(2).project_id
3983 # No tracker change
4004 # No tracker change
3984 assert_equal 1, Issue.find(1).tracker_id
4005 assert_equal 1, Issue.find(1).tracker_id
3985 assert_equal 2, Issue.find(2).tracker_id
4006 assert_equal 2, Issue.find(2).tracker_id
3986 end
4007 end
3987
4008
3988 def test_bulk_update_project_on_single_issue_should_follow_when_needed
4009 def test_bulk_update_project_on_single_issue_should_follow_when_needed
3989 @request.session[:user_id] = 2
4010 @request.session[:user_id] = 2
3990 post :bulk_update, :id => 1, :issue => {:project_id => '2'}, :follow => '1'
4011 post :bulk_update, :id => 1, :issue => {:project_id => '2'}, :follow => '1'
3991 assert_redirected_to '/issues/1'
4012 assert_redirected_to '/issues/1'
3992 end
4013 end
3993
4014
3994 def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
4015 def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
3995 @request.session[:user_id] = 2
4016 @request.session[:user_id] = 2
3996 post :bulk_update, :id => [1, 2], :issue => {:project_id => '2'}, :follow => '1'
4017 post :bulk_update, :id => [1, 2], :issue => {:project_id => '2'}, :follow => '1'
3997 assert_redirected_to '/projects/onlinestore/issues'
4018 assert_redirected_to '/projects/onlinestore/issues'
3998 end
4019 end
3999
4020
4000 def test_bulk_update_tracker
4021 def test_bulk_update_tracker
4001 @request.session[:user_id] = 2
4022 @request.session[:user_id] = 2
4002 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2'}
4023 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2'}
4003 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4024 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4004 assert_equal 2, Issue.find(1).tracker_id
4025 assert_equal 2, Issue.find(1).tracker_id
4005 assert_equal 2, Issue.find(2).tracker_id
4026 assert_equal 2, Issue.find(2).tracker_id
4006 end
4027 end
4007
4028
4008 def test_bulk_update_status
4029 def test_bulk_update_status
4009 @request.session[:user_id] = 2
4030 @request.session[:user_id] = 2
4010 # update issues priority
4031 # update issues priority
4011 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
4032 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
4012 :issue => {:priority_id => '',
4033 :issue => {:priority_id => '',
4013 :assigned_to_id => '',
4034 :assigned_to_id => '',
4014 :status_id => '5'}
4035 :status_id => '5'}
4015
4036
4016 assert_response 302
4037 assert_response 302
4017 issue = Issue.find(1)
4038 issue = Issue.find(1)
4018 assert issue.closed?
4039 assert issue.closed?
4019 end
4040 end
4020
4041
4021 def test_bulk_update_priority
4042 def test_bulk_update_priority
4022 @request.session[:user_id] = 2
4043 @request.session[:user_id] = 2
4023 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
4044 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
4024
4045
4025 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4046 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4026 assert_equal 6, Issue.find(1).priority_id
4047 assert_equal 6, Issue.find(1).priority_id
4027 assert_equal 6, Issue.find(2).priority_id
4048 assert_equal 6, Issue.find(2).priority_id
4028 end
4049 end
4029
4050
4030 def test_bulk_update_with_notes
4051 def test_bulk_update_with_notes
4031 @request.session[:user_id] = 2
4052 @request.session[:user_id] = 2
4032 post :bulk_update, :ids => [1, 2], :notes => 'Moving two issues'
4053 post :bulk_update, :ids => [1, 2], :notes => 'Moving two issues'
4033
4054
4034 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4055 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4035 assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
4056 assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
4036 assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
4057 assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
4037 end
4058 end
4038
4059
4039 def test_bulk_update_parent_id
4060 def test_bulk_update_parent_id
4040 IssueRelation.delete_all
4061 IssueRelation.delete_all
4041 @request.session[:user_id] = 2
4062 @request.session[:user_id] = 2
4042 post :bulk_update, :ids => [1, 3],
4063 post :bulk_update, :ids => [1, 3],
4043 :notes => 'Bulk editing parent',
4064 :notes => 'Bulk editing parent',
4044 :issue => {:priority_id => '', :assigned_to_id => '',
4065 :issue => {:priority_id => '', :assigned_to_id => '',
4045 :status_id => '', :parent_issue_id => '2'}
4066 :status_id => '', :parent_issue_id => '2'}
4046 assert_response 302
4067 assert_response 302
4047 parent = Issue.find(2)
4068 parent = Issue.find(2)
4048 assert_equal parent.id, Issue.find(1).parent_id
4069 assert_equal parent.id, Issue.find(1).parent_id
4049 assert_equal parent.id, Issue.find(3).parent_id
4070 assert_equal parent.id, Issue.find(3).parent_id
4050 assert_equal [1, 3], parent.children.collect(&:id).sort
4071 assert_equal [1, 3], parent.children.collect(&:id).sort
4051 end
4072 end
4052
4073
4053 def test_bulk_update_estimated_hours
4074 def test_bulk_update_estimated_hours
4054 @request.session[:user_id] = 2
4075 @request.session[:user_id] = 2
4055 post :bulk_update, :ids => [1, 2], :issue => {:estimated_hours => 4.25}
4076 post :bulk_update, :ids => [1, 2], :issue => {:estimated_hours => 4.25}
4056
4077
4057 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4078 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
4058 assert_equal 4.25, Issue.find(1).estimated_hours
4079 assert_equal 4.25, Issue.find(1).estimated_hours
4059 assert_equal 4.25, Issue.find(2).estimated_hours
4080 assert_equal 4.25, Issue.find(2).estimated_hours
4060 end
4081 end
4061
4082
4062 def test_bulk_update_custom_field
4083 def test_bulk_update_custom_field
4063 @request.session[:user_id] = 2
4084 @request.session[:user_id] = 2
4064 # update issues priority
4085 # update issues priority
4065 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
4086 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
4066 :issue => {:priority_id => '',
4087 :issue => {:priority_id => '',
4067 :assigned_to_id => '',
4088 :assigned_to_id => '',
4068 :custom_field_values => {'2' => '777'}}
4089 :custom_field_values => {'2' => '777'}}
4069
4090
4070 assert_response 302
4091 assert_response 302
4071
4092
4072 issue = Issue.find(1)
4093 issue = Issue.find(1)
4073 journal = issue.journals.reorder('created_on DESC').first
4094 journal = issue.journals.reorder('created_on DESC').first
4074 assert_equal '777', issue.custom_value_for(2).value
4095 assert_equal '777', issue.custom_value_for(2).value
4075 assert_equal 1, journal.details.size
4096 assert_equal 1, journal.details.size
4076 assert_equal '125', journal.details.first.old_value
4097 assert_equal '125', journal.details.first.old_value
4077 assert_equal '777', journal.details.first.value
4098 assert_equal '777', journal.details.first.value
4078 end
4099 end
4079
4100
4080 def test_bulk_update_custom_field_to_blank
4101 def test_bulk_update_custom_field_to_blank
4081 @request.session[:user_id] = 2
4102 @request.session[:user_id] = 2
4082 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing custom field',
4103 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing custom field',
4083 :issue => {:priority_id => '',
4104 :issue => {:priority_id => '',
4084 :assigned_to_id => '',
4105 :assigned_to_id => '',
4085 :custom_field_values => {'1' => '__none__'}}
4106 :custom_field_values => {'1' => '__none__'}}
4086 assert_response 302
4107 assert_response 302
4087 assert_equal '', Issue.find(1).custom_field_value(1)
4108 assert_equal '', Issue.find(1).custom_field_value(1)
4088 assert_equal '', Issue.find(3).custom_field_value(1)
4109 assert_equal '', Issue.find(3).custom_field_value(1)
4089 end
4110 end
4090
4111
4091 def test_bulk_update_multi_custom_field
4112 def test_bulk_update_multi_custom_field
4092 field = CustomField.find(1)
4113 field = CustomField.find(1)
4093 field.update_attribute :multiple, true
4114 field.update_attribute :multiple, true
4094
4115
4095 @request.session[:user_id] = 2
4116 @request.session[:user_id] = 2
4096 post :bulk_update, :ids => [1, 2, 3], :notes => 'Bulk editing multi custom field',
4117 post :bulk_update, :ids => [1, 2, 3], :notes => 'Bulk editing multi custom field',
4097 :issue => {:priority_id => '',
4118 :issue => {:priority_id => '',
4098 :assigned_to_id => '',
4119 :assigned_to_id => '',
4099 :custom_field_values => {'1' => ['MySQL', 'Oracle']}}
4120 :custom_field_values => {'1' => ['MySQL', 'Oracle']}}
4100
4121
4101 assert_response 302
4122 assert_response 302
4102
4123
4103 assert_equal ['MySQL', 'Oracle'], Issue.find(1).custom_field_value(1).sort
4124 assert_equal ['MySQL', 'Oracle'], Issue.find(1).custom_field_value(1).sort
4104 assert_equal ['MySQL', 'Oracle'], Issue.find(3).custom_field_value(1).sort
4125 assert_equal ['MySQL', 'Oracle'], Issue.find(3).custom_field_value(1).sort
4105 # the custom field is not associated with the issue tracker
4126 # the custom field is not associated with the issue tracker
4106 assert_nil Issue.find(2).custom_field_value(1)
4127 assert_nil Issue.find(2).custom_field_value(1)
4107 end
4128 end
4108
4129
4109 def test_bulk_update_multi_custom_field_to_blank
4130 def test_bulk_update_multi_custom_field_to_blank
4110 field = CustomField.find(1)
4131 field = CustomField.find(1)
4111 field.update_attribute :multiple, true
4132 field.update_attribute :multiple, true
4112
4133
4113 @request.session[:user_id] = 2
4134 @request.session[:user_id] = 2
4114 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing multi custom field',
4135 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing multi custom field',
4115 :issue => {:priority_id => '',
4136 :issue => {:priority_id => '',
4116 :assigned_to_id => '',
4137 :assigned_to_id => '',
4117 :custom_field_values => {'1' => ['__none__']}}
4138 :custom_field_values => {'1' => ['__none__']}}
4118 assert_response 302
4139 assert_response 302
4119 assert_equal [''], Issue.find(1).custom_field_value(1)
4140 assert_equal [''], Issue.find(1).custom_field_value(1)
4120 assert_equal [''], Issue.find(3).custom_field_value(1)
4141 assert_equal [''], Issue.find(3).custom_field_value(1)
4121 end
4142 end
4122
4143
4123 def test_bulk_update_unassign
4144 def test_bulk_update_unassign
4124 assert_not_nil Issue.find(2).assigned_to
4145 assert_not_nil Issue.find(2).assigned_to
4125 @request.session[:user_id] = 2
4146 @request.session[:user_id] = 2
4126 # unassign issues
4147 # unassign issues
4127 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
4148 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
4128 assert_response 302
4149 assert_response 302
4129 # check that the issues were updated
4150 # check that the issues were updated
4130 assert_nil Issue.find(2).assigned_to
4151 assert_nil Issue.find(2).assigned_to
4131 end
4152 end
4132
4153
4133 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
4154 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
4134 @request.session[:user_id] = 2
4155 @request.session[:user_id] = 2
4135
4156
4136 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
4157 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
4137
4158
4138 assert_response :redirect
4159 assert_response :redirect
4139 issues = Issue.find([1,2])
4160 issues = Issue.find([1,2])
4140 issues.each do |issue|
4161 issues.each do |issue|
4141 assert_equal 4, issue.fixed_version_id
4162 assert_equal 4, issue.fixed_version_id
4142 assert_not_equal issue.project_id, issue.fixed_version.project_id
4163 assert_not_equal issue.project_id, issue.fixed_version.project_id
4143 end
4164 end
4144 end
4165 end
4145
4166
4146 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
4167 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
4147 @request.session[:user_id] = 2
4168 @request.session[:user_id] = 2
4148 post :bulk_update, :ids => [1,2], :back_url => '/issues'
4169 post :bulk_update, :ids => [1,2], :back_url => '/issues'
4149
4170
4150 assert_response :redirect
4171 assert_response :redirect
4151 assert_redirected_to '/issues'
4172 assert_redirected_to '/issues'
4152 end
4173 end
4153
4174
4154 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
4175 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
4155 @request.session[:user_id] = 2
4176 @request.session[:user_id] = 2
4156 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
4177 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
4157
4178
4158 assert_response :redirect
4179 assert_response :redirect
4159 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
4180 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
4160 end
4181 end
4161
4182
4162 def test_bulk_update_with_all_failures_should_show_errors
4183 def test_bulk_update_with_all_failures_should_show_errors
4163 @request.session[:user_id] = 2
4184 @request.session[:user_id] = 2
4164 post :bulk_update, :ids => [1, 2], :issue => {:start_date => 'foo'}
4185 post :bulk_update, :ids => [1, 2], :issue => {:start_date => 'foo'}
4165
4186
4166 assert_response :success
4187 assert_response :success
4167 assert_template 'bulk_edit'
4188 assert_template 'bulk_edit'
4168 assert_select '#errorExplanation span', :text => 'Failed to save 2 issue(s) on 2 selected: #1, #2.'
4189 assert_select '#errorExplanation span', :text => 'Failed to save 2 issue(s) on 2 selected: #1, #2.'
4169 assert_select '#errorExplanation ul li', :text => 'Start date is not a valid date: #1, #2'
4190 assert_select '#errorExplanation ul li', :text => 'Start date is not a valid date: #1, #2'
4170
4191
4171 assert_equal [1, 2], assigns[:issues].map(&:id)
4192 assert_equal [1, 2], assigns[:issues].map(&:id)
4172 end
4193 end
4173
4194
4174 def test_bulk_update_with_some_failures_should_show_errors
4195 def test_bulk_update_with_some_failures_should_show_errors
4175 issue1 = Issue.generate!(:start_date => '2013-05-12')
4196 issue1 = Issue.generate!(:start_date => '2013-05-12')
4176 issue2 = Issue.generate!(:start_date => '2013-05-15')
4197 issue2 = Issue.generate!(:start_date => '2013-05-15')
4177 issue3 = Issue.generate!
4198 issue3 = Issue.generate!
4178 @request.session[:user_id] = 2
4199 @request.session[:user_id] = 2
4179 post :bulk_update, :ids => [issue1.id, issue2.id, issue3.id],
4200 post :bulk_update, :ids => [issue1.id, issue2.id, issue3.id],
4180 :issue => {:due_date => '2013-05-01'}
4201 :issue => {:due_date => '2013-05-01'}
4181 assert_response :success
4202 assert_response :success
4182 assert_template 'bulk_edit'
4203 assert_template 'bulk_edit'
4183 assert_select '#errorExplanation span',
4204 assert_select '#errorExplanation span',
4184 :text => "Failed to save 2 issue(s) on 3 selected: ##{issue1.id}, ##{issue2.id}."
4205 :text => "Failed to save 2 issue(s) on 3 selected: ##{issue1.id}, ##{issue2.id}."
4185 assert_select '#errorExplanation ul li',
4206 assert_select '#errorExplanation ul li',
4186 :text => "Due date must be greater than start date: ##{issue1.id}, ##{issue2.id}"
4207 :text => "Due date must be greater than start date: ##{issue1.id}, ##{issue2.id}"
4187 assert_equal [issue1.id, issue2.id], assigns[:issues].map(&:id)
4208 assert_equal [issue1.id, issue2.id], assigns[:issues].map(&:id)
4188 end
4209 end
4189
4210
4190 def test_bulk_update_with_failure_should_preserved_form_values
4211 def test_bulk_update_with_failure_should_preserved_form_values
4191 @request.session[:user_id] = 2
4212 @request.session[:user_id] = 2
4192 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2', :start_date => 'foo'}
4213 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2', :start_date => 'foo'}
4193
4214
4194 assert_response :success
4215 assert_response :success
4195 assert_template 'bulk_edit'
4216 assert_template 'bulk_edit'
4196 assert_select 'select[name=?]', 'issue[tracker_id]' do
4217 assert_select 'select[name=?]', 'issue[tracker_id]' do
4197 assert_select 'option[value="2"][selected=selected]'
4218 assert_select 'option[value="2"][selected=selected]'
4198 end
4219 end
4199 assert_select 'input[name=?][value=?]', 'issue[start_date]', 'foo'
4220 assert_select 'input[name=?][value=?]', 'issue[start_date]', 'foo'
4200 end
4221 end
4201
4222
4202 def test_get_bulk_copy
4223 def test_get_bulk_copy
4203 @request.session[:user_id] = 2
4224 @request.session[:user_id] = 2
4204 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
4225 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
4205 assert_response :success
4226 assert_response :success
4206 assert_template 'bulk_edit'
4227 assert_template 'bulk_edit'
4207
4228
4208 issues = assigns(:issues)
4229 issues = assigns(:issues)
4209 assert_not_nil issues
4230 assert_not_nil issues
4210 assert_equal [1, 2, 3], issues.map(&:id).sort
4231 assert_equal [1, 2, 3], issues.map(&:id).sort
4211
4232
4212 assert_select 'select[name=?]', 'issue[project_id]' do
4233 assert_select 'select[name=?]', 'issue[project_id]' do
4213 assert_select 'option[value=""]'
4234 assert_select 'option[value=""]'
4214 end
4235 end
4215 assert_select 'input[name=copy_attachments]'
4236 assert_select 'input[name=copy_attachments]'
4216 end
4237 end
4217
4238
4218 def test_get_bulk_copy_without_add_issues_permission_should_not_propose_current_project_as_target
4239 def test_get_bulk_copy_without_add_issues_permission_should_not_propose_current_project_as_target
4219 user = setup_user_with_copy_but_not_add_permission
4240 user = setup_user_with_copy_but_not_add_permission
4220 @request.session[:user_id] = user.id
4241 @request.session[:user_id] = user.id
4221
4242
4222 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
4243 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
4223 assert_response :success
4244 assert_response :success
4224 assert_template 'bulk_edit'
4245 assert_template 'bulk_edit'
4225
4246
4226 assert_select 'select[name=?]', 'issue[project_id]' do
4247 assert_select 'select[name=?]', 'issue[project_id]' do
4227 assert_select 'option[value=""]', 0
4248 assert_select 'option[value=""]', 0
4228 assert_select 'option[value="2"]'
4249 assert_select 'option[value="2"]'
4229 end
4250 end
4230 end
4251 end
4231
4252
4232 def test_bulk_copy_to_another_project
4253 def test_bulk_copy_to_another_project
4233 @request.session[:user_id] = 2
4254 @request.session[:user_id] = 2
4234 assert_difference 'Issue.count', 2 do
4255 assert_difference 'Issue.count', 2 do
4235 assert_no_difference 'Project.find(1).issues.count' do
4256 assert_no_difference 'Project.find(1).issues.count' do
4236 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}, :copy => '1'
4257 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}, :copy => '1'
4237 end
4258 end
4238 end
4259 end
4239 assert_redirected_to '/projects/ecookbook/issues'
4260 assert_redirected_to '/projects/ecookbook/issues'
4240
4261
4241 copies = Issue.order('id DESC').limit(issues.size)
4262 copies = Issue.order('id DESC').limit(issues.size)
4242 copies.each do |copy|
4263 copies.each do |copy|
4243 assert_equal 2, copy.project_id
4264 assert_equal 2, copy.project_id
4244 end
4265 end
4245 end
4266 end
4246
4267
4247 def test_bulk_copy_without_add_issues_permission_should_be_allowed_on_project_with_permission
4268 def test_bulk_copy_without_add_issues_permission_should_be_allowed_on_project_with_permission
4248 user = setup_user_with_copy_but_not_add_permission
4269 user = setup_user_with_copy_but_not_add_permission
4249 @request.session[:user_id] = user.id
4270 @request.session[:user_id] = user.id
4250
4271
4251 assert_difference 'Issue.count', 3 do
4272 assert_difference 'Issue.count', 3 do
4252 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => '2'}, :copy => '1'
4273 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => '2'}, :copy => '1'
4253 assert_response 302
4274 assert_response 302
4254 end
4275 end
4255 end
4276 end
4256
4277
4257 def test_bulk_copy_on_same_project_without_add_issues_permission_should_be_denied
4278 def test_bulk_copy_on_same_project_without_add_issues_permission_should_be_denied
4258 user = setup_user_with_copy_but_not_add_permission
4279 user = setup_user_with_copy_but_not_add_permission
4259 @request.session[:user_id] = user.id
4280 @request.session[:user_id] = user.id
4260
4281
4261 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => ''}, :copy => '1'
4282 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => ''}, :copy => '1'
4262 assert_response 403
4283 assert_response 403
4263 end
4284 end
4264
4285
4265 def test_bulk_copy_on_different_project_without_add_issues_permission_should_be_denied
4286 def test_bulk_copy_on_different_project_without_add_issues_permission_should_be_denied
4266 user = setup_user_with_copy_but_not_add_permission
4287 user = setup_user_with_copy_but_not_add_permission
4267 @request.session[:user_id] = user.id
4288 @request.session[:user_id] = user.id
4268
4289
4269 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => '1'}, :copy => '1'
4290 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => '1'}, :copy => '1'
4270 assert_response 403
4291 assert_response 403
4271 end
4292 end
4272
4293
4273 def test_bulk_copy_should_allow_not_changing_the_issue_attributes
4294 def test_bulk_copy_should_allow_not_changing_the_issue_attributes
4274 @request.session[:user_id] = 2
4295 @request.session[:user_id] = 2
4275 issues = [
4296 issues = [
4276 Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1,
4297 Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1,
4277 :priority_id => 2, :subject => 'issue 1', :author_id => 1,
4298 :priority_id => 2, :subject => 'issue 1', :author_id => 1,
4278 :assigned_to_id => nil),
4299 :assigned_to_id => nil),
4279 Issue.create!(:project_id => 2, :tracker_id => 3, :status_id => 2,
4300 Issue.create!(:project_id => 2, :tracker_id => 3, :status_id => 2,
4280 :priority_id => 1, :subject => 'issue 2', :author_id => 2,
4301 :priority_id => 1, :subject => 'issue 2', :author_id => 2,
4281 :assigned_to_id => 3)
4302 :assigned_to_id => 3)
4282 ]
4303 ]
4283 assert_difference 'Issue.count', issues.size do
4304 assert_difference 'Issue.count', issues.size do
4284 post :bulk_update, :ids => issues.map(&:id), :copy => '1',
4305 post :bulk_update, :ids => issues.map(&:id), :copy => '1',
4285 :issue => {
4306 :issue => {
4286 :project_id => '', :tracker_id => '', :assigned_to_id => '',
4307 :project_id => '', :tracker_id => '', :assigned_to_id => '',
4287 :status_id => '', :start_date => '', :due_date => ''
4308 :status_id => '', :start_date => '', :due_date => ''
4288 }
4309 }
4289 end
4310 end
4290
4311
4291 copies = Issue.order('id DESC').limit(issues.size)
4312 copies = Issue.order('id DESC').limit(issues.size)
4292 issues.each do |orig|
4313 issues.each do |orig|
4293 copy = copies.detect {|c| c.subject == orig.subject}
4314 copy = copies.detect {|c| c.subject == orig.subject}
4294 assert_not_nil copy
4315 assert_not_nil copy
4295 assert_equal orig.project_id, copy.project_id
4316 assert_equal orig.project_id, copy.project_id
4296 assert_equal orig.tracker_id, copy.tracker_id
4317 assert_equal orig.tracker_id, copy.tracker_id
4297 assert_equal orig.status_id, copy.status_id
4318 assert_equal orig.status_id, copy.status_id
4298 assert_equal orig.assigned_to_id, copy.assigned_to_id
4319 assert_equal orig.assigned_to_id, copy.assigned_to_id
4299 assert_equal orig.priority_id, copy.priority_id
4320 assert_equal orig.priority_id, copy.priority_id
4300 end
4321 end
4301 end
4322 end
4302
4323
4303 def test_bulk_copy_should_allow_changing_the_issue_attributes
4324 def test_bulk_copy_should_allow_changing_the_issue_attributes
4304 # Fixes random test failure with Mysql
4325 # Fixes random test failure with Mysql
4305 # where Issue.where(:project_id => 2).limit(2).order('id desc')
4326 # where Issue.where(:project_id => 2).limit(2).order('id desc')
4306 # doesn't return the expected results
4327 # doesn't return the expected results
4307 Issue.delete_all("project_id=2")
4328 Issue.delete_all("project_id=2")
4308
4329
4309 @request.session[:user_id] = 2
4330 @request.session[:user_id] = 2
4310 assert_difference 'Issue.count', 2 do
4331 assert_difference 'Issue.count', 2 do
4311 assert_no_difference 'Project.find(1).issues.count' do
4332 assert_no_difference 'Project.find(1).issues.count' do
4312 post :bulk_update, :ids => [1, 2], :copy => '1',
4333 post :bulk_update, :ids => [1, 2], :copy => '1',
4313 :issue => {
4334 :issue => {
4314 :project_id => '2', :tracker_id => '', :assigned_to_id => '2',
4335 :project_id => '2', :tracker_id => '', :assigned_to_id => '2',
4315 :status_id => '1', :start_date => '2009-12-01', :due_date => '2009-12-31'
4336 :status_id => '1', :start_date => '2009-12-01', :due_date => '2009-12-31'
4316 }
4337 }
4317 end
4338 end
4318 end
4339 end
4319
4340
4320 copied_issues = Issue.where(:project_id => 2).limit(2).order('id desc').to_a
4341 copied_issues = Issue.where(:project_id => 2).limit(2).order('id desc').to_a
4321 assert_equal 2, copied_issues.size
4342 assert_equal 2, copied_issues.size
4322 copied_issues.each do |issue|
4343 copied_issues.each do |issue|
4323 assert_equal 2, issue.project_id, "Project is incorrect"
4344 assert_equal 2, issue.project_id, "Project is incorrect"
4324 assert_equal 2, issue.assigned_to_id, "Assigned to is incorrect"
4345 assert_equal 2, issue.assigned_to_id, "Assigned to is incorrect"
4325 assert_equal 1, issue.status_id, "Status is incorrect"
4346 assert_equal 1, issue.status_id, "Status is incorrect"
4326 assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
4347 assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
4327 assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
4348 assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
4328 end
4349 end
4329 end
4350 end
4330
4351
4331 def test_bulk_copy_should_allow_adding_a_note
4352 def test_bulk_copy_should_allow_adding_a_note
4332 @request.session[:user_id] = 2
4353 @request.session[:user_id] = 2
4333 assert_difference 'Issue.count', 1 do
4354 assert_difference 'Issue.count', 1 do
4334 post :bulk_update, :ids => [1], :copy => '1',
4355 post :bulk_update, :ids => [1], :copy => '1',
4335 :notes => 'Copying one issue',
4356 :notes => 'Copying one issue',
4336 :issue => {
4357 :issue => {
4337 :project_id => '', :tracker_id => '', :assigned_to_id => '4',
4358 :project_id => '', :tracker_id => '', :assigned_to_id => '4',
4338 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
4359 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
4339 }
4360 }
4340 end
4361 end
4341 issue = Issue.order('id DESC').first
4362 issue = Issue.order('id DESC').first
4342 assert_equal 1, issue.journals.size
4363 assert_equal 1, issue.journals.size
4343 journal = issue.journals.first
4364 journal = issue.journals.first
4344 assert_equal 'Copying one issue', journal.notes
4365 assert_equal 'Copying one issue', journal.notes
4345 end
4366 end
4346
4367
4347 def test_bulk_copy_should_allow_not_copying_the_attachments
4368 def test_bulk_copy_should_allow_not_copying_the_attachments
4348 attachment_count = Issue.find(3).attachments.size
4369 attachment_count = Issue.find(3).attachments.size
4349 assert attachment_count > 0
4370 assert attachment_count > 0
4350 @request.session[:user_id] = 2
4371 @request.session[:user_id] = 2
4351
4372
4352 assert_difference 'Issue.count', 1 do
4373 assert_difference 'Issue.count', 1 do
4353 assert_no_difference 'Attachment.count' do
4374 assert_no_difference 'Attachment.count' do
4354 post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '0',
4375 post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '0',
4355 :issue => {
4376 :issue => {
4356 :project_id => ''
4377 :project_id => ''
4357 }
4378 }
4358 end
4379 end
4359 end
4380 end
4360 end
4381 end
4361
4382
4362 def test_bulk_copy_should_allow_copying_the_attachments
4383 def test_bulk_copy_should_allow_copying_the_attachments
4363 attachment_count = Issue.find(3).attachments.size
4384 attachment_count = Issue.find(3).attachments.size
4364 assert attachment_count > 0
4385 assert attachment_count > 0
4365 @request.session[:user_id] = 2
4386 @request.session[:user_id] = 2
4366
4387
4367 assert_difference 'Issue.count', 1 do
4388 assert_difference 'Issue.count', 1 do
4368 assert_difference 'Attachment.count', attachment_count do
4389 assert_difference 'Attachment.count', attachment_count do
4369 post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '1',
4390 post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '1',
4370 :issue => {
4391 :issue => {
4371 :project_id => ''
4392 :project_id => ''
4372 }
4393 }
4373 end
4394 end
4374 end
4395 end
4375 end
4396 end
4376
4397
4377 def test_bulk_copy_should_add_relations_with_copied_issues
4398 def test_bulk_copy_should_add_relations_with_copied_issues
4378 @request.session[:user_id] = 2
4399 @request.session[:user_id] = 2
4379
4400
4380 assert_difference 'Issue.count', 2 do
4401 assert_difference 'Issue.count', 2 do
4381 assert_difference 'IssueRelation.count', 2 do
4402 assert_difference 'IssueRelation.count', 2 do
4382 post :bulk_update, :ids => [1, 3], :copy => '1', :link_copy => '1',
4403 post :bulk_update, :ids => [1, 3], :copy => '1', :link_copy => '1',
4383 :issue => {
4404 :issue => {
4384 :project_id => '1'
4405 :project_id => '1'
4385 }
4406 }
4386 end
4407 end
4387 end
4408 end
4388 end
4409 end
4389
4410
4390 def test_bulk_copy_should_allow_not_copying_the_subtasks
4411 def test_bulk_copy_should_allow_not_copying_the_subtasks
4391 issue = Issue.generate_with_descendants!
4412 issue = Issue.generate_with_descendants!
4392 @request.session[:user_id] = 2
4413 @request.session[:user_id] = 2
4393
4414
4394 assert_difference 'Issue.count', 1 do
4415 assert_difference 'Issue.count', 1 do
4395 post :bulk_update, :ids => [issue.id], :copy => '1', :copy_subtasks => '0',
4416 post :bulk_update, :ids => [issue.id], :copy => '1', :copy_subtasks => '0',
4396 :issue => {
4417 :issue => {
4397 :project_id => ''
4418 :project_id => ''
4398 }
4419 }
4399 end
4420 end
4400 end
4421 end
4401
4422
4402 def test_bulk_copy_should_allow_copying_the_subtasks
4423 def test_bulk_copy_should_allow_copying_the_subtasks
4403 issue = Issue.generate_with_descendants!
4424 issue = Issue.generate_with_descendants!
4404 count = issue.descendants.count
4425 count = issue.descendants.count
4405 @request.session[:user_id] = 2
4426 @request.session[:user_id] = 2
4406
4427
4407 assert_difference 'Issue.count', count+1 do
4428 assert_difference 'Issue.count', count+1 do
4408 post :bulk_update, :ids => [issue.id], :copy => '1', :copy_subtasks => '1',
4429 post :bulk_update, :ids => [issue.id], :copy => '1', :copy_subtasks => '1',
4409 :issue => {
4430 :issue => {
4410 :project_id => ''
4431 :project_id => ''
4411 }
4432 }
4412 end
4433 end
4413 copy = Issue.where(:parent_id => nil).order("id DESC").first
4434 copy = Issue.where(:parent_id => nil).order("id DESC").first
4414 assert_equal count, copy.descendants.count
4435 assert_equal count, copy.descendants.count
4415 end
4436 end
4416
4437
4417 def test_bulk_copy_should_not_copy_selected_subtasks_twice
4438 def test_bulk_copy_should_not_copy_selected_subtasks_twice
4418 issue = Issue.generate_with_descendants!
4439 issue = Issue.generate_with_descendants!
4419 count = issue.descendants.count
4440 count = issue.descendants.count
4420 @request.session[:user_id] = 2
4441 @request.session[:user_id] = 2
4421
4442
4422 assert_difference 'Issue.count', count+1 do
4443 assert_difference 'Issue.count', count+1 do
4423 post :bulk_update, :ids => issue.self_and_descendants.map(&:id), :copy => '1', :copy_subtasks => '1',
4444 post :bulk_update, :ids => issue.self_and_descendants.map(&:id), :copy => '1', :copy_subtasks => '1',
4424 :issue => {
4445 :issue => {
4425 :project_id => ''
4446 :project_id => ''
4426 }
4447 }
4427 end
4448 end
4428 copy = Issue.where(:parent_id => nil).order("id DESC").first
4449 copy = Issue.where(:parent_id => nil).order("id DESC").first
4429 assert_equal count, copy.descendants.count
4450 assert_equal count, copy.descendants.count
4430 end
4451 end
4431
4452
4432 def test_bulk_copy_to_another_project_should_follow_when_needed
4453 def test_bulk_copy_to_another_project_should_follow_when_needed
4433 @request.session[:user_id] = 2
4454 @request.session[:user_id] = 2
4434 post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
4455 post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
4435 issue = Issue.order('id DESC').first
4456 issue = Issue.order('id DESC').first
4436 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
4457 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
4437 end
4458 end
4438
4459
4439 def test_bulk_copy_with_all_failures_should_display_errors
4460 def test_bulk_copy_with_all_failures_should_display_errors
4440 @request.session[:user_id] = 2
4461 @request.session[:user_id] = 2
4441 post :bulk_update, :ids => [1, 2], :copy => '1', :issue => {:start_date => 'foo'}
4462 post :bulk_update, :ids => [1, 2], :copy => '1', :issue => {:start_date => 'foo'}
4442
4463
4443 assert_response :success
4464 assert_response :success
4444 end
4465 end
4445
4466
4446 def test_destroy_issue_with_no_time_entries
4467 def test_destroy_issue_with_no_time_entries
4447 assert_nil TimeEntry.find_by_issue_id(2)
4468 assert_nil TimeEntry.find_by_issue_id(2)
4448 @request.session[:user_id] = 2
4469 @request.session[:user_id] = 2
4449
4470
4450 assert_difference 'Issue.count', -1 do
4471 assert_difference 'Issue.count', -1 do
4451 delete :destroy, :id => 2
4472 delete :destroy, :id => 2
4452 end
4473 end
4453 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4474 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4454 assert_nil Issue.find_by_id(2)
4475 assert_nil Issue.find_by_id(2)
4455 end
4476 end
4456
4477
4457 def test_destroy_issues_with_time_entries
4478 def test_destroy_issues_with_time_entries
4458 @request.session[:user_id] = 2
4479 @request.session[:user_id] = 2
4459
4480
4460 assert_no_difference 'Issue.count' do
4481 assert_no_difference 'Issue.count' do
4461 delete :destroy, :ids => [1, 3]
4482 delete :destroy, :ids => [1, 3]
4462 end
4483 end
4463 assert_response :success
4484 assert_response :success
4464 assert_template 'destroy'
4485 assert_template 'destroy'
4465 assert_not_nil assigns(:hours)
4486 assert_not_nil assigns(:hours)
4466 assert Issue.find_by_id(1) && Issue.find_by_id(3)
4487 assert Issue.find_by_id(1) && Issue.find_by_id(3)
4467
4488
4468 assert_select 'form' do
4489 assert_select 'form' do
4469 assert_select 'input[name=_method][value=delete]'
4490 assert_select 'input[name=_method][value=delete]'
4470 end
4491 end
4471 end
4492 end
4472
4493
4473 def test_destroy_issues_and_destroy_time_entries
4494 def test_destroy_issues_and_destroy_time_entries
4474 @request.session[:user_id] = 2
4495 @request.session[:user_id] = 2
4475
4496
4476 assert_difference 'Issue.count', -2 do
4497 assert_difference 'Issue.count', -2 do
4477 assert_difference 'TimeEntry.count', -3 do
4498 assert_difference 'TimeEntry.count', -3 do
4478 delete :destroy, :ids => [1, 3], :todo => 'destroy'
4499 delete :destroy, :ids => [1, 3], :todo => 'destroy'
4479 end
4500 end
4480 end
4501 end
4481 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4502 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4482 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4503 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4483 assert_nil TimeEntry.find_by_id([1, 2])
4504 assert_nil TimeEntry.find_by_id([1, 2])
4484 end
4505 end
4485
4506
4486 def test_destroy_issues_and_assign_time_entries_to_project
4507 def test_destroy_issues_and_assign_time_entries_to_project
4487 @request.session[:user_id] = 2
4508 @request.session[:user_id] = 2
4488
4509
4489 assert_difference 'Issue.count', -2 do
4510 assert_difference 'Issue.count', -2 do
4490 assert_no_difference 'TimeEntry.count' do
4511 assert_no_difference 'TimeEntry.count' do
4491 delete :destroy, :ids => [1, 3], :todo => 'nullify'
4512 delete :destroy, :ids => [1, 3], :todo => 'nullify'
4492 end
4513 end
4493 end
4514 end
4494 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4515 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4495 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4516 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4496 assert_nil TimeEntry.find(1).issue_id
4517 assert_nil TimeEntry.find(1).issue_id
4497 assert_nil TimeEntry.find(2).issue_id
4518 assert_nil TimeEntry.find(2).issue_id
4498 end
4519 end
4499
4520
4500 def test_destroy_issues_and_reassign_time_entries_to_another_issue
4521 def test_destroy_issues_and_reassign_time_entries_to_another_issue
4501 @request.session[:user_id] = 2
4522 @request.session[:user_id] = 2
4502
4523
4503 assert_difference 'Issue.count', -2 do
4524 assert_difference 'Issue.count', -2 do
4504 assert_no_difference 'TimeEntry.count' do
4525 assert_no_difference 'TimeEntry.count' do
4505 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
4526 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
4506 end
4527 end
4507 end
4528 end
4508 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4529 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4509 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4530 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4510 assert_equal 2, TimeEntry.find(1).issue_id
4531 assert_equal 2, TimeEntry.find(1).issue_id
4511 assert_equal 2, TimeEntry.find(2).issue_id
4532 assert_equal 2, TimeEntry.find(2).issue_id
4512 end
4533 end
4513
4534
4514 def test_destroy_issues_and_reassign_time_entries_to_an_invalid_issue_should_fail
4535 def test_destroy_issues_and_reassign_time_entries_to_an_invalid_issue_should_fail
4515 @request.session[:user_id] = 2
4536 @request.session[:user_id] = 2
4516
4537
4517 assert_no_difference 'Issue.count' do
4538 assert_no_difference 'Issue.count' do
4518 assert_no_difference 'TimeEntry.count' do
4539 assert_no_difference 'TimeEntry.count' do
4519 # try to reassign time to an issue of another project
4540 # try to reassign time to an issue of another project
4520 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 4
4541 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 4
4521 end
4542 end
4522 end
4543 end
4523 assert_response :success
4544 assert_response :success
4524 assert_template 'destroy'
4545 assert_template 'destroy'
4525 end
4546 end
4526
4547
4527 def test_destroy_issues_from_different_projects
4548 def test_destroy_issues_from_different_projects
4528 @request.session[:user_id] = 2
4549 @request.session[:user_id] = 2
4529
4550
4530 assert_difference 'Issue.count', -3 do
4551 assert_difference 'Issue.count', -3 do
4531 delete :destroy, :ids => [1, 2, 6], :todo => 'destroy'
4552 delete :destroy, :ids => [1, 2, 6], :todo => 'destroy'
4532 end
4553 end
4533 assert_redirected_to :controller => 'issues', :action => 'index'
4554 assert_redirected_to :controller => 'issues', :action => 'index'
4534 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
4555 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
4535 end
4556 end
4536
4557
4537 def test_destroy_parent_and_child_issues
4558 def test_destroy_parent_and_child_issues
4538 parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue')
4559 parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue')
4539 child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id)
4560 child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id)
4540 assert child.is_descendant_of?(parent.reload)
4561 assert child.is_descendant_of?(parent.reload)
4541
4562
4542 @request.session[:user_id] = 2
4563 @request.session[:user_id] = 2
4543 assert_difference 'Issue.count', -2 do
4564 assert_difference 'Issue.count', -2 do
4544 delete :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
4565 delete :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
4545 end
4566 end
4546 assert_response 302
4567 assert_response 302
4547 end
4568 end
4548
4569
4549 def test_destroy_invalid_should_respond_with_404
4570 def test_destroy_invalid_should_respond_with_404
4550 @request.session[:user_id] = 2
4571 @request.session[:user_id] = 2
4551 assert_no_difference 'Issue.count' do
4572 assert_no_difference 'Issue.count' do
4552 delete :destroy, :id => 999
4573 delete :destroy, :id => 999
4553 end
4574 end
4554 assert_response 404
4575 assert_response 404
4555 end
4576 end
4556
4577
4557 def test_default_search_scope
4578 def test_default_search_scope
4558 get :index
4579 get :index
4559
4580
4560 assert_select 'div#quick-search form' do
4581 assert_select 'div#quick-search form' do
4561 assert_select 'input[name=issues][value="1"][type=hidden]'
4582 assert_select 'input[name=issues][value="1"][type=hidden]'
4562 end
4583 end
4563 end
4584 end
4564
4585
4565 def setup_user_with_copy_but_not_add_permission
4586 def setup_user_with_copy_but_not_add_permission
4566 Role.all.each {|r| r.remove_permission! :add_issues}
4587 Role.all.each {|r| r.remove_permission! :add_issues}
4567 Role.find_by_name('Manager').add_permission! :add_issues
4588 Role.find_by_name('Manager').add_permission! :add_issues
4568 user = User.generate!
4589 user = User.generate!
4569 User.add_to_project(user, Project.find(1), Role.find_by_name('Developer'))
4590 User.add_to_project(user, Project.find(1), Role.find_by_name('Developer'))
4570 User.add_to_project(user, Project.find(2), Role.find_by_name('Manager'))
4591 User.add_to_project(user, Project.find(2), Role.find_by_name('Manager'))
4571 user
4592 user
4572 end
4593 end
4573 end
4594 end
@@ -1,718 +1,694
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 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 ProjectsControllerTest < ActionController::TestCase
20 class ProjectsControllerTest < ActionController::TestCase
21 fixtures :projects, :versions, :users, :email_addresses, :roles, :members,
21 fixtures :projects, :versions, :users, :email_addresses, :roles, :members,
22 :member_roles, :issues, :journals, :journal_details,
22 :member_roles, :issues, :journals, :journal_details,
23 :trackers, :projects_trackers, :issue_statuses,
23 :trackers, :projects_trackers, :issue_statuses,
24 :enabled_modules, :enumerations, :boards, :messages,
24 :enabled_modules, :enumerations, :boards, :messages,
25 :attachments, :custom_fields, :custom_values, :time_entries,
25 :attachments, :custom_fields, :custom_values, :time_entries,
26 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
26 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
27
27
28 def setup
28 def setup
29 @request.session[:user_id] = nil
29 @request.session[:user_id] = nil
30 Setting.default_language = 'en'
30 Setting.default_language = 'en'
31 end
31 end
32
32
33 def test_index_by_anonymous_should_not_show_private_projects
33 def test_index_by_anonymous_should_not_show_private_projects
34 get :index
34 get :index
35 assert_response :success
35 assert_response :success
36 assert_template 'index'
36 assert_template 'index'
37 projects = assigns(:projects)
37 projects = assigns(:projects)
38 assert_not_nil projects
38 assert_not_nil projects
39 assert projects.all?(&:is_public?)
39 assert projects.all?(&:is_public?)
40
40
41 assert_select 'ul' do
41 assert_select 'ul' do
42 assert_select 'li' do
42 assert_select 'li' do
43 assert_select 'a', :text => 'eCookbook'
43 assert_select 'a', :text => 'eCookbook'
44 assert_select 'ul' do
44 assert_select 'ul' do
45 assert_select 'a', :text => 'Child of private child'
45 assert_select 'a', :text => 'Child of private child'
46 end
46 end
47 end
47 end
48 end
48 end
49 assert_select 'a', :text => /Private child of eCookbook/, :count => 0
49 assert_select 'a', :text => /Private child of eCookbook/, :count => 0
50 end
50 end
51
51
52 def test_index_atom
52 def test_index_atom
53 get :index, :format => 'atom'
53 get :index, :format => 'atom'
54 assert_response :success
54 assert_response :success
55 assert_template 'common/feed'
55 assert_template 'common/feed'
56 assert_select 'feed>title', :text => 'Redmine: Latest projects'
56 assert_select 'feed>title', :text => 'Redmine: Latest projects'
57 assert_select 'feed>entry', :count => Project.visible(User.current).count
57 assert_select 'feed>entry', :count => Project.visible(User.current).count
58 end
58 end
59
59
60 test "#index by non-admin user with view_time_entries permission should show overall spent time link" do
60 test "#index by non-admin user with view_time_entries permission should show overall spent time link" do
61 @request.session[:user_id] = 3
61 @request.session[:user_id] = 3
62 get :index
62 get :index
63 assert_template 'index'
63 assert_template 'index'
64 assert_select 'a[href=?]', '/time_entries'
64 assert_select 'a[href=?]', '/time_entries'
65 end
65 end
66
66
67 test "#index by non-admin user without view_time_entries permission should not show overall spent time link" do
67 test "#index by non-admin user without view_time_entries permission should not show overall spent time link" do
68 Role.find(2).remove_permission! :view_time_entries
68 Role.find(2).remove_permission! :view_time_entries
69 Role.non_member.remove_permission! :view_time_entries
69 Role.non_member.remove_permission! :view_time_entries
70 Role.anonymous.remove_permission! :view_time_entries
70 Role.anonymous.remove_permission! :view_time_entries
71 @request.session[:user_id] = 3
71 @request.session[:user_id] = 3
72
72
73 get :index
73 get :index
74 assert_template 'index'
74 assert_template 'index'
75 assert_select 'a[href=?]', '/time_entries', 0
75 assert_select 'a[href=?]', '/time_entries', 0
76 end
76 end
77
77
78 test "#index by non-admin user with permission should show add project link" do
78 test "#index by non-admin user with permission should show add project link" do
79 Role.find(1).add_permission! :add_project
79 Role.find(1).add_permission! :add_project
80 @request.session[:user_id] = 2
80 @request.session[:user_id] = 2
81 get :index
81 get :index
82 assert_template 'index'
82 assert_template 'index'
83 assert_select 'a[href=?]', '/projects/new'
83 assert_select 'a[href=?]', '/projects/new'
84 end
84 end
85
85
86 test "#new by admin user should accept get" do
86 test "#new by admin user should accept get" do
87 @request.session[:user_id] = 1
87 @request.session[:user_id] = 1
88
88
89 get :new
89 get :new
90 assert_response :success
90 assert_response :success
91 assert_template 'new'
91 assert_template 'new'
92 end
92 end
93
93
94 test "#new by non-admin user with add_project permission should accept get" do
94 test "#new by non-admin user with add_project permission should accept get" do
95 Role.non_member.add_permission! :add_project
95 Role.non_member.add_permission! :add_project
96 @request.session[:user_id] = 9
96 @request.session[:user_id] = 9
97
97
98 get :new
98 get :new
99 assert_response :success
99 assert_response :success
100 assert_template 'new'
100 assert_template 'new'
101 assert_select 'select[name=?]', 'project[parent_id]', 0
101 assert_select 'select[name=?]', 'project[parent_id]', 0
102 end
102 end
103
103
104 test "#new by non-admin user with add_subprojects permission should accept get" do
104 test "#new by non-admin user with add_subprojects permission should accept get" do
105 Role.find(1).remove_permission! :add_project
105 Role.find(1).remove_permission! :add_project
106 Role.find(1).add_permission! :add_subprojects
106 Role.find(1).add_permission! :add_subprojects
107 @request.session[:user_id] = 2
107 @request.session[:user_id] = 2
108
108
109 get :new, :parent_id => 'ecookbook'
109 get :new, :parent_id => 'ecookbook'
110 assert_response :success
110 assert_response :success
111 assert_template 'new'
111 assert_template 'new'
112
112
113 assert_select 'select[name=?]', 'project[parent_id]' do
113 assert_select 'select[name=?]', 'project[parent_id]' do
114 # parent project selected
114 # parent project selected
115 assert_select 'option[value="1"][selected=selected]'
115 assert_select 'option[value="1"][selected=selected]'
116 # no empty value
116 # no empty value
117 assert_select 'option[value=""]', 0
117 assert_select 'option[value=""]', 0
118 end
118 end
119 end
119 end
120
120
121 def test_new_should_not_display_invalid_search_link
121 def test_new_should_not_display_invalid_search_link
122 @request.session[:user_id] = 1
122 @request.session[:user_id] = 1
123
123
124 get :new
124 get :new
125 assert_response :success
125 assert_response :success
126 assert_select '#quick-search form[action=?]', '/search'
126 assert_select '#quick-search form[action=?]', '/search'
127 assert_select '#quick-search a[href=?]', '/search'
127 assert_select '#quick-search a[href=?]', '/search'
128 end
128 end
129
129
130 test "#create by admin user should create a new project" do
130 test "#create by admin user should create a new project" do
131 @request.session[:user_id] = 1
131 @request.session[:user_id] = 1
132
132
133 post :create,
133 post :create,
134 :project => {
134 :project => {
135 :name => "blog",
135 :name => "blog",
136 :description => "weblog",
136 :description => "weblog",
137 :homepage => 'http://weblog',
137 :homepage => 'http://weblog',
138 :identifier => "blog",
138 :identifier => "blog",
139 :is_public => 1,
139 :is_public => 1,
140 :custom_field_values => { '3' => 'Beta' },
140 :custom_field_values => { '3' => 'Beta' },
141 :tracker_ids => ['1', '3'],
141 :tracker_ids => ['1', '3'],
142 # an issue custom field that is not for all project
142 # an issue custom field that is not for all project
143 :issue_custom_field_ids => ['9'],
143 :issue_custom_field_ids => ['9'],
144 :enabled_module_names => ['issue_tracking', 'news', 'repository']
144 :enabled_module_names => ['issue_tracking', 'news', 'repository']
145 }
145 }
146 assert_redirected_to '/projects/blog/settings'
146 assert_redirected_to '/projects/blog/settings'
147
147
148 project = Project.find_by_name('blog')
148 project = Project.find_by_name('blog')
149 assert_kind_of Project, project
149 assert_kind_of Project, project
150 assert project.active?
150 assert project.active?
151 assert_equal 'weblog', project.description
151 assert_equal 'weblog', project.description
152 assert_equal 'http://weblog', project.homepage
152 assert_equal 'http://weblog', project.homepage
153 assert_equal true, project.is_public?
153 assert_equal true, project.is_public?
154 assert_nil project.parent
154 assert_nil project.parent
155 assert_equal 'Beta', project.custom_value_for(3).value
155 assert_equal 'Beta', project.custom_value_for(3).value
156 assert_equal [1, 3], project.trackers.map(&:id).sort
156 assert_equal [1, 3], project.trackers.map(&:id).sort
157 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
157 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
158 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
158 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
159 end
159 end
160
160
161 test "#create by admin user should create a new subproject" do
161 test "#create by admin user should create a new subproject" do
162 @request.session[:user_id] = 1
162 @request.session[:user_id] = 1
163
163
164 assert_difference 'Project.count' do
164 assert_difference 'Project.count' do
165 post :create, :project => { :name => "blog",
165 post :create, :project => { :name => "blog",
166 :description => "weblog",
166 :description => "weblog",
167 :identifier => "blog",
167 :identifier => "blog",
168 :is_public => 1,
168 :is_public => 1,
169 :custom_field_values => { '3' => 'Beta' },
169 :custom_field_values => { '3' => 'Beta' },
170 :parent_id => 1
170 :parent_id => 1
171 }
171 }
172 assert_redirected_to '/projects/blog/settings'
172 assert_redirected_to '/projects/blog/settings'
173 end
173 end
174
174
175 project = Project.find_by_name('blog')
175 project = Project.find_by_name('blog')
176 assert_kind_of Project, project
176 assert_kind_of Project, project
177 assert_equal Project.find(1), project.parent
177 assert_equal Project.find(1), project.parent
178 end
178 end
179
179
180 test "#create by admin user should continue" do
180 test "#create by admin user should continue" do
181 @request.session[:user_id] = 1
181 @request.session[:user_id] = 1
182
182
183 assert_difference 'Project.count' do
183 assert_difference 'Project.count' do
184 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
184 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
185 end
185 end
186 assert_redirected_to '/projects/new'
186 assert_redirected_to '/projects/new'
187 end
187 end
188
188
189 test "#create by non-admin user with add_project permission should create a new project" do
189 test "#create by non-admin user with add_project permission should create a new project" do
190 Role.non_member.add_permission! :add_project
190 Role.non_member.add_permission! :add_project
191 @request.session[:user_id] = 9
191 @request.session[:user_id] = 9
192
192
193 post :create, :project => { :name => "blog",
193 post :create, :project => { :name => "blog",
194 :description => "weblog",
194 :description => "weblog",
195 :identifier => "blog",
195 :identifier => "blog",
196 :is_public => 1,
196 :is_public => 1,
197 :custom_field_values => { '3' => 'Beta' },
197 :custom_field_values => { '3' => 'Beta' },
198 :tracker_ids => ['1', '3'],
198 :tracker_ids => ['1', '3'],
199 :enabled_module_names => ['issue_tracking', 'news', 'repository']
199 :enabled_module_names => ['issue_tracking', 'news', 'repository']
200 }
200 }
201
201
202 assert_redirected_to '/projects/blog/settings'
202 assert_redirected_to '/projects/blog/settings'
203
203
204 project = Project.find_by_name('blog')
204 project = Project.find_by_name('blog')
205 assert_kind_of Project, project
205 assert_kind_of Project, project
206 assert_equal 'weblog', project.description
206 assert_equal 'weblog', project.description
207 assert_equal true, project.is_public?
207 assert_equal true, project.is_public?
208 assert_equal [1, 3], project.trackers.map(&:id).sort
208 assert_equal [1, 3], project.trackers.map(&:id).sort
209 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
209 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
210
210
211 # User should be added as a project member
211 # User should be added as a project member
212 assert User.find(9).member_of?(project)
212 assert User.find(9).member_of?(project)
213 assert_equal 1, project.members.size
213 assert_equal 1, project.members.size
214 end
214 end
215
215
216 test "#create by non-admin user with add_project permission should fail with parent_id" do
216 test "#create by non-admin user with add_project permission should fail with parent_id" do
217 Role.non_member.add_permission! :add_project
217 Role.non_member.add_permission! :add_project
218 @request.session[:user_id] = 9
218 @request.session[:user_id] = 9
219
219
220 assert_no_difference 'Project.count' do
220 assert_no_difference 'Project.count' do
221 post :create, :project => { :name => "blog",
221 post :create, :project => { :name => "blog",
222 :description => "weblog",
222 :description => "weblog",
223 :identifier => "blog",
223 :identifier => "blog",
224 :is_public => 1,
224 :is_public => 1,
225 :custom_field_values => { '3' => 'Beta' },
225 :custom_field_values => { '3' => 'Beta' },
226 :parent_id => 1
226 :parent_id => 1
227 }
227 }
228 end
228 end
229 assert_response :success
229 assert_response :success
230 project = assigns(:project)
230 project = assigns(:project)
231 assert_kind_of Project, project
231 assert_kind_of Project, project
232 assert_not_equal [], project.errors[:parent_id]
232 assert_not_equal [], project.errors[:parent_id]
233 end
233 end
234
234
235 test "#create by non-admin user with add_subprojects permission should create a project with a parent_id" do
235 test "#create by non-admin user with add_subprojects permission should create a project with a parent_id" do
236 Role.find(1).remove_permission! :add_project
236 Role.find(1).remove_permission! :add_project
237 Role.find(1).add_permission! :add_subprojects
237 Role.find(1).add_permission! :add_subprojects
238 @request.session[:user_id] = 2
238 @request.session[:user_id] = 2
239
239
240 post :create, :project => { :name => "blog",
240 post :create, :project => { :name => "blog",
241 :description => "weblog",
241 :description => "weblog",
242 :identifier => "blog",
242 :identifier => "blog",
243 :is_public => 1,
243 :is_public => 1,
244 :custom_field_values => { '3' => 'Beta' },
244 :custom_field_values => { '3' => 'Beta' },
245 :parent_id => 1
245 :parent_id => 1
246 }
246 }
247 assert_redirected_to '/projects/blog/settings'
247 assert_redirected_to '/projects/blog/settings'
248 project = Project.find_by_name('blog')
248 project = Project.find_by_name('blog')
249 end
249 end
250
250
251 test "#create by non-admin user with add_subprojects permission should fail without parent_id" do
251 test "#create by non-admin user with add_subprojects permission should fail without parent_id" do
252 Role.find(1).remove_permission! :add_project
252 Role.find(1).remove_permission! :add_project
253 Role.find(1).add_permission! :add_subprojects
253 Role.find(1).add_permission! :add_subprojects
254 @request.session[:user_id] = 2
254 @request.session[:user_id] = 2
255
255
256 assert_no_difference 'Project.count' do
256 assert_no_difference 'Project.count' do
257 post :create, :project => { :name => "blog",
257 post :create, :project => { :name => "blog",
258 :description => "weblog",
258 :description => "weblog",
259 :identifier => "blog",
259 :identifier => "blog",
260 :is_public => 1,
260 :is_public => 1,
261 :custom_field_values => { '3' => 'Beta' }
261 :custom_field_values => { '3' => 'Beta' }
262 }
262 }
263 end
263 end
264 assert_response :success
264 assert_response :success
265 project = assigns(:project)
265 project = assigns(:project)
266 assert_kind_of Project, project
266 assert_kind_of Project, project
267 assert_not_equal [], project.errors[:parent_id]
267 assert_not_equal [], project.errors[:parent_id]
268 end
268 end
269
269
270 test "#create by non-admin user with add_subprojects permission should fail with unauthorized parent_id" do
270 test "#create by non-admin user with add_subprojects permission should fail with unauthorized parent_id" do
271 Role.find(1).remove_permission! :add_project
271 Role.find(1).remove_permission! :add_project
272 Role.find(1).add_permission! :add_subprojects
272 Role.find(1).add_permission! :add_subprojects
273 @request.session[:user_id] = 2
273 @request.session[:user_id] = 2
274
274
275 assert !User.find(2).member_of?(Project.find(6))
275 assert !User.find(2).member_of?(Project.find(6))
276 assert_no_difference 'Project.count' do
276 assert_no_difference 'Project.count' do
277 post :create, :project => { :name => "blog",
277 post :create, :project => { :name => "blog",
278 :description => "weblog",
278 :description => "weblog",
279 :identifier => "blog",
279 :identifier => "blog",
280 :is_public => 1,
280 :is_public => 1,
281 :custom_field_values => { '3' => 'Beta' },
281 :custom_field_values => { '3' => 'Beta' },
282 :parent_id => 6
282 :parent_id => 6
283 }
283 }
284 end
284 end
285 assert_response :success
285 assert_response :success
286 project = assigns(:project)
286 project = assigns(:project)
287 assert_kind_of Project, project
287 assert_kind_of Project, project
288 assert_not_equal [], project.errors[:parent_id]
288 assert_not_equal [], project.errors[:parent_id]
289 end
289 end
290
290
291 def test_create_subproject_with_inherit_members_should_inherit_members
291 def test_create_subproject_with_inherit_members_should_inherit_members
292 Role.find_by_name('Manager').add_permission! :add_subprojects
292 Role.find_by_name('Manager').add_permission! :add_subprojects
293 parent = Project.find(1)
293 parent = Project.find(1)
294 @request.session[:user_id] = 2
294 @request.session[:user_id] = 2
295
295
296 assert_difference 'Project.count' do
296 assert_difference 'Project.count' do
297 post :create, :project => {
297 post :create, :project => {
298 :name => 'inherited', :identifier => 'inherited', :parent_id => parent.id, :inherit_members => '1'
298 :name => 'inherited', :identifier => 'inherited', :parent_id => parent.id, :inherit_members => '1'
299 }
299 }
300 assert_response 302
300 assert_response 302
301 end
301 end
302
302
303 project = Project.order('id desc').first
303 project = Project.order('id desc').first
304 assert_equal 'inherited', project.name
304 assert_equal 'inherited', project.name
305 assert_equal parent, project.parent
305 assert_equal parent, project.parent
306 assert project.memberships.count > 0
306 assert project.memberships.count > 0
307 assert_equal parent.memberships.count, project.memberships.count
307 assert_equal parent.memberships.count, project.memberships.count
308 end
308 end
309
309
310 def test_create_should_preserve_modules_on_validation_failure
310 def test_create_should_preserve_modules_on_validation_failure
311 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
311 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
312 @request.session[:user_id] = 1
312 @request.session[:user_id] = 1
313 assert_no_difference 'Project.count' do
313 assert_no_difference 'Project.count' do
314 post :create, :project => {
314 post :create, :project => {
315 :name => "blog",
315 :name => "blog",
316 :identifier => "",
316 :identifier => "",
317 :enabled_module_names => %w(issue_tracking news)
317 :enabled_module_names => %w(issue_tracking news)
318 }
318 }
319 end
319 end
320 assert_response :success
320 assert_response :success
321 project = assigns(:project)
321 project = assigns(:project)
322 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
322 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
323 end
323 end
324 end
324 end
325
325
326 def test_show_by_id
326 def test_show_by_id
327 get :show, :id => 1
327 get :show, :id => 1
328 assert_response :success
328 assert_response :success
329 assert_template 'show'
329 assert_template 'show'
330 assert_not_nil assigns(:project)
330 assert_not_nil assigns(:project)
331 end
331 end
332
332
333 def test_show_by_identifier
333 def test_show_by_identifier
334 get :show, :id => 'ecookbook'
334 get :show, :id => 'ecookbook'
335 assert_response :success
335 assert_response :success
336 assert_template 'show'
336 assert_template 'show'
337 assert_not_nil assigns(:project)
337 assert_not_nil assigns(:project)
338 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
338 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
339
339
340 assert_select 'li', :text => /Development status/
340 assert_select 'li', :text => /Development status/
341 end
341 end
342
342
343 def test_show_should_not_display_empty_sidebar
343 def test_show_should_not_display_empty_sidebar
344 p = Project.find(1)
344 p = Project.find(1)
345 p.enabled_module_names = []
345 p.enabled_module_names = []
346 p.save!
346 p.save!
347
347
348 get :show, :id => 'ecookbook'
348 get :show, :id => 'ecookbook'
349 assert_response :success
349 assert_response :success
350 assert_select '#main.nosidebar'
350 assert_select '#main.nosidebar'
351 end
351 end
352
352
353 def test_show_should_not_display_hidden_custom_fields
353 def test_show_should_not_display_hidden_custom_fields
354 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
354 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
355 get :show, :id => 'ecookbook'
355 get :show, :id => 'ecookbook'
356 assert_response :success
356 assert_response :success
357 assert_template 'show'
357 assert_template 'show'
358 assert_not_nil assigns(:project)
358 assert_not_nil assigns(:project)
359
359
360 assert_select 'li', :text => /Development status/, :count => 0
360 assert_select 'li', :text => /Development status/, :count => 0
361 end
361 end
362
362
363 def test_show_should_not_display_blank_custom_fields_with_multiple_values
363 def test_show_should_not_display_blank_custom_fields_with_multiple_values
364 f1 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Foo Bar), :multiple => true
364 f1 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Foo Bar), :multiple => true
365 f2 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Baz Qux), :multiple => true
365 f2 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Baz Qux), :multiple => true
366 project = Project.generate!(:custom_field_values => {f2.id.to_s => %w(Qux)})
366 project = Project.generate!(:custom_field_values => {f2.id.to_s => %w(Qux)})
367
367
368 get :show, :id => project.id
368 get :show, :id => project.id
369 assert_response :success
369 assert_response :success
370
370
371 assert_select 'li', :text => /#{f1.name}/, :count => 0
371 assert_select 'li', :text => /#{f1.name}/, :count => 0
372 assert_select 'li', :text => /#{f2.name}/
372 assert_select 'li', :text => /#{f2.name}/
373 end
373 end
374
374
375 def test_show_should_not_display_blank_text_custom_fields
375 def test_show_should_not_display_blank_text_custom_fields
376 f1 = ProjectCustomField.generate! :field_format => 'text'
376 f1 = ProjectCustomField.generate! :field_format => 'text'
377
377
378 get :show, :id => 1
378 get :show, :id => 1
379 assert_response :success
379 assert_response :success
380
380
381 assert_select 'li', :text => /#{f1.name}/, :count => 0
381 assert_select 'li', :text => /#{f1.name}/, :count => 0
382 end
382 end
383
383
384 def test_show_should_not_fail_when_custom_values_are_nil
384 def test_show_should_not_fail_when_custom_values_are_nil
385 project = Project.find_by_identifier('ecookbook')
385 project = Project.find_by_identifier('ecookbook')
386 project.custom_values.first.update_attribute(:value, nil)
386 project.custom_values.first.update_attribute(:value, nil)
387 get :show, :id => 'ecookbook'
387 get :show, :id => 'ecookbook'
388 assert_response :success
388 assert_response :success
389 assert_template 'show'
389 assert_template 'show'
390 assert_not_nil assigns(:project)
390 assert_not_nil assigns(:project)
391 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
391 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
392 end
392 end
393
393
394 def show_archived_project_should_be_denied
394 def show_archived_project_should_be_denied
395 project = Project.find_by_identifier('ecookbook')
395 project = Project.find_by_identifier('ecookbook')
396 project.archive!
396 project.archive!
397
397
398 get :show, :id => 'ecookbook'
398 get :show, :id => 'ecookbook'
399 assert_response 403
399 assert_response 403
400 assert_nil assigns(:project)
400 assert_nil assigns(:project)
401 assert_select 'p', :text => /archived/
401 assert_select 'p', :text => /archived/
402 end
402 end
403
403
404 def test_show_should_not_show_private_subprojects_that_are_not_visible
404 def test_show_should_not_show_private_subprojects_that_are_not_visible
405 get :show, :id => 'ecookbook'
405 get :show, :id => 'ecookbook'
406 assert_response :success
406 assert_response :success
407 assert_template 'show'
407 assert_template 'show'
408 assert_select 'a', :text => /Private child/, :count => 0
408 assert_select 'a', :text => /Private child/, :count => 0
409 end
409 end
410
410
411 def test_show_should_show_private_subprojects_that_are_visible
411 def test_show_should_show_private_subprojects_that_are_visible
412 @request.session[:user_id] = 2 # manager who is a member of the private subproject
412 @request.session[:user_id] = 2 # manager who is a member of the private subproject
413 get :show, :id => 'ecookbook'
413 get :show, :id => 'ecookbook'
414 assert_response :success
414 assert_response :success
415 assert_template 'show'
415 assert_template 'show'
416 assert_select 'a', :text => /Private child/
416 assert_select 'a', :text => /Private child/
417 end
417 end
418
418
419 def test_settings
419 def test_settings
420 @request.session[:user_id] = 2 # manager
420 @request.session[:user_id] = 2 # manager
421 get :settings, :id => 1
421 get :settings, :id => 1
422 assert_response :success
422 assert_response :success
423 assert_template 'settings'
423 assert_template 'settings'
424 end
424 end
425
425
426 def test_settings_of_subproject
426 def test_settings_of_subproject
427 @request.session[:user_id] = 2
427 @request.session[:user_id] = 2
428 get :settings, :id => 'private-child'
428 get :settings, :id => 'private-child'
429 assert_response :success
429 assert_response :success
430 assert_template 'settings'
430 assert_template 'settings'
431
431
432 assert_select 'input[type=checkbox][name=?]', 'project[inherit_members]'
432 assert_select 'input[type=checkbox][name=?]', 'project[inherit_members]'
433 end
433 end
434
434
435 def test_settings_should_be_denied_for_member_on_closed_project
435 def test_settings_should_be_denied_for_member_on_closed_project
436 Project.find(1).close
436 Project.find(1).close
437 @request.session[:user_id] = 2 # manager
437 @request.session[:user_id] = 2 # manager
438
438
439 get :settings, :id => 1
439 get :settings, :id => 1
440 assert_response 403
440 assert_response 403
441 end
441 end
442
442
443 def test_settings_should_be_denied_for_anonymous_on_closed_project
443 def test_settings_should_be_denied_for_anonymous_on_closed_project
444 Project.find(1).close
444 Project.find(1).close
445
445
446 get :settings, :id => 1
446 get :settings, :id => 1
447 assert_response 302
447 assert_response 302
448 end
448 end
449
449
450 def test_setting_with_wiki_module_and_no_wiki
450 def test_setting_with_wiki_module_and_no_wiki
451 Project.find(1).wiki.destroy
451 Project.find(1).wiki.destroy
452 Role.find(1).add_permission! :manage_wiki
452 Role.find(1).add_permission! :manage_wiki
453 @request.session[:user_id] = 2
453 @request.session[:user_id] = 2
454
454
455 get :settings, :id => 1
455 get :settings, :id => 1
456 assert_response :success
456 assert_response :success
457 assert_template 'settings'
457 assert_template 'settings'
458
458
459 assert_select 'form[action=?]', '/projects/ecookbook/wiki' do
459 assert_select 'form[action=?]', '/projects/ecookbook/wiki' do
460 assert_select 'input[name=?]', 'wiki[start_page]'
460 assert_select 'input[name=?]', 'wiki[start_page]'
461 end
461 end
462 end
462 end
463
463
464 def test_update
464 def test_update
465 @request.session[:user_id] = 2 # manager
465 @request.session[:user_id] = 2 # manager
466 post :update, :id => 1, :project => {:name => 'Test changed name',
466 post :update, :id => 1, :project => {:name => 'Test changed name',
467 :issue_custom_field_ids => ['']}
467 :issue_custom_field_ids => ['']}
468 assert_redirected_to '/projects/ecookbook/settings'
468 assert_redirected_to '/projects/ecookbook/settings'
469 project = Project.find(1)
469 project = Project.find(1)
470 assert_equal 'Test changed name', project.name
470 assert_equal 'Test changed name', project.name
471 end
471 end
472
472
473 def test_update_with_failure
473 def test_update_with_failure
474 @request.session[:user_id] = 2 # manager
474 @request.session[:user_id] = 2 # manager
475 post :update, :id => 1, :project => {:name => ''}
475 post :update, :id => 1, :project => {:name => ''}
476 assert_response :success
476 assert_response :success
477 assert_template 'settings'
477 assert_template 'settings'
478 assert_select_error /name cannot be blank/i
478 assert_select_error /name cannot be blank/i
479 end
479 end
480
480
481 def test_update_should_be_denied_for_member_on_closed_project
481 def test_update_should_be_denied_for_member_on_closed_project
482 Project.find(1).close
482 Project.find(1).close
483 @request.session[:user_id] = 2 # manager
483 @request.session[:user_id] = 2 # manager
484
484
485 post :update, :id => 1, :project => {:name => 'Closed'}
485 post :update, :id => 1, :project => {:name => 'Closed'}
486 assert_response 403
486 assert_response 403
487 assert_equal 'eCookbook', Project.find(1).name
487 assert_equal 'eCookbook', Project.find(1).name
488 end
488 end
489
489
490 def test_update_should_be_denied_for_anonymous_on_closed_project
490 def test_update_should_be_denied_for_anonymous_on_closed_project
491 Project.find(1).close
491 Project.find(1).close
492
492
493 post :update, :id => 1, :project => {:name => 'Closed'}
493 post :update, :id => 1, :project => {:name => 'Closed'}
494 assert_response 302
494 assert_response 302
495 assert_equal 'eCookbook', Project.find(1).name
495 assert_equal 'eCookbook', Project.find(1).name
496 end
496 end
497
497
498 def test_update_child_project_without_parent_permission_should_not_show_validation_error
498 def test_update_child_project_without_parent_permission_should_not_show_validation_error
499 child = Project.generate_with_parent!
499 child = Project.generate_with_parent!
500 user = User.generate!
500 user = User.generate!
501 User.add_to_project(user, child, Role.generate!(:permissions => [:edit_project]))
501 User.add_to_project(user, child, Role.generate!(:permissions => [:edit_project]))
502 @request.session[:user_id] = user.id
502 @request.session[:user_id] = user.id
503
503
504 post :update, :id => child.id, :project => {:name => 'Updated'}
504 post :update, :id => child.id, :project => {:name => 'Updated'}
505 assert_response 302
505 assert_response 302
506 assert_match /Successful update/, flash[:notice]
506 assert_match /Successful update/, flash[:notice]
507 end
507 end
508
508
509 def test_modules
509 def test_modules
510 @request.session[:user_id] = 2
510 @request.session[:user_id] = 2
511 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
511 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
512
512
513 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
513 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
514 assert_redirected_to '/projects/ecookbook/settings/modules'
514 assert_redirected_to '/projects/ecookbook/settings/modules'
515 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
515 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
516 end
516 end
517
517
518 def test_destroy_leaf_project_without_confirmation_should_show_confirmation
518 def test_destroy_leaf_project_without_confirmation_should_show_confirmation
519 @request.session[:user_id] = 1 # admin
519 @request.session[:user_id] = 1 # admin
520
520
521 assert_no_difference 'Project.count' do
521 assert_no_difference 'Project.count' do
522 delete :destroy, :id => 2
522 delete :destroy, :id => 2
523 assert_response :success
523 assert_response :success
524 assert_template 'destroy'
524 assert_template 'destroy'
525 end
525 end
526 end
526 end
527
527
528 def test_destroy_without_confirmation_should_show_confirmation_with_subprojects
528 def test_destroy_without_confirmation_should_show_confirmation_with_subprojects
529 @request.session[:user_id] = 1 # admin
529 @request.session[:user_id] = 1 # admin
530
530
531 assert_no_difference 'Project.count' do
531 assert_no_difference 'Project.count' do
532 delete :destroy, :id => 1
532 delete :destroy, :id => 1
533 assert_response :success
533 assert_response :success
534 assert_template 'destroy'
534 assert_template 'destroy'
535 end
535 end
536 assert_select 'strong',
536 assert_select 'strong',
537 :text => ['Private child of eCookbook',
537 :text => ['Private child of eCookbook',
538 'Child of private child, eCookbook Subproject 1',
538 'Child of private child, eCookbook Subproject 1',
539 'eCookbook Subproject 2'].join(', ')
539 'eCookbook Subproject 2'].join(', ')
540 end
540 end
541
541
542 def test_destroy_with_confirmation_should_destroy_the_project_and_subprojects
542 def test_destroy_with_confirmation_should_destroy_the_project_and_subprojects
543 @request.session[:user_id] = 1 # admin
543 @request.session[:user_id] = 1 # admin
544
544
545 assert_difference 'Project.count', -5 do
545 assert_difference 'Project.count', -5 do
546 delete :destroy, :id => 1, :confirm => 1
546 delete :destroy, :id => 1, :confirm => 1
547 assert_redirected_to '/admin/projects'
547 assert_redirected_to '/admin/projects'
548 end
548 end
549 assert_nil Project.find_by_id(1)
549 assert_nil Project.find_by_id(1)
550 end
550 end
551
551
552 def test_archive
552 def test_archive
553 @request.session[:user_id] = 1 # admin
553 @request.session[:user_id] = 1 # admin
554 post :archive, :id => 1
554 post :archive, :id => 1
555 assert_redirected_to '/admin/projects'
555 assert_redirected_to '/admin/projects'
556 assert !Project.find(1).active?
556 assert !Project.find(1).active?
557 end
557 end
558
558
559 def test_archive_with_failure
559 def test_archive_with_failure
560 @request.session[:user_id] = 1
560 @request.session[:user_id] = 1
561 Project.any_instance.stubs(:archive).returns(false)
561 Project.any_instance.stubs(:archive).returns(false)
562 post :archive, :id => 1
562 post :archive, :id => 1
563 assert_redirected_to '/admin/projects'
563 assert_redirected_to '/admin/projects'
564 assert_match /project cannot be archived/i, flash[:error]
564 assert_match /project cannot be archived/i, flash[:error]
565 end
565 end
566
566
567 def test_unarchive
567 def test_unarchive
568 @request.session[:user_id] = 1 # admin
568 @request.session[:user_id] = 1 # admin
569 Project.find(1).archive
569 Project.find(1).archive
570 post :unarchive, :id => 1
570 post :unarchive, :id => 1
571 assert_redirected_to '/admin/projects'
571 assert_redirected_to '/admin/projects'
572 assert Project.find(1).active?
572 assert Project.find(1).active?
573 end
573 end
574
574
575 def test_close
575 def test_close
576 @request.session[:user_id] = 2
576 @request.session[:user_id] = 2
577 post :close, :id => 1
577 post :close, :id => 1
578 assert_redirected_to '/projects/ecookbook'
578 assert_redirected_to '/projects/ecookbook'
579 assert_equal Project::STATUS_CLOSED, Project.find(1).status
579 assert_equal Project::STATUS_CLOSED, Project.find(1).status
580 end
580 end
581
581
582 def test_reopen
582 def test_reopen
583 Project.find(1).close
583 Project.find(1).close
584 @request.session[:user_id] = 2
584 @request.session[:user_id] = 2
585 post :reopen, :id => 1
585 post :reopen, :id => 1
586 assert_redirected_to '/projects/ecookbook'
586 assert_redirected_to '/projects/ecookbook'
587 assert Project.find(1).active?
587 assert Project.find(1).active?
588 end
588 end
589
589
590 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
590 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
591 CustomField.delete_all
591 CustomField.delete_all
592 parent = nil
592 parent = nil
593 6.times do |i|
593 6.times do |i|
594 p = Project.generate_with_parent!(parent)
594 p = Project.generate_with_parent!(parent)
595 get :show, :id => p
595 get :show, :id => p
596 assert_select '#header h1' do
596 assert_select '#header h1' do
597 assert_select 'a', :count => [i, 3].min
597 assert_select 'a', :count => [i, 3].min
598 end
598 end
599
599
600 parent = p
600 parent = p
601 end
601 end
602 end
602 end
603
603
604 def test_get_copy
604 def test_get_copy
605 @request.session[:user_id] = 1 # admin
605 @request.session[:user_id] = 1 # admin
606 get :copy, :id => 1
606 get :copy, :id => 1
607 assert_response :success
607 assert_response :success
608 assert_template 'copy'
608 assert_template 'copy'
609 assert assigns(:project)
609 assert assigns(:project)
610 assert_equal Project.find(1).description, assigns(:project).description
610 assert_equal Project.find(1).description, assigns(:project).description
611 assert_nil assigns(:project).id
611 assert_nil assigns(:project).id
612
612
613 assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1
613 assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1
614 end
614 end
615
615
616 def test_get_copy_with_invalid_source_should_respond_with_404
616 def test_get_copy_with_invalid_source_should_respond_with_404
617 @request.session[:user_id] = 1
617 @request.session[:user_id] = 1
618 get :copy, :id => 99
618 get :copy, :id => 99
619 assert_response 404
619 assert_response 404
620 end
620 end
621
621
622 def test_get_copy_should_preselect_custom_fields
622 def test_get_copy_should_preselect_custom_fields
623 field1 = IssueCustomField.generate!(:is_for_all => false)
623 field1 = IssueCustomField.generate!(:is_for_all => false)
624 field2 = IssueCustomField.generate!(:is_for_all => false)
624 field2 = IssueCustomField.generate!(:is_for_all => false)
625 source = Project.generate!(:issue_custom_fields => [field1])
625 source = Project.generate!(:issue_custom_fields => [field1])
626 @request.session[:user_id] = 1
626 @request.session[:user_id] = 1
627
627
628 get :copy, :id => source.id
628 get :copy, :id => source.id
629 assert_response :success
629 assert_response :success
630 assert_select 'fieldset#project_issue_custom_fields' do
630 assert_select 'fieldset#project_issue_custom_fields' do
631 assert_select 'input[type=checkbox][value=?][checked=checked]', field1.id.to_s
631 assert_select 'input[type=checkbox][value=?][checked=checked]', field1.id.to_s
632 assert_select 'input[type=checkbox][value=?]:not([checked])', field2.id.to_s
632 assert_select 'input[type=checkbox][value=?]:not([checked])', field2.id.to_s
633 end
633 end
634 end
634 end
635
635
636 def test_post_copy_should_copy_requested_items
636 def test_post_copy_should_copy_requested_items
637 @request.session[:user_id] = 1 # admin
637 @request.session[:user_id] = 1 # admin
638 CustomField.delete_all
638 CustomField.delete_all
639
639
640 assert_difference 'Project.count' do
640 assert_difference 'Project.count' do
641 post :copy, :id => 1,
641 post :copy, :id => 1,
642 :project => {
642 :project => {
643 :name => 'Copy',
643 :name => 'Copy',
644 :identifier => 'unique-copy',
644 :identifier => 'unique-copy',
645 :tracker_ids => ['1', '2', '3', ''],
645 :tracker_ids => ['1', '2', '3', ''],
646 :enabled_module_names => %w(issue_tracking time_tracking)
646 :enabled_module_names => %w(issue_tracking time_tracking)
647 },
647 },
648 :only => %w(issues versions)
648 :only => %w(issues versions)
649 end
649 end
650 project = Project.find('unique-copy')
650 project = Project.find('unique-copy')
651 source = Project.find(1)
651 source = Project.find(1)
652 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
652 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
653
653
654 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
654 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
655 assert_equal source.issues.count, project.issues.count, "All issues were not copied"
655 assert_equal source.issues.count, project.issues.count, "All issues were not copied"
656 assert_equal 0, project.members.count
656 assert_equal 0, project.members.count
657 end
657 end
658
658
659 def test_post_copy_should_redirect_to_settings_when_successful
659 def test_post_copy_should_redirect_to_settings_when_successful
660 @request.session[:user_id] = 1 # admin
660 @request.session[:user_id] = 1 # admin
661 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
661 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
662 assert_response :redirect
662 assert_response :redirect
663 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
663 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
664 end
664 end
665
665
666 def test_post_copy_with_failure
666 def test_post_copy_with_failure
667 @request.session[:user_id] = 1
667 @request.session[:user_id] = 1
668 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => ''}
668 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => ''}
669 assert_response :success
669 assert_response :success
670 assert_template 'copy'
670 assert_template 'copy'
671 end
671 end
672
672
673 def test_jump_should_redirect_to_active_tab
673 def test_jump_should_redirect_to_active_tab
674 get :show, :id => 1, :jump => 'issues'
674 get :show, :id => 1, :jump => 'issues'
675 assert_redirected_to '/projects/ecookbook/issues'
675 assert_redirected_to '/projects/ecookbook/issues'
676 end
676 end
677
677
678 def test_jump_should_not_redirect_to_inactive_tab
678 def test_jump_should_not_redirect_to_inactive_tab
679 get :show, :id => 3, :jump => 'documents'
679 get :show, :id => 3, :jump => 'documents'
680 assert_response :success
680 assert_response :success
681 assert_template 'show'
681 assert_template 'show'
682 end
682 end
683
683
684 def test_jump_should_not_redirect_to_unknown_tab
684 def test_jump_should_not_redirect_to_unknown_tab
685 get :show, :id => 3, :jump => 'foobar'
685 get :show, :id => 3, :jump => 'foobar'
686 assert_response :success
686 assert_response :success
687 assert_template 'show'
687 assert_template 'show'
688 end
688 end
689
689
690 def test_body_should_have_project_css_class
690 def test_body_should_have_project_css_class
691 get :show, :id => 1
691 get :show, :id => 1
692 assert_select 'body.project-ecookbook'
692 assert_select 'body.project-ecookbook'
693 end
693 end
694
695 def test_project_menu_should_include_new_issue_link
696 @request.session[:user_id] = 2
697 get :show, :id => 1
698 assert_select '#main-menu a.new-issue[href="/projects/ecookbook/issues/new"]', :text => 'New issue'
699 end
700
701 def test_project_menu_should_not_include_new_issue_link_for_project_without_trackers
702 Project.find(1).trackers.clear
703
704 @request.session[:user_id] = 2
705 get :show, :id => 1
706 assert_select '#main-menu a.new-issue', 0
707 end
708
709 def test_project_menu_should_not_include_new_issue_link_for_users_with_copy_issues_permission_only
710 role = Role.find(1)
711 role.remove_permission! :add_issues
712 role.add_permission! :copy_issues
713
714 @request.session[:user_id] = 2
715 get :show, :id => 1
716 assert_select '#main-menu a.new-issue', 0
717 end
718 end
694 end
@@ -1,86 +1,80
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 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 module RedmineMenuTestHelper
20 module RedmineMenuTestHelper
21 # Assertions
21 # Assertions
22 def assert_number_of_items_in_menu(menu_name, count)
22 def assert_number_of_items_in_menu(menu_name, count)
23 assert Redmine::MenuManager.items(menu_name).size >= count, "Menu has less than #{count} items"
23 assert Redmine::MenuManager.items(menu_name).size >= count, "Menu has less than #{count} items"
24 end
24 end
25
25
26 def assert_menu_contains_item_named(menu_name, item_name)
26 def assert_menu_contains_item_named(menu_name, item_name)
27 assert Redmine::MenuManager.items(menu_name).collect(&:name).include?(item_name.to_sym), "Menu did not have an item named #{item_name}"
27 assert Redmine::MenuManager.items(menu_name).collect(&:name).include?(item_name.to_sym), "Menu did not have an item named #{item_name}"
28 end
28 end
29
29
30 # Helpers
30 # Helpers
31 def get_menu_item(menu_name, item_name)
31 def get_menu_item(menu_name, item_name)
32 Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
32 Redmine::MenuManager.items(menu_name).find {|item| item.name == item_name.to_sym}
33 end
33 end
34 end
34 end
35
35
36 class RedmineTest < ActiveSupport::TestCase
36 class RedmineTest < ActiveSupport::TestCase
37 include RedmineMenuTestHelper
37 include RedmineMenuTestHelper
38
38
39 def test_top_menu
39 def test_top_menu
40 assert_number_of_items_in_menu :top_menu, 5
40 assert_number_of_items_in_menu :top_menu, 5
41 assert_menu_contains_item_named :top_menu, :home
41 assert_menu_contains_item_named :top_menu, :home
42 assert_menu_contains_item_named :top_menu, :my_page
42 assert_menu_contains_item_named :top_menu, :my_page
43 assert_menu_contains_item_named :top_menu, :projects
43 assert_menu_contains_item_named :top_menu, :projects
44 assert_menu_contains_item_named :top_menu, :administration
44 assert_menu_contains_item_named :top_menu, :administration
45 assert_menu_contains_item_named :top_menu, :help
45 assert_menu_contains_item_named :top_menu, :help
46 end
46 end
47
47
48 def test_account_menu
48 def test_account_menu
49 assert_number_of_items_in_menu :account_menu, 4
49 assert_number_of_items_in_menu :account_menu, 4
50 assert_menu_contains_item_named :account_menu, :login
50 assert_menu_contains_item_named :account_menu, :login
51 assert_menu_contains_item_named :account_menu, :register
51 assert_menu_contains_item_named :account_menu, :register
52 assert_menu_contains_item_named :account_menu, :my_account
52 assert_menu_contains_item_named :account_menu, :my_account
53 assert_menu_contains_item_named :account_menu, :logout
53 assert_menu_contains_item_named :account_menu, :logout
54 end
54 end
55
55
56 def test_application_menu
56 def test_application_menu
57 assert_number_of_items_in_menu :application_menu, 0
57 assert_number_of_items_in_menu :application_menu, 0
58 end
58 end
59
59
60 def test_admin_menu
60 def test_admin_menu
61 assert_number_of_items_in_menu :admin_menu, 0
61 assert_number_of_items_in_menu :admin_menu, 0
62 end
62 end
63
63
64 def test_project_menu
64 def test_project_menu
65 assert_number_of_items_in_menu :project_menu, 14
65 assert_number_of_items_in_menu :project_menu, 13
66 assert_menu_contains_item_named :project_menu, :overview
66 assert_menu_contains_item_named :project_menu, :overview
67 assert_menu_contains_item_named :project_menu, :activity
67 assert_menu_contains_item_named :project_menu, :activity
68 assert_menu_contains_item_named :project_menu, :roadmap
68 assert_menu_contains_item_named :project_menu, :roadmap
69 assert_menu_contains_item_named :project_menu, :issues
69 assert_menu_contains_item_named :project_menu, :issues
70 assert_menu_contains_item_named :project_menu, :new_issue
71 assert_menu_contains_item_named :project_menu, :calendar
70 assert_menu_contains_item_named :project_menu, :calendar
72 assert_menu_contains_item_named :project_menu, :gantt
71 assert_menu_contains_item_named :project_menu, :gantt
73 assert_menu_contains_item_named :project_menu, :news
72 assert_menu_contains_item_named :project_menu, :news
74 assert_menu_contains_item_named :project_menu, :documents
73 assert_menu_contains_item_named :project_menu, :documents
75 assert_menu_contains_item_named :project_menu, :wiki
74 assert_menu_contains_item_named :project_menu, :wiki
76 assert_menu_contains_item_named :project_menu, :boards
75 assert_menu_contains_item_named :project_menu, :boards
77 assert_menu_contains_item_named :project_menu, :files
76 assert_menu_contains_item_named :project_menu, :files
78 assert_menu_contains_item_named :project_menu, :repository
77 assert_menu_contains_item_named :project_menu, :repository
79 assert_menu_contains_item_named :project_menu, :settings
78 assert_menu_contains_item_named :project_menu, :settings
80 end
79 end
81
82 def test_new_issue_should_have_root_as_a_parent
83 new_issue = get_menu_item(:project_menu, :new_issue)
84 assert_equal :root, new_issue.parent.name
85 end
86 end
80 end
General Comments 0
You need to be logged in to leave comments. Login now