##// END OF EJS Templates
Merged r5991 from trunk....
Jean-Philippe Lang -
r6038:2325831d81a3
parent child
Show More
@@ -1,335 +1,335
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class IssuesController < ApplicationController
18 class IssuesController < ApplicationController
19 menu_item :new_issue, :only => [:new, :create]
19 menu_item :new_issue, :only => [:new, :create]
20 default_search_scope :issues
20 default_search_scope :issues
21
21
22 before_filter :find_issue, :only => [:show, :edit, :update]
22 before_filter :find_issue, :only => [:show, :edit, :update]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy]
24 before_filter :check_project_uniqueness, :only => [:move, :perform_move]
24 before_filter :check_project_uniqueness, :only => [:move, :perform_move]
25 before_filter :find_project, :only => [:new, :create]
25 before_filter :find_project, :only => [:new, :create]
26 before_filter :authorize, :except => [:index]
26 before_filter :authorize, :except => [:index]
27 before_filter :find_optional_project, :only => [:index]
27 before_filter :find_optional_project, :only => [:index]
28 before_filter :check_for_default_issue_status, :only => [:new, :create]
28 before_filter :check_for_default_issue_status, :only => [:new, :create]
29 before_filter :build_new_issue_from_params, :only => [:new, :create]
29 before_filter :build_new_issue_from_params, :only => [:new, :create]
30 accept_key_auth :index, :show, :create, :update, :destroy
30 accept_key_auth :index, :show, :create, :update, :destroy
31
31
32 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
32 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
33
33
34 helper :journals
34 helper :journals
35 helper :projects
35 helper :projects
36 include ProjectsHelper
36 include ProjectsHelper
37 helper :custom_fields
37 helper :custom_fields
38 include CustomFieldsHelper
38 include CustomFieldsHelper
39 helper :issue_relations
39 helper :issue_relations
40 include IssueRelationsHelper
40 include IssueRelationsHelper
41 helper :watchers
41 helper :watchers
42 include WatchersHelper
42 include WatchersHelper
43 helper :attachments
43 helper :attachments
44 include AttachmentsHelper
44 include AttachmentsHelper
45 helper :queries
45 helper :queries
46 include QueriesHelper
46 include QueriesHelper
47 helper :repositories
47 helper :repositories
48 include RepositoriesHelper
48 include RepositoriesHelper
49 helper :sort
49 helper :sort
50 include SortHelper
50 include SortHelper
51 include IssuesHelper
51 include IssuesHelper
52 helper :timelog
52 helper :timelog
53 helper :gantt
53 helper :gantt
54 include Redmine::Export::PDF
54 include Redmine::Export::PDF
55
55
56 verify :method => [:post, :delete],
56 verify :method => [:post, :delete],
57 :only => :destroy,
57 :only => :destroy,
58 :render => { :nothing => true, :status => :method_not_allowed }
58 :render => { :nothing => true, :status => :method_not_allowed }
59
59
60 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
60 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
61 verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed }
61 verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed }
62 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
62 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
63
63
64 def index
64 def index
65 retrieve_query
65 retrieve_query
66 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
66 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
67 sort_update(@query.sortable_columns)
67 sort_update(@query.sortable_columns)
68
68
69 if @query.valid?
69 if @query.valid?
70 case params[:format]
70 case params[:format]
71 when 'csv', 'pdf'
71 when 'csv', 'pdf'
72 @limit = Setting.issues_export_limit.to_i
72 @limit = Setting.issues_export_limit.to_i
73 when 'atom'
73 when 'atom'
74 @limit = Setting.feeds_limit.to_i
74 @limit = Setting.feeds_limit.to_i
75 when 'xml', 'json'
75 when 'xml', 'json'
76 @offset, @limit = api_offset_and_limit
76 @offset, @limit = api_offset_and_limit
77 else
77 else
78 @limit = per_page_option
78 @limit = per_page_option
79 end
79 end
80
80
81 @issue_count = @query.issue_count
81 @issue_count = @query.issue_count
82 @issue_pages = Paginator.new self, @issue_count, @limit, params['page']
82 @issue_pages = Paginator.new self, @issue_count, @limit, params['page']
83 @offset ||= @issue_pages.current.offset
83 @offset ||= @issue_pages.current.offset
84 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
84 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
85 :order => sort_clause,
85 :order => sort_clause,
86 :offset => @offset,
86 :offset => @offset,
87 :limit => @limit)
87 :limit => @limit)
88 @issue_count_by_group = @query.issue_count_by_group
88 @issue_count_by_group = @query.issue_count_by_group
89
89
90 respond_to do |format|
90 respond_to do |format|
91 format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
91 format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
92 format.api
92 format.api
93 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
93 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
94 format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }
94 format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }
95 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
95 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
96 end
96 end
97 else
97 else
98 # Send html if the query is not valid
98 # Send html if the query is not valid
99 render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
99 render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
100 end
100 end
101 rescue ActiveRecord::RecordNotFound
101 rescue ActiveRecord::RecordNotFound
102 render_404
102 render_404
103 end
103 end
104
104
105 def show
105 def show
106 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
106 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
107 @journals.each_with_index {|j,i| j.indice = i+1}
107 @journals.each_with_index {|j,i| j.indice = i+1}
108 @journals.reverse! if User.current.wants_comments_in_reverse_order?
108 @journals.reverse! if User.current.wants_comments_in_reverse_order?
109
109
110 if User.current.allowed_to?(:view_changesets, @project)
110 if User.current.allowed_to?(:view_changesets, @project)
111 @changesets = @issue.changesets.visible.all
111 @changesets = @issue.changesets.visible.all
112 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
112 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
113 end
113 end
114
114
115 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
115 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
116 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
116 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
117 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
117 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
118 @priorities = IssuePriority.all
118 @priorities = IssuePriority.all
119 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
119 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
120 respond_to do |format|
120 respond_to do |format|
121 format.html { render :template => 'issues/show.rhtml' }
121 format.html { render :template => 'issues/show.rhtml' }
122 format.api
122 format.api
123 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
123 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
124 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
124 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
125 end
125 end
126 end
126 end
127
127
128 # Add a new issue
128 # Add a new issue
129 # The new issue will be created from an existing one if copy_from parameter is given
129 # The new issue will be created from an existing one if copy_from parameter is given
130 def new
130 def new
131 respond_to do |format|
131 respond_to do |format|
132 format.html { render :action => 'new', :layout => !request.xhr? }
132 format.html { render :action => 'new', :layout => !request.xhr? }
133 format.js { render :partial => 'attributes' }
133 format.js { render :partial => 'attributes' }
134 end
134 end
135 end
135 end
136
136
137 def create
137 def create
138 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
138 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
139 if @issue.save
139 if @issue.save
140 attachments = Attachment.attach_files(@issue, params[:attachments])
140 attachments = Attachment.attach_files(@issue, params[:attachments])
141 render_attachment_warning_if_needed(@issue)
141 render_attachment_warning_if_needed(@issue)
142 flash[:notice] = l(:notice_successful_create)
142 flash[:notice] = l(:notice_successful_create)
143 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
143 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
144 respond_to do |format|
144 respond_to do |format|
145 format.html {
145 format.html {
146 redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
146 redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
147 { :action => 'show', :id => @issue })
147 { :action => 'show', :id => @issue })
148 }
148 }
149 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
149 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
150 end
150 end
151 return
151 return
152 else
152 else
153 respond_to do |format|
153 respond_to do |format|
154 format.html { render :action => 'new' }
154 format.html { render :action => 'new' }
155 format.api { render_validation_errors(@issue) }
155 format.api { render_validation_errors(@issue) }
156 end
156 end
157 end
157 end
158 end
158 end
159
159
160 def edit
160 def edit
161 update_issue_from_params
161 update_issue_from_params
162
162
163 @journal = @issue.current_journal
163 @journal = @issue.current_journal
164
164
165 respond_to do |format|
165 respond_to do |format|
166 format.html { }
166 format.html { }
167 format.xml { }
167 format.xml { }
168 end
168 end
169 end
169 end
170
170
171 def update
171 def update
172 update_issue_from_params
172 update_issue_from_params
173
173
174 if @issue.save_issue_with_child_records(params, @time_entry)
174 if @issue.save_issue_with_child_records(params, @time_entry)
175 render_attachment_warning_if_needed(@issue)
175 render_attachment_warning_if_needed(@issue)
176 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
176 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
177
177
178 respond_to do |format|
178 respond_to do |format|
179 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
179 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
180 format.api { head :ok }
180 format.api { head :ok }
181 end
181 end
182 else
182 else
183 render_attachment_warning_if_needed(@issue)
183 render_attachment_warning_if_needed(@issue)
184 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
184 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
185 @journal = @issue.current_journal
185 @journal = @issue.current_journal
186
186
187 respond_to do |format|
187 respond_to do |format|
188 format.html { render :action => 'edit' }
188 format.html { render :action => 'edit' }
189 format.api { render_validation_errors(@issue) }
189 format.api { render_validation_errors(@issue) }
190 end
190 end
191 end
191 end
192 end
192 end
193
193
194 # Bulk edit a set of issues
194 # Bulk edit a set of issues
195 def bulk_edit
195 def bulk_edit
196 @issues.sort!
196 @issues.sort!
197 @available_statuses = @projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w}
197 @available_statuses = @projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w}
198 @custom_fields = @projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c}
198 @custom_fields = @projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c}
199 @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
199 @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
200 @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
200 @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
201 end
201 end
202
202
203 def bulk_update
203 def bulk_update
204 @issues.sort!
204 @issues.sort!
205 attributes = parse_params_for_bulk_issue_attributes(params)
205 attributes = parse_params_for_bulk_issue_attributes(params)
206
206
207 unsaved_issue_ids = []
207 unsaved_issue_ids = []
208 @issues.each do |issue|
208 @issues.each do |issue|
209 issue.reload
209 issue.reload
210 journal = issue.init_journal(User.current, params[:notes])
210 journal = issue.init_journal(User.current, params[:notes])
211 issue.safe_attributes = attributes
211 issue.safe_attributes = attributes
212 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
212 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
213 unless issue.save
213 unless issue.save
214 # Keep unsaved issue ids to display them in flash error
214 # Keep unsaved issue ids to display them in flash error
215 unsaved_issue_ids << issue.id
215 unsaved_issue_ids << issue.id
216 end
216 end
217 end
217 end
218 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
218 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
219 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
219 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
220 end
220 end
221
221
222 def destroy
222 def destroy
223 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
223 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
224 if @hours > 0
224 if @hours > 0
225 case params[:todo]
225 case params[:todo]
226 when 'destroy'
226 when 'destroy'
227 # nothing to do
227 # nothing to do
228 when 'nullify'
228 when 'nullify'
229 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
229 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
230 when 'reassign'
230 when 'reassign'
231 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
231 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
232 if reassign_to.nil?
232 if reassign_to.nil?
233 flash.now[:error] = l(:error_issue_not_found_in_project)
233 flash.now[:error] = l(:error_issue_not_found_in_project)
234 return
234 return
235 else
235 else
236 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
236 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
237 end
237 end
238 else
238 else
239 # display the destroy form if it's a user request
239 # display the destroy form if it's a user request
240 return unless api_request?
240 return unless api_request?
241 end
241 end
242 end
242 end
243 @issues.each do |issue|
243 @issues.each do |issue|
244 begin
244 begin
245 issue.reload.destroy
245 issue.reload.destroy
246 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
246 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
247 # nothing to do, issue was already deleted (eg. by a parent)
247 # nothing to do, issue was already deleted (eg. by a parent)
248 end
248 end
249 end
249 end
250 respond_to do |format|
250 respond_to do |format|
251 format.html { redirect_back_or_default(:action => 'index', :project_id => @project) }
251 format.html { redirect_back_or_default(:action => 'index', :project_id => @project) }
252 format.api { head :ok }
252 format.api { head :ok }
253 end
253 end
254 end
254 end
255
255
256 private
256 private
257 def find_issue
257 def find_issue
258 # Issue.visible.find(...) can not be used to redirect user to the login form
258 # Issue.visible.find(...) can not be used to redirect user to the login form
259 # if the issue actually exists but requires authentication
259 # if the issue actually exists but requires authentication
260 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
260 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
261 unless @issue.visible?
261 unless @issue.visible?
262 deny_access
262 deny_access
263 return
263 return
264 end
264 end
265 @project = @issue.project
265 @project = @issue.project
266 rescue ActiveRecord::RecordNotFound
266 rescue ActiveRecord::RecordNotFound
267 render_404
267 render_404
268 end
268 end
269
269
270 def find_project
270 def find_project
271 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
271 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
272 @project = Project.find(project_id)
272 @project = Project.find(project_id)
273 rescue ActiveRecord::RecordNotFound
273 rescue ActiveRecord::RecordNotFound
274 render_404
274 render_404
275 end
275 end
276
276
277 # Used by #edit and #update to set some common instance variables
277 # Used by #edit and #update to set some common instance variables
278 # from the params
278 # from the params
279 # TODO: Refactor, not everything in here is needed by #edit
279 # TODO: Refactor, not everything in here is needed by #edit
280 def update_issue_from_params
280 def update_issue_from_params
281 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
281 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
282 @priorities = IssuePriority.all
282 @priorities = IssuePriority.all
283 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
283 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
284 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
284 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
285 @time_entry.attributes = params[:time_entry]
285 @time_entry.attributes = params[:time_entry]
286
286
287 @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
287 @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
288 @issue.init_journal(User.current, @notes)
288 @issue.init_journal(User.current, @notes)
289 @issue.safe_attributes = params[:issue]
289 @issue.safe_attributes = params[:issue]
290 end
290 end
291
291
292 # TODO: Refactor, lots of extra code in here
292 # TODO: Refactor, lots of extra code in here
293 # TODO: Changing tracker on an existing issue should not trigger this
293 # TODO: Changing tracker on an existing issue should not trigger this
294 def build_new_issue_from_params
294 def build_new_issue_from_params
295 if params[:id].blank?
295 if params[:id].blank?
296 @issue = Issue.new
296 @issue = Issue.new
297 @issue.copy_from(params[:copy_from]) if params[:copy_from]
297 @issue.copy_from(params[:copy_from]) if params[:copy_from]
298 @issue.project = @project
298 @issue.project = @project
299 else
299 else
300 @issue = @project.issues.visible.find(params[:id])
300 @issue = @project.issues.visible.find(params[:id])
301 end
301 end
302
302
303 @issue.project = @project
303 @issue.project = @project
304 @issue.author = User.current
304 # Tracker must be set before custom field values
305 # Tracker must be set before custom field values
305 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
306 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
306 if @issue.tracker.nil?
307 if @issue.tracker.nil?
307 render_error l(:error_no_tracker_in_project)
308 render_error l(:error_no_tracker_in_project)
308 return false
309 return false
309 end
310 end
310 @issue.start_date ||= Date.today
311 @issue.start_date ||= Date.today
311 if params[:issue].is_a?(Hash)
312 if params[:issue].is_a?(Hash)
312 @issue.safe_attributes = params[:issue]
313 @issue.safe_attributes = params[:issue]
313 if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record?
314 if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record?
314 @issue.watcher_user_ids = params[:issue]['watcher_user_ids']
315 @issue.watcher_user_ids = params[:issue]['watcher_user_ids']
315 end
316 end
316 end
317 end
317 @issue.author = User.current
318 @priorities = IssuePriority.all
318 @priorities = IssuePriority.all
319 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
319 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
320 end
320 end
321
321
322 def check_for_default_issue_status
322 def check_for_default_issue_status
323 if IssueStatus.default.nil?
323 if IssueStatus.default.nil?
324 render_error l(:error_no_default_issue_status)
324 render_error l(:error_no_default_issue_status)
325 return false
325 return false
326 end
326 end
327 end
327 end
328
328
329 def parse_params_for_bulk_issue_attributes(params)
329 def parse_params_for_bulk_issue_attributes(params)
330 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
330 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
331 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
331 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
332 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
332 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
333 attributes
333 attributes
334 end
334 end
335 end
335 end
@@ -1,193 +1,194
1 ---
1 ---
2 roles_001:
2 roles_001:
3 name: Manager
3 name: Manager
4 id: 1
4 id: 1
5 builtin: 0
5 builtin: 0
6 issues_visibility: all
6 issues_visibility: all
7 permissions: |
7 permissions: |
8 ---
8 ---
9 - :add_project
9 - :add_project
10 - :edit_project
10 - :edit_project
11 - :select_project_modules
11 - :select_project_modules
12 - :manage_members
12 - :manage_members
13 - :manage_versions
13 - :manage_versions
14 - :manage_categories
14 - :manage_categories
15 - :view_issues
15 - :view_issues
16 - :add_issues
16 - :add_issues
17 - :edit_issues
17 - :edit_issues
18 - :manage_issue_relations
18 - :manage_issue_relations
19 - :manage_subtasks
19 - :manage_subtasks
20 - :add_issue_notes
20 - :add_issue_notes
21 - :move_issues
21 - :move_issues
22 - :delete_issues
22 - :delete_issues
23 - :view_issue_watchers
23 - :view_issue_watchers
24 - :add_issue_watchers
24 - :add_issue_watchers
25 - :set_issues_private
25 - :delete_issue_watchers
26 - :delete_issue_watchers
26 - :manage_public_queries
27 - :manage_public_queries
27 - :save_queries
28 - :save_queries
28 - :view_gantt
29 - :view_gantt
29 - :view_calendar
30 - :view_calendar
30 - :log_time
31 - :log_time
31 - :view_time_entries
32 - :view_time_entries
32 - :edit_time_entries
33 - :edit_time_entries
33 - :delete_time_entries
34 - :delete_time_entries
34 - :manage_news
35 - :manage_news
35 - :comment_news
36 - :comment_news
36 - :view_documents
37 - :view_documents
37 - :manage_documents
38 - :manage_documents
38 - :view_wiki_pages
39 - :view_wiki_pages
39 - :export_wiki_pages
40 - :export_wiki_pages
40 - :view_wiki_edits
41 - :view_wiki_edits
41 - :edit_wiki_pages
42 - :edit_wiki_pages
42 - :delete_wiki_pages_attachments
43 - :delete_wiki_pages_attachments
43 - :protect_wiki_pages
44 - :protect_wiki_pages
44 - :delete_wiki_pages
45 - :delete_wiki_pages
45 - :rename_wiki_pages
46 - :rename_wiki_pages
46 - :add_messages
47 - :add_messages
47 - :edit_messages
48 - :edit_messages
48 - :delete_messages
49 - :delete_messages
49 - :manage_boards
50 - :manage_boards
50 - :view_files
51 - :view_files
51 - :manage_files
52 - :manage_files
52 - :browse_repository
53 - :browse_repository
53 - :manage_repository
54 - :manage_repository
54 - :view_changesets
55 - :view_changesets
55 - :manage_project_activities
56 - :manage_project_activities
56
57
57 position: 1
58 position: 1
58 roles_002:
59 roles_002:
59 name: Developer
60 name: Developer
60 id: 2
61 id: 2
61 builtin: 0
62 builtin: 0
62 issues_visibility: default
63 issues_visibility: default
63 permissions: |
64 permissions: |
64 ---
65 ---
65 - :edit_project
66 - :edit_project
66 - :manage_members
67 - :manage_members
67 - :manage_versions
68 - :manage_versions
68 - :manage_categories
69 - :manage_categories
69 - :view_issues
70 - :view_issues
70 - :add_issues
71 - :add_issues
71 - :edit_issues
72 - :edit_issues
72 - :manage_issue_relations
73 - :manage_issue_relations
73 - :manage_subtasks
74 - :manage_subtasks
74 - :add_issue_notes
75 - :add_issue_notes
75 - :move_issues
76 - :move_issues
76 - :delete_issues
77 - :delete_issues
77 - :view_issue_watchers
78 - :view_issue_watchers
78 - :save_queries
79 - :save_queries
79 - :view_gantt
80 - :view_gantt
80 - :view_calendar
81 - :view_calendar
81 - :log_time
82 - :log_time
82 - :view_time_entries
83 - :view_time_entries
83 - :edit_own_time_entries
84 - :edit_own_time_entries
84 - :manage_news
85 - :manage_news
85 - :comment_news
86 - :comment_news
86 - :view_documents
87 - :view_documents
87 - :manage_documents
88 - :manage_documents
88 - :view_wiki_pages
89 - :view_wiki_pages
89 - :view_wiki_edits
90 - :view_wiki_edits
90 - :edit_wiki_pages
91 - :edit_wiki_pages
91 - :protect_wiki_pages
92 - :protect_wiki_pages
92 - :delete_wiki_pages
93 - :delete_wiki_pages
93 - :add_messages
94 - :add_messages
94 - :edit_own_messages
95 - :edit_own_messages
95 - :delete_own_messages
96 - :delete_own_messages
96 - :manage_boards
97 - :manage_boards
97 - :view_files
98 - :view_files
98 - :manage_files
99 - :manage_files
99 - :browse_repository
100 - :browse_repository
100 - :view_changesets
101 - :view_changesets
101
102
102 position: 2
103 position: 2
103 roles_003:
104 roles_003:
104 name: Reporter
105 name: Reporter
105 id: 3
106 id: 3
106 builtin: 0
107 builtin: 0
107 issues_visibility: default
108 issues_visibility: default
108 permissions: |
109 permissions: |
109 ---
110 ---
110 - :edit_project
111 - :edit_project
111 - :manage_members
112 - :manage_members
112 - :manage_versions
113 - :manage_versions
113 - :manage_categories
114 - :manage_categories
114 - :view_issues
115 - :view_issues
115 - :add_issues
116 - :add_issues
116 - :edit_issues
117 - :edit_issues
117 - :manage_issue_relations
118 - :manage_issue_relations
118 - :add_issue_notes
119 - :add_issue_notes
119 - :move_issues
120 - :move_issues
120 - :view_issue_watchers
121 - :view_issue_watchers
121 - :save_queries
122 - :save_queries
122 - :view_gantt
123 - :view_gantt
123 - :view_calendar
124 - :view_calendar
124 - :log_time
125 - :log_time
125 - :view_time_entries
126 - :view_time_entries
126 - :manage_news
127 - :manage_news
127 - :comment_news
128 - :comment_news
128 - :view_documents
129 - :view_documents
129 - :manage_documents
130 - :manage_documents
130 - :view_wiki_pages
131 - :view_wiki_pages
131 - :view_wiki_edits
132 - :view_wiki_edits
132 - :edit_wiki_pages
133 - :edit_wiki_pages
133 - :delete_wiki_pages
134 - :delete_wiki_pages
134 - :add_messages
135 - :add_messages
135 - :manage_boards
136 - :manage_boards
136 - :view_files
137 - :view_files
137 - :manage_files
138 - :manage_files
138 - :browse_repository
139 - :browse_repository
139 - :view_changesets
140 - :view_changesets
140
141
141 position: 3
142 position: 3
142 roles_004:
143 roles_004:
143 name: Non member
144 name: Non member
144 id: 4
145 id: 4
145 builtin: 1
146 builtin: 1
146 issues_visibility: default
147 issues_visibility: default
147 permissions: |
148 permissions: |
148 ---
149 ---
149 - :view_issues
150 - :view_issues
150 - :add_issues
151 - :add_issues
151 - :edit_issues
152 - :edit_issues
152 - :manage_issue_relations
153 - :manage_issue_relations
153 - :add_issue_notes
154 - :add_issue_notes
154 - :move_issues
155 - :move_issues
155 - :save_queries
156 - :save_queries
156 - :view_gantt
157 - :view_gantt
157 - :view_calendar
158 - :view_calendar
158 - :log_time
159 - :log_time
159 - :view_time_entries
160 - :view_time_entries
160 - :comment_news
161 - :comment_news
161 - :view_documents
162 - :view_documents
162 - :manage_documents
163 - :manage_documents
163 - :view_wiki_pages
164 - :view_wiki_pages
164 - :view_wiki_edits
165 - :view_wiki_edits
165 - :edit_wiki_pages
166 - :edit_wiki_pages
166 - :add_messages
167 - :add_messages
167 - :view_files
168 - :view_files
168 - :manage_files
169 - :manage_files
169 - :browse_repository
170 - :browse_repository
170 - :view_changesets
171 - :view_changesets
171
172
172 position: 4
173 position: 4
173 roles_005:
174 roles_005:
174 name: Anonymous
175 name: Anonymous
175 id: 5
176 id: 5
176 builtin: 2
177 builtin: 2
177 issues_visibility: default
178 issues_visibility: default
178 permissions: |
179 permissions: |
179 ---
180 ---
180 - :view_issues
181 - :view_issues
181 - :add_issue_notes
182 - :add_issue_notes
182 - :view_gantt
183 - :view_gantt
183 - :view_calendar
184 - :view_calendar
184 - :view_time_entries
185 - :view_time_entries
185 - :view_documents
186 - :view_documents
186 - :view_wiki_pages
187 - :view_wiki_pages
187 - :view_wiki_edits
188 - :view_wiki_edits
188 - :view_files
189 - :view_files
189 - :browse_repository
190 - :browse_repository
190 - :view_changesets
191 - :view_changesets
191
192
192 position: 5
193 position: 5
193
194
@@ -1,1435 +1,1465
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'issues_controller'
19 require 'issues_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class IssuesController; def rescue_action(e) raise e end; end
22 class IssuesController; def rescue_action(e) raise e end; end
23
23
24 class IssuesControllerTest < ActionController::TestCase
24 class IssuesControllerTest < ActionController::TestCase
25 fixtures :projects,
25 fixtures :projects,
26 :users,
26 :users,
27 :roles,
27 :roles,
28 :members,
28 :members,
29 :member_roles,
29 :member_roles,
30 :issues,
30 :issues,
31 :issue_statuses,
31 :issue_statuses,
32 :versions,
32 :versions,
33 :trackers,
33 :trackers,
34 :projects_trackers,
34 :projects_trackers,
35 :issue_categories,
35 :issue_categories,
36 :enabled_modules,
36 :enabled_modules,
37 :enumerations,
37 :enumerations,
38 :attachments,
38 :attachments,
39 :workflows,
39 :workflows,
40 :custom_fields,
40 :custom_fields,
41 :custom_values,
41 :custom_values,
42 :custom_fields_projects,
42 :custom_fields_projects,
43 :custom_fields_trackers,
43 :custom_fields_trackers,
44 :time_entries,
44 :time_entries,
45 :journals,
45 :journals,
46 :journal_details,
46 :journal_details,
47 :queries
47 :queries
48
48
49 def setup
49 def setup
50 @controller = IssuesController.new
50 @controller = IssuesController.new
51 @request = ActionController::TestRequest.new
51 @request = ActionController::TestRequest.new
52 @response = ActionController::TestResponse.new
52 @response = ActionController::TestResponse.new
53 User.current = nil
53 User.current = nil
54 end
54 end
55
55
56 def test_index
56 def test_index
57 Setting.default_language = 'en'
57 Setting.default_language = 'en'
58
58
59 get :index
59 get :index
60 assert_response :success
60 assert_response :success
61 assert_template 'index.rhtml'
61 assert_template 'index.rhtml'
62 assert_not_nil assigns(:issues)
62 assert_not_nil assigns(:issues)
63 assert_nil assigns(:project)
63 assert_nil assigns(:project)
64 assert_tag :tag => 'a', :content => /Can't print recipes/
64 assert_tag :tag => 'a', :content => /Can't print recipes/
65 assert_tag :tag => 'a', :content => /Subproject issue/
65 assert_tag :tag => 'a', :content => /Subproject issue/
66 # private projects hidden
66 # private projects hidden
67 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
67 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
68 assert_no_tag :tag => 'a', :content => /Issue on project 2/
68 assert_no_tag :tag => 'a', :content => /Issue on project 2/
69 # project column
69 # project column
70 assert_tag :tag => 'th', :content => /Project/
70 assert_tag :tag => 'th', :content => /Project/
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.rhtml'
77 assert_template 'index.rhtml'
78 assert_not_nil assigns(:issues)
78 assert_not_nil assigns(:issues)
79 assert_nil assigns(:project)
79 assert_nil assigns(:project)
80 assert_no_tag :tag => 'a', :content => /Can't print recipes/
80 assert_no_tag :tag => 'a', :content => /Can't print recipes/
81 assert_tag :tag => 'a', :content => /Subproject issue/
81 assert_tag :tag => 'a', :content => /Subproject issue/
82 end
82 end
83
83
84 def test_index_should_not_list_issues_when_module_disabled
84 def test_index_should_not_list_issues_when_module_disabled
85 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
85 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
86 get :index
86 get :index
87 assert_response :success
87 assert_response :success
88 assert_template 'index.rhtml'
88 assert_template 'index.rhtml'
89 assert_not_nil assigns(:issues)
89 assert_not_nil assigns(:issues)
90 assert_nil assigns(:project)
90 assert_nil assigns(:project)
91 assert_no_tag :tag => 'a', :content => /Can't print recipes/
91 assert_no_tag :tag => 'a', :content => /Can't print recipes/
92 assert_tag :tag => 'a', :content => /Subproject issue/
92 assert_tag :tag => 'a', :content => /Subproject issue/
93 end
93 end
94
94
95 def test_index_should_list_visible_issues_only
95 def test_index_should_list_visible_issues_only
96 get :index, :per_page => 100
96 get :index, :per_page => 100
97 assert_response :success
97 assert_response :success
98 assert_not_nil assigns(:issues)
98 assert_not_nil assigns(:issues)
99 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
99 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
100 end
100 end
101
101
102 def test_index_with_project
102 def test_index_with_project
103 Setting.display_subprojects_issues = 0
103 Setting.display_subprojects_issues = 0
104 get :index, :project_id => 1
104 get :index, :project_id => 1
105 assert_response :success
105 assert_response :success
106 assert_template 'index.rhtml'
106 assert_template 'index.rhtml'
107 assert_not_nil assigns(:issues)
107 assert_not_nil assigns(:issues)
108 assert_tag :tag => 'a', :content => /Can't print recipes/
108 assert_tag :tag => 'a', :content => /Can't print recipes/
109 assert_no_tag :tag => 'a', :content => /Subproject issue/
109 assert_no_tag :tag => 'a', :content => /Subproject issue/
110 end
110 end
111
111
112 def test_index_with_project_and_subprojects
112 def test_index_with_project_and_subprojects
113 Setting.display_subprojects_issues = 1
113 Setting.display_subprojects_issues = 1
114 get :index, :project_id => 1
114 get :index, :project_id => 1
115 assert_response :success
115 assert_response :success
116 assert_template 'index.rhtml'
116 assert_template 'index.rhtml'
117 assert_not_nil assigns(:issues)
117 assert_not_nil assigns(:issues)
118 assert_tag :tag => 'a', :content => /Can't print recipes/
118 assert_tag :tag => 'a', :content => /Can't print recipes/
119 assert_tag :tag => 'a', :content => /Subproject issue/
119 assert_tag :tag => 'a', :content => /Subproject issue/
120 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
120 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
121 end
121 end
122
122
123 def test_index_with_project_and_subprojects_should_show_private_subprojects
123 def test_index_with_project_and_subprojects_should_show_private_subprojects
124 @request.session[:user_id] = 2
124 @request.session[:user_id] = 2
125 Setting.display_subprojects_issues = 1
125 Setting.display_subprojects_issues = 1
126 get :index, :project_id => 1
126 get :index, :project_id => 1
127 assert_response :success
127 assert_response :success
128 assert_template 'index.rhtml'
128 assert_template 'index.rhtml'
129 assert_not_nil assigns(:issues)
129 assert_not_nil assigns(:issues)
130 assert_tag :tag => 'a', :content => /Can't print recipes/
130 assert_tag :tag => 'a', :content => /Can't print recipes/
131 assert_tag :tag => 'a', :content => /Subproject issue/
131 assert_tag :tag => 'a', :content => /Subproject issue/
132 assert_tag :tag => 'a', :content => /Issue of a private subproject/
132 assert_tag :tag => 'a', :content => /Issue of a private subproject/
133 end
133 end
134
134
135 def test_index_with_project_and_default_filter
135 def test_index_with_project_and_default_filter
136 get :index, :project_id => 1, :set_filter => 1
136 get :index, :project_id => 1, :set_filter => 1
137 assert_response :success
137 assert_response :success
138 assert_template 'index.rhtml'
138 assert_template 'index.rhtml'
139 assert_not_nil assigns(:issues)
139 assert_not_nil assigns(:issues)
140
140
141 query = assigns(:query)
141 query = assigns(:query)
142 assert_not_nil query
142 assert_not_nil query
143 # default filter
143 # default filter
144 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
144 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
145 end
145 end
146
146
147 def test_index_with_project_and_filter
147 def test_index_with_project_and_filter
148 get :index, :project_id => 1, :set_filter => 1,
148 get :index, :project_id => 1, :set_filter => 1,
149 :f => ['tracker_id'],
149 :f => ['tracker_id'],
150 :op => {'tracker_id' => '='},
150 :op => {'tracker_id' => '='},
151 :v => {'tracker_id' => ['1']}
151 :v => {'tracker_id' => ['1']}
152 assert_response :success
152 assert_response :success
153 assert_template 'index.rhtml'
153 assert_template 'index.rhtml'
154 assert_not_nil assigns(:issues)
154 assert_not_nil assigns(:issues)
155
155
156 query = assigns(:query)
156 query = assigns(:query)
157 assert_not_nil query
157 assert_not_nil query
158 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
158 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
159 end
159 end
160
160
161 def test_index_with_project_and_empty_filters
161 def test_index_with_project_and_empty_filters
162 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
162 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
163 assert_response :success
163 assert_response :success
164 assert_template 'index.rhtml'
164 assert_template 'index.rhtml'
165 assert_not_nil assigns(:issues)
165 assert_not_nil assigns(:issues)
166
166
167 query = assigns(:query)
167 query = assigns(:query)
168 assert_not_nil query
168 assert_not_nil query
169 # no filter
169 # no filter
170 assert_equal({}, query.filters)
170 assert_equal({}, query.filters)
171 end
171 end
172
172
173 def test_index_with_query
173 def test_index_with_query
174 get :index, :project_id => 1, :query_id => 5
174 get :index, :project_id => 1, :query_id => 5
175 assert_response :success
175 assert_response :success
176 assert_template 'index.rhtml'
176 assert_template 'index.rhtml'
177 assert_not_nil assigns(:issues)
177 assert_not_nil assigns(:issues)
178 assert_nil assigns(:issue_count_by_group)
178 assert_nil assigns(:issue_count_by_group)
179 end
179 end
180
180
181 def test_index_with_query_grouped_by_tracker
181 def test_index_with_query_grouped_by_tracker
182 get :index, :project_id => 1, :query_id => 6
182 get :index, :project_id => 1, :query_id => 6
183 assert_response :success
183 assert_response :success
184 assert_template 'index.rhtml'
184 assert_template 'index.rhtml'
185 assert_not_nil assigns(:issues)
185 assert_not_nil assigns(:issues)
186 assert_not_nil assigns(:issue_count_by_group)
186 assert_not_nil assigns(:issue_count_by_group)
187 end
187 end
188
188
189 def test_index_with_query_grouped_by_list_custom_field
189 def test_index_with_query_grouped_by_list_custom_field
190 get :index, :project_id => 1, :query_id => 9
190 get :index, :project_id => 1, :query_id => 9
191 assert_response :success
191 assert_response :success
192 assert_template 'index.rhtml'
192 assert_template 'index.rhtml'
193 assert_not_nil assigns(:issues)
193 assert_not_nil assigns(:issues)
194 assert_not_nil assigns(:issue_count_by_group)
194 assert_not_nil assigns(:issue_count_by_group)
195 end
195 end
196
196
197 def test_index_sort_by_field_not_included_in_columns
197 def test_index_sort_by_field_not_included_in_columns
198 Setting.issue_list_default_columns = %w(subject author)
198 Setting.issue_list_default_columns = %w(subject author)
199 get :index, :sort => 'tracker'
199 get :index, :sort => 'tracker'
200 end
200 end
201
201
202 def test_index_csv_with_project
202 def test_index_csv_with_project
203 Setting.default_language = 'en'
203 Setting.default_language = 'en'
204
204
205 get :index, :format => 'csv'
205 get :index, :format => 'csv'
206 assert_response :success
206 assert_response :success
207 assert_not_nil assigns(:issues)
207 assert_not_nil assigns(:issues)
208 assert_equal 'text/csv', @response.content_type
208 assert_equal 'text/csv', @response.content_type
209 assert @response.body.starts_with?("#,")
209 assert @response.body.starts_with?("#,")
210
210
211 get :index, :project_id => 1, :format => 'csv'
211 get :index, :project_id => 1, :format => 'csv'
212 assert_response :success
212 assert_response :success
213 assert_not_nil assigns(:issues)
213 assert_not_nil assigns(:issues)
214 assert_equal 'text/csv', @response.content_type
214 assert_equal 'text/csv', @response.content_type
215 end
215 end
216
216
217 def test_index_pdf
217 def test_index_pdf
218 get :index, :format => 'pdf'
218 get :index, :format => 'pdf'
219 assert_response :success
219 assert_response :success
220 assert_not_nil assigns(:issues)
220 assert_not_nil assigns(:issues)
221 assert_equal 'application/pdf', @response.content_type
221 assert_equal 'application/pdf', @response.content_type
222
222
223 get :index, :project_id => 1, :format => 'pdf'
223 get :index, :project_id => 1, :format => 'pdf'
224 assert_response :success
224 assert_response :success
225 assert_not_nil assigns(:issues)
225 assert_not_nil assigns(:issues)
226 assert_equal 'application/pdf', @response.content_type
226 assert_equal 'application/pdf', @response.content_type
227
227
228 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
228 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
229 assert_response :success
229 assert_response :success
230 assert_not_nil assigns(:issues)
230 assert_not_nil assigns(:issues)
231 assert_equal 'application/pdf', @response.content_type
231 assert_equal 'application/pdf', @response.content_type
232 end
232 end
233
233
234 def test_index_pdf_with_query_grouped_by_list_custom_field
234 def test_index_pdf_with_query_grouped_by_list_custom_field
235 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
235 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
236 assert_response :success
236 assert_response :success
237 assert_not_nil assigns(:issues)
237 assert_not_nil assigns(:issues)
238 assert_not_nil assigns(:issue_count_by_group)
238 assert_not_nil assigns(:issue_count_by_group)
239 assert_equal 'application/pdf', @response.content_type
239 assert_equal 'application/pdf', @response.content_type
240 end
240 end
241
241
242 def test_index_sort
242 def test_index_sort
243 get :index, :sort => 'tracker,id:desc'
243 get :index, :sort => 'tracker,id:desc'
244 assert_response :success
244 assert_response :success
245
245
246 sort_params = @request.session['issues_index_sort']
246 sort_params = @request.session['issues_index_sort']
247 assert sort_params.is_a?(String)
247 assert sort_params.is_a?(String)
248 assert_equal 'tracker,id:desc', sort_params
248 assert_equal 'tracker,id:desc', sort_params
249
249
250 issues = assigns(:issues)
250 issues = assigns(:issues)
251 assert_not_nil issues
251 assert_not_nil issues
252 assert !issues.empty?
252 assert !issues.empty?
253 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
253 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
254 end
254 end
255
255
256 def test_index_with_columns
256 def test_index_with_columns
257 columns = ['tracker', 'subject', 'assigned_to']
257 columns = ['tracker', 'subject', 'assigned_to']
258 get :index, :set_filter => 1, :c => columns
258 get :index, :set_filter => 1, :c => columns
259 assert_response :success
259 assert_response :success
260
260
261 # query should use specified columns
261 # query should use specified columns
262 query = assigns(:query)
262 query = assigns(:query)
263 assert_kind_of Query, query
263 assert_kind_of Query, query
264 assert_equal columns, query.column_names.map(&:to_s)
264 assert_equal columns, query.column_names.map(&:to_s)
265
265
266 # columns should be stored in session
266 # columns should be stored in session
267 assert_kind_of Hash, session[:query]
267 assert_kind_of Hash, session[:query]
268 assert_kind_of Array, session[:query][:column_names]
268 assert_kind_of Array, session[:query][:column_names]
269 assert_equal columns, session[:query][:column_names].map(&:to_s)
269 assert_equal columns, session[:query][:column_names].map(&:to_s)
270
270
271 # ensure only these columns are kept in the selected columns list
271 # ensure only these columns are kept in the selected columns list
272 assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
272 assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
273 :children => { :count => 3 }
273 :children => { :count => 3 }
274 assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
274 assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
275 :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
275 :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
276 end
276 end
277
277
278 def test_index_with_custom_field_column
278 def test_index_with_custom_field_column
279 columns = %w(tracker subject cf_2)
279 columns = %w(tracker subject cf_2)
280 get :index, :set_filter => 1, :c => columns
280 get :index, :set_filter => 1, :c => columns
281 assert_response :success
281 assert_response :success
282
282
283 # query should use specified columns
283 # query should use specified columns
284 query = assigns(:query)
284 query = assigns(:query)
285 assert_kind_of Query, query
285 assert_kind_of Query, query
286 assert_equal columns, query.column_names.map(&:to_s)
286 assert_equal columns, query.column_names.map(&:to_s)
287
287
288 assert_tag :td,
288 assert_tag :td,
289 :attributes => {:class => 'cf_2 string'},
289 :attributes => {:class => 'cf_2 string'},
290 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
290 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
291 end
291 end
292
292
293 def test_show_by_anonymous
293 def test_show_by_anonymous
294 get :show, :id => 1
294 get :show, :id => 1
295 assert_response :success
295 assert_response :success
296 assert_template 'show.rhtml'
296 assert_template 'show.rhtml'
297 assert_not_nil assigns(:issue)
297 assert_not_nil assigns(:issue)
298 assert_equal Issue.find(1), assigns(:issue)
298 assert_equal Issue.find(1), assigns(:issue)
299
299
300 # anonymous role is allowed to add a note
300 # anonymous role is allowed to add a note
301 assert_tag :tag => 'form',
301 assert_tag :tag => 'form',
302 :descendant => { :tag => 'fieldset',
302 :descendant => { :tag => 'fieldset',
303 :child => { :tag => 'legend',
303 :child => { :tag => 'legend',
304 :content => /Notes/ } }
304 :content => /Notes/ } }
305 end
305 end
306
306
307 def test_show_by_manager
307 def test_show_by_manager
308 @request.session[:user_id] = 2
308 @request.session[:user_id] = 2
309 get :show, :id => 1
309 get :show, :id => 1
310 assert_response :success
310 assert_response :success
311
311
312 assert_tag :tag => 'a',
312 assert_tag :tag => 'a',
313 :content => /Quote/
313 :content => /Quote/
314
314
315 assert_tag :tag => 'form',
315 assert_tag :tag => 'form',
316 :descendant => { :tag => 'fieldset',
316 :descendant => { :tag => 'fieldset',
317 :child => { :tag => 'legend',
317 :child => { :tag => 'legend',
318 :content => /Change properties/ } },
318 :content => /Change properties/ } },
319 :descendant => { :tag => 'fieldset',
319 :descendant => { :tag => 'fieldset',
320 :child => { :tag => 'legend',
320 :child => { :tag => 'legend',
321 :content => /Log time/ } },
321 :content => /Log time/ } },
322 :descendant => { :tag => 'fieldset',
322 :descendant => { :tag => 'fieldset',
323 :child => { :tag => 'legend',
323 :child => { :tag => 'legend',
324 :content => /Notes/ } }
324 :content => /Notes/ } }
325 end
325 end
326
326
327 def test_show_should_deny_anonymous_access_without_permission
327 def test_show_should_deny_anonymous_access_without_permission
328 Role.anonymous.remove_permission!(:view_issues)
328 Role.anonymous.remove_permission!(:view_issues)
329 get :show, :id => 1
329 get :show, :id => 1
330 assert_response :redirect
330 assert_response :redirect
331 end
331 end
332
332
333 def test_show_should_deny_anonymous_access_to_private_issue
333 def test_show_should_deny_anonymous_access_to_private_issue
334 Issue.update_all(["is_private = ?", true], "id = 1")
334 Issue.update_all(["is_private = ?", true], "id = 1")
335 get :show, :id => 1
335 get :show, :id => 1
336 assert_response :redirect
336 assert_response :redirect
337 end
337 end
338
338
339 def test_show_should_deny_non_member_access_without_permission
339 def test_show_should_deny_non_member_access_without_permission
340 Role.non_member.remove_permission!(:view_issues)
340 Role.non_member.remove_permission!(:view_issues)
341 @request.session[:user_id] = 9
341 @request.session[:user_id] = 9
342 get :show, :id => 1
342 get :show, :id => 1
343 assert_response 403
343 assert_response 403
344 end
344 end
345
345
346 def test_show_should_deny_non_member_access_to_private_issue
346 def test_show_should_deny_non_member_access_to_private_issue
347 Issue.update_all(["is_private = ?", true], "id = 1")
347 Issue.update_all(["is_private = ?", true], "id = 1")
348 @request.session[:user_id] = 9
348 @request.session[:user_id] = 9
349 get :show, :id => 1
349 get :show, :id => 1
350 assert_response 403
350 assert_response 403
351 end
351 end
352
352
353 def test_show_should_deny_member_access_without_permission
353 def test_show_should_deny_member_access_without_permission
354 Role.find(1).remove_permission!(:view_issues)
354 Role.find(1).remove_permission!(:view_issues)
355 @request.session[:user_id] = 2
355 @request.session[:user_id] = 2
356 get :show, :id => 1
356 get :show, :id => 1
357 assert_response 403
357 assert_response 403
358 end
358 end
359
359
360 def test_show_should_deny_member_access_to_private_issue_without_permission
360 def test_show_should_deny_member_access_to_private_issue_without_permission
361 Issue.update_all(["is_private = ?", true], "id = 1")
361 Issue.update_all(["is_private = ?", true], "id = 1")
362 @request.session[:user_id] = 3
362 @request.session[:user_id] = 3
363 get :show, :id => 1
363 get :show, :id => 1
364 assert_response 403
364 assert_response 403
365 end
365 end
366
366
367 def test_show_should_allow_author_access_to_private_issue
367 def test_show_should_allow_author_access_to_private_issue
368 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
368 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
369 @request.session[:user_id] = 3
369 @request.session[:user_id] = 3
370 get :show, :id => 1
370 get :show, :id => 1
371 assert_response :success
371 assert_response :success
372 end
372 end
373
373
374 def test_show_should_allow_assignee_access_to_private_issue
374 def test_show_should_allow_assignee_access_to_private_issue
375 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
375 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
376 @request.session[:user_id] = 3
376 @request.session[:user_id] = 3
377 get :show, :id => 1
377 get :show, :id => 1
378 assert_response :success
378 assert_response :success
379 end
379 end
380
380
381 def test_show_should_allow_member_access_to_private_issue_with_permission
381 def test_show_should_allow_member_access_to_private_issue_with_permission
382 Issue.update_all(["is_private = ?", true], "id = 1")
382 Issue.update_all(["is_private = ?", true], "id = 1")
383 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
383 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
384 @request.session[:user_id] = 3
384 @request.session[:user_id] = 3
385 get :show, :id => 1
385 get :show, :id => 1
386 assert_response :success
386 assert_response :success
387 end
387 end
388
388
389 def test_show_should_not_disclose_relations_to_invisible_issues
389 def test_show_should_not_disclose_relations_to_invisible_issues
390 Setting.cross_project_issue_relations = '1'
390 Setting.cross_project_issue_relations = '1'
391 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
391 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
392 # Relation to a private project issue
392 # Relation to a private project issue
393 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
393 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
394
394
395 get :show, :id => 1
395 get :show, :id => 1
396 assert_response :success
396 assert_response :success
397
397
398 assert_tag :div, :attributes => { :id => 'relations' },
398 assert_tag :div, :attributes => { :id => 'relations' },
399 :descendant => { :tag => 'a', :content => /#2$/ }
399 :descendant => { :tag => 'a', :content => /#2$/ }
400 assert_no_tag :div, :attributes => { :id => 'relations' },
400 assert_no_tag :div, :attributes => { :id => 'relations' },
401 :descendant => { :tag => 'a', :content => /#4$/ }
401 :descendant => { :tag => 'a', :content => /#4$/ }
402 end
402 end
403
403
404 def test_show_atom
404 def test_show_atom
405 get :show, :id => 2, :format => 'atom'
405 get :show, :id => 2, :format => 'atom'
406 assert_response :success
406 assert_response :success
407 assert_template 'journals/index.rxml'
407 assert_template 'journals/index.rxml'
408 # Inline image
408 # Inline image
409 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
409 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
410 end
410 end
411
411
412 def test_show_export_to_pdf
412 def test_show_export_to_pdf
413 get :show, :id => 3, :format => 'pdf'
413 get :show, :id => 3, :format => 'pdf'
414 assert_response :success
414 assert_response :success
415 assert_equal 'application/pdf', @response.content_type
415 assert_equal 'application/pdf', @response.content_type
416 assert @response.body.starts_with?('%PDF')
416 assert @response.body.starts_with?('%PDF')
417 assert_not_nil assigns(:issue)
417 assert_not_nil assigns(:issue)
418 end
418 end
419
419
420 def test_get_new
420 def test_get_new
421 @request.session[:user_id] = 2
421 @request.session[:user_id] = 2
422 get :new, :project_id => 1, :tracker_id => 1
422 get :new, :project_id => 1, :tracker_id => 1
423 assert_response :success
423 assert_response :success
424 assert_template 'new'
424 assert_template 'new'
425
425
426 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
426 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
427 :value => 'Default string' }
427 :value => 'Default string' }
428 end
428 end
429
429
430 def test_get_new_without_tracker_id
430 def test_get_new_without_tracker_id
431 @request.session[:user_id] = 2
431 @request.session[:user_id] = 2
432 get :new, :project_id => 1
432 get :new, :project_id => 1
433 assert_response :success
433 assert_response :success
434 assert_template 'new'
434 assert_template 'new'
435
435
436 issue = assigns(:issue)
436 issue = assigns(:issue)
437 assert_not_nil issue
437 assert_not_nil issue
438 assert_equal Project.find(1).trackers.first, issue.tracker
438 assert_equal Project.find(1).trackers.first, issue.tracker
439 end
439 end
440
440
441 def test_get_new_with_no_default_status_should_display_an_error
441 def test_get_new_with_no_default_status_should_display_an_error
442 @request.session[:user_id] = 2
442 @request.session[:user_id] = 2
443 IssueStatus.delete_all
443 IssueStatus.delete_all
444
444
445 get :new, :project_id => 1
445 get :new, :project_id => 1
446 assert_response 500
446 assert_response 500
447 assert_error_tag :content => /No default issue/
447 assert_error_tag :content => /No default issue/
448 end
448 end
449
449
450 def test_get_new_with_no_tracker_should_display_an_error
450 def test_get_new_with_no_tracker_should_display_an_error
451 @request.session[:user_id] = 2
451 @request.session[:user_id] = 2
452 Tracker.delete_all
452 Tracker.delete_all
453
453
454 get :new, :project_id => 1
454 get :new, :project_id => 1
455 assert_response 500
455 assert_response 500
456 assert_error_tag :content => /No tracker/
456 assert_error_tag :content => /No tracker/
457 end
457 end
458
458
459 def test_update_new_form
459 def test_update_new_form
460 @request.session[:user_id] = 2
460 @request.session[:user_id] = 2
461 xhr :post, :new, :project_id => 1,
461 xhr :post, :new, :project_id => 1,
462 :issue => {:tracker_id => 2,
462 :issue => {:tracker_id => 2,
463 :subject => 'This is the test_new issue',
463 :subject => 'This is the test_new issue',
464 :description => 'This is the description',
464 :description => 'This is the description',
465 :priority_id => 5}
465 :priority_id => 5}
466 assert_response :success
466 assert_response :success
467 assert_template 'attributes'
467 assert_template 'attributes'
468
468
469 issue = assigns(:issue)
469 issue = assigns(:issue)
470 assert_kind_of Issue, issue
470 assert_kind_of Issue, issue
471 assert_equal 1, issue.project_id
471 assert_equal 1, issue.project_id
472 assert_equal 2, issue.tracker_id
472 assert_equal 2, issue.tracker_id
473 assert_equal 'This is the test_new issue', issue.subject
473 assert_equal 'This is the test_new issue', issue.subject
474 end
474 end
475
475
476 def test_post_create
476 def test_post_create
477 @request.session[:user_id] = 2
477 @request.session[:user_id] = 2
478 assert_difference 'Issue.count' do
478 assert_difference 'Issue.count' do
479 post :create, :project_id => 1,
479 post :create, :project_id => 1,
480 :issue => {:tracker_id => 3,
480 :issue => {:tracker_id => 3,
481 :status_id => 2,
481 :status_id => 2,
482 :subject => 'This is the test_new issue',
482 :subject => 'This is the test_new issue',
483 :description => 'This is the description',
483 :description => 'This is the description',
484 :priority_id => 5,
484 :priority_id => 5,
485 :start_date => '2010-11-07',
485 :start_date => '2010-11-07',
486 :estimated_hours => '',
486 :estimated_hours => '',
487 :custom_field_values => {'2' => 'Value for field 2'}}
487 :custom_field_values => {'2' => 'Value for field 2'}}
488 end
488 end
489 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
489 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
490
490
491 issue = Issue.find_by_subject('This is the test_new issue')
491 issue = Issue.find_by_subject('This is the test_new issue')
492 assert_not_nil issue
492 assert_not_nil issue
493 assert_equal 2, issue.author_id
493 assert_equal 2, issue.author_id
494 assert_equal 3, issue.tracker_id
494 assert_equal 3, issue.tracker_id
495 assert_equal 2, issue.status_id
495 assert_equal 2, issue.status_id
496 assert_equal Date.parse('2010-11-07'), issue.start_date
496 assert_equal Date.parse('2010-11-07'), issue.start_date
497 assert_nil issue.estimated_hours
497 assert_nil issue.estimated_hours
498 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
498 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
499 assert_not_nil v
499 assert_not_nil v
500 assert_equal 'Value for field 2', v.value
500 assert_equal 'Value for field 2', v.value
501 end
501 end
502
502
503 def test_post_create_without_start_date
503 def test_post_create_without_start_date
504 @request.session[:user_id] = 2
504 @request.session[:user_id] = 2
505 assert_difference 'Issue.count' do
505 assert_difference 'Issue.count' do
506 post :create, :project_id => 1,
506 post :create, :project_id => 1,
507 :issue => {:tracker_id => 3,
507 :issue => {:tracker_id => 3,
508 :status_id => 2,
508 :status_id => 2,
509 :subject => 'This is the test_new issue',
509 :subject => 'This is the test_new issue',
510 :description => 'This is the description',
510 :description => 'This is the description',
511 :priority_id => 5,
511 :priority_id => 5,
512 :start_date => '',
512 :start_date => '',
513 :estimated_hours => '',
513 :estimated_hours => '',
514 :custom_field_values => {'2' => 'Value for field 2'}}
514 :custom_field_values => {'2' => 'Value for field 2'}}
515 end
515 end
516 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
516 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
517
517
518 issue = Issue.find_by_subject('This is the test_new issue')
518 issue = Issue.find_by_subject('This is the test_new issue')
519 assert_not_nil issue
519 assert_not_nil issue
520 assert_nil issue.start_date
520 assert_nil issue.start_date
521 end
521 end
522
522
523 def test_post_create_and_continue
523 def test_post_create_and_continue
524 @request.session[:user_id] = 2
524 @request.session[:user_id] = 2
525 post :create, :project_id => 1,
525 post :create, :project_id => 1,
526 :issue => {:tracker_id => 3,
526 :issue => {:tracker_id => 3,
527 :subject => 'This is first issue',
527 :subject => 'This is first issue',
528 :priority_id => 5},
528 :priority_id => 5},
529 :continue => ''
529 :continue => ''
530 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook',
530 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook',
531 :issue => {:tracker_id => 3}
531 :issue => {:tracker_id => 3}
532 end
532 end
533
533
534 def test_post_create_without_custom_fields_param
534 def test_post_create_without_custom_fields_param
535 @request.session[:user_id] = 2
535 @request.session[:user_id] = 2
536 assert_difference 'Issue.count' do
536 assert_difference 'Issue.count' do
537 post :create, :project_id => 1,
537 post :create, :project_id => 1,
538 :issue => {:tracker_id => 1,
538 :issue => {:tracker_id => 1,
539 :subject => 'This is the test_new issue',
539 :subject => 'This is the test_new issue',
540 :description => 'This is the description',
540 :description => 'This is the description',
541 :priority_id => 5}
541 :priority_id => 5}
542 end
542 end
543 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
543 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
544 end
544 end
545
545
546 def test_post_create_with_required_custom_field_and_without_custom_fields_param
546 def test_post_create_with_required_custom_field_and_without_custom_fields_param
547 field = IssueCustomField.find_by_name('Database')
547 field = IssueCustomField.find_by_name('Database')
548 field.update_attribute(:is_required, true)
548 field.update_attribute(:is_required, true)
549
549
550 @request.session[:user_id] = 2
550 @request.session[:user_id] = 2
551 post :create, :project_id => 1,
551 post :create, :project_id => 1,
552 :issue => {:tracker_id => 1,
552 :issue => {:tracker_id => 1,
553 :subject => 'This is the test_new issue',
553 :subject => 'This is the test_new issue',
554 :description => 'This is the description',
554 :description => 'This is the description',
555 :priority_id => 5}
555 :priority_id => 5}
556 assert_response :success
556 assert_response :success
557 assert_template 'new'
557 assert_template 'new'
558 issue = assigns(:issue)
558 issue = assigns(:issue)
559 assert_not_nil issue
559 assert_not_nil issue
560 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
560 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
561 end
561 end
562
562
563 def test_post_create_with_watchers
563 def test_post_create_with_watchers
564 @request.session[:user_id] = 2
564 @request.session[:user_id] = 2
565 ActionMailer::Base.deliveries.clear
565 ActionMailer::Base.deliveries.clear
566
566
567 assert_difference 'Watcher.count', 2 do
567 assert_difference 'Watcher.count', 2 do
568 post :create, :project_id => 1,
568 post :create, :project_id => 1,
569 :issue => {:tracker_id => 1,
569 :issue => {:tracker_id => 1,
570 :subject => 'This is a new issue with watchers',
570 :subject => 'This is a new issue with watchers',
571 :description => 'This is the description',
571 :description => 'This is the description',
572 :priority_id => 5,
572 :priority_id => 5,
573 :watcher_user_ids => ['2', '3']}
573 :watcher_user_ids => ['2', '3']}
574 end
574 end
575 issue = Issue.find_by_subject('This is a new issue with watchers')
575 issue = Issue.find_by_subject('This is a new issue with watchers')
576 assert_not_nil issue
576 assert_not_nil issue
577 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
577 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
578
578
579 # Watchers added
579 # Watchers added
580 assert_equal [2, 3], issue.watcher_user_ids.sort
580 assert_equal [2, 3], issue.watcher_user_ids.sort
581 assert issue.watched_by?(User.find(3))
581 assert issue.watched_by?(User.find(3))
582 # Watchers notified
582 # Watchers notified
583 mail = ActionMailer::Base.deliveries.last
583 mail = ActionMailer::Base.deliveries.last
584 assert_kind_of TMail::Mail, mail
584 assert_kind_of TMail::Mail, mail
585 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
585 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
586 end
586 end
587
587
588 def test_post_create_subissue
588 def test_post_create_subissue
589 @request.session[:user_id] = 2
589 @request.session[:user_id] = 2
590
590
591 assert_difference 'Issue.count' do
591 assert_difference 'Issue.count' do
592 post :create, :project_id => 1,
592 post :create, :project_id => 1,
593 :issue => {:tracker_id => 1,
593 :issue => {:tracker_id => 1,
594 :subject => 'This is a child issue',
594 :subject => 'This is a child issue',
595 :parent_issue_id => 2}
595 :parent_issue_id => 2}
596 end
596 end
597 issue = Issue.find_by_subject('This is a child issue')
597 issue = Issue.find_by_subject('This is a child issue')
598 assert_not_nil issue
598 assert_not_nil issue
599 assert_equal Issue.find(2), issue.parent
599 assert_equal Issue.find(2), issue.parent
600 end
600 end
601
601
602 def test_post_create_subissue_with_non_numeric_parent_id
602 def test_post_create_subissue_with_non_numeric_parent_id
603 @request.session[:user_id] = 2
603 @request.session[:user_id] = 2
604
604
605 assert_difference 'Issue.count' do
605 assert_difference 'Issue.count' do
606 post :create, :project_id => 1,
606 post :create, :project_id => 1,
607 :issue => {:tracker_id => 1,
607 :issue => {:tracker_id => 1,
608 :subject => 'This is a child issue',
608 :subject => 'This is a child issue',
609 :parent_issue_id => 'ABC'}
609 :parent_issue_id => 'ABC'}
610 end
610 end
611 issue = Issue.find_by_subject('This is a child issue')
611 issue = Issue.find_by_subject('This is a child issue')
612 assert_not_nil issue
612 assert_not_nil issue
613 assert_nil issue.parent
613 assert_nil issue.parent
614 end
614 end
615
616 def test_post_create_private
617 @request.session[:user_id] = 2
618
619 assert_difference 'Issue.count' do
620 post :create, :project_id => 1,
621 :issue => {:tracker_id => 1,
622 :subject => 'This is a private issue',
623 :is_private => '1'}
624 end
625 issue = Issue.first(:order => 'id DESC')
626 assert issue.is_private?
627 end
628
629 def test_post_create_private_with_set_own_issues_private_permission
630 role = Role.find(1)
631 role.remove_permission! :set_issues_private
632 role.add_permission! :set_own_issues_private
633
634 @request.session[:user_id] = 2
635
636 assert_difference 'Issue.count' do
637 post :create, :project_id => 1,
638 :issue => {:tracker_id => 1,
639 :subject => 'This is a private issue',
640 :is_private => '1'}
641 end
642 issue = Issue.first(:order => 'id DESC')
643 assert issue.is_private?
644 end
615
645
616 def test_post_create_should_send_a_notification
646 def test_post_create_should_send_a_notification
617 ActionMailer::Base.deliveries.clear
647 ActionMailer::Base.deliveries.clear
618 @request.session[:user_id] = 2
648 @request.session[:user_id] = 2
619 assert_difference 'Issue.count' do
649 assert_difference 'Issue.count' do
620 post :create, :project_id => 1,
650 post :create, :project_id => 1,
621 :issue => {:tracker_id => 3,
651 :issue => {:tracker_id => 3,
622 :subject => 'This is the test_new issue',
652 :subject => 'This is the test_new issue',
623 :description => 'This is the description',
653 :description => 'This is the description',
624 :priority_id => 5,
654 :priority_id => 5,
625 :estimated_hours => '',
655 :estimated_hours => '',
626 :custom_field_values => {'2' => 'Value for field 2'}}
656 :custom_field_values => {'2' => 'Value for field 2'}}
627 end
657 end
628 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
658 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
629
659
630 assert_equal 1, ActionMailer::Base.deliveries.size
660 assert_equal 1, ActionMailer::Base.deliveries.size
631 end
661 end
632
662
633 def test_post_create_should_preserve_fields_values_on_validation_failure
663 def test_post_create_should_preserve_fields_values_on_validation_failure
634 @request.session[:user_id] = 2
664 @request.session[:user_id] = 2
635 post :create, :project_id => 1,
665 post :create, :project_id => 1,
636 :issue => {:tracker_id => 1,
666 :issue => {:tracker_id => 1,
637 # empty subject
667 # empty subject
638 :subject => '',
668 :subject => '',
639 :description => 'This is a description',
669 :description => 'This is a description',
640 :priority_id => 6,
670 :priority_id => 6,
641 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
671 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
642 assert_response :success
672 assert_response :success
643 assert_template 'new'
673 assert_template 'new'
644
674
645 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
675 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
646 :content => 'This is a description'
676 :content => 'This is a description'
647 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
677 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
648 :child => { :tag => 'option', :attributes => { :selected => 'selected',
678 :child => { :tag => 'option', :attributes => { :selected => 'selected',
649 :value => '6' },
679 :value => '6' },
650 :content => 'High' }
680 :content => 'High' }
651 # Custom fields
681 # Custom fields
652 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
682 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
653 :child => { :tag => 'option', :attributes => { :selected => 'selected',
683 :child => { :tag => 'option', :attributes => { :selected => 'selected',
654 :value => 'Oracle' },
684 :value => 'Oracle' },
655 :content => 'Oracle' }
685 :content => 'Oracle' }
656 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
686 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
657 :value => 'Value for field 2'}
687 :value => 'Value for field 2'}
658 end
688 end
659
689
660 def test_post_create_should_ignore_non_safe_attributes
690 def test_post_create_should_ignore_non_safe_attributes
661 @request.session[:user_id] = 2
691 @request.session[:user_id] = 2
662 assert_nothing_raised do
692 assert_nothing_raised do
663 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
693 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
664 end
694 end
665 end
695 end
666
696
667 context "without workflow privilege" do
697 context "without workflow privilege" do
668 setup do
698 setup do
669 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
699 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
670 Role.anonymous.add_permission! :add_issues, :add_issue_notes
700 Role.anonymous.add_permission! :add_issues, :add_issue_notes
671 end
701 end
672
702
673 context "#new" do
703 context "#new" do
674 should "propose default status only" do
704 should "propose default status only" do
675 get :new, :project_id => 1
705 get :new, :project_id => 1
676 assert_response :success
706 assert_response :success
677 assert_template 'new'
707 assert_template 'new'
678 assert_tag :tag => 'select',
708 assert_tag :tag => 'select',
679 :attributes => {:name => 'issue[status_id]'},
709 :attributes => {:name => 'issue[status_id]'},
680 :children => {:count => 1},
710 :children => {:count => 1},
681 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
711 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
682 end
712 end
683
713
684 should "accept default status" do
714 should "accept default status" do
685 assert_difference 'Issue.count' do
715 assert_difference 'Issue.count' do
686 post :create, :project_id => 1,
716 post :create, :project_id => 1,
687 :issue => {:tracker_id => 1,
717 :issue => {:tracker_id => 1,
688 :subject => 'This is an issue',
718 :subject => 'This is an issue',
689 :status_id => 1}
719 :status_id => 1}
690 end
720 end
691 issue = Issue.last(:order => 'id')
721 issue = Issue.last(:order => 'id')
692 assert_equal IssueStatus.default, issue.status
722 assert_equal IssueStatus.default, issue.status
693 end
723 end
694
724
695 should "ignore unauthorized status" do
725 should "ignore unauthorized status" do
696 assert_difference 'Issue.count' do
726 assert_difference 'Issue.count' do
697 post :create, :project_id => 1,
727 post :create, :project_id => 1,
698 :issue => {:tracker_id => 1,
728 :issue => {:tracker_id => 1,
699 :subject => 'This is an issue',
729 :subject => 'This is an issue',
700 :status_id => 3}
730 :status_id => 3}
701 end
731 end
702 issue = Issue.last(:order => 'id')
732 issue = Issue.last(:order => 'id')
703 assert_equal IssueStatus.default, issue.status
733 assert_equal IssueStatus.default, issue.status
704 end
734 end
705 end
735 end
706
736
707 context "#update" do
737 context "#update" do
708 should "ignore status change" do
738 should "ignore status change" do
709 assert_difference 'Journal.count' do
739 assert_difference 'Journal.count' do
710 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
740 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
711 end
741 end
712 assert_equal 1, Issue.find(1).status_id
742 assert_equal 1, Issue.find(1).status_id
713 end
743 end
714
744
715 should "ignore attributes changes" do
745 should "ignore attributes changes" do
716 assert_difference 'Journal.count' do
746 assert_difference 'Journal.count' do
717 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
747 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
718 end
748 end
719 issue = Issue.find(1)
749 issue = Issue.find(1)
720 assert_equal "Can't print recipes", issue.subject
750 assert_equal "Can't print recipes", issue.subject
721 assert_nil issue.assigned_to
751 assert_nil issue.assigned_to
722 end
752 end
723 end
753 end
724 end
754 end
725
755
726 context "with workflow privilege" do
756 context "with workflow privilege" do
727 setup do
757 setup do
728 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
758 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
729 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
759 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
730 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
760 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
731 Role.anonymous.add_permission! :add_issues, :add_issue_notes
761 Role.anonymous.add_permission! :add_issues, :add_issue_notes
732 end
762 end
733
763
734 context "#update" do
764 context "#update" do
735 should "accept authorized status" do
765 should "accept authorized status" do
736 assert_difference 'Journal.count' do
766 assert_difference 'Journal.count' do
737 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
767 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
738 end
768 end
739 assert_equal 3, Issue.find(1).status_id
769 assert_equal 3, Issue.find(1).status_id
740 end
770 end
741
771
742 should "ignore unauthorized status" do
772 should "ignore unauthorized status" do
743 assert_difference 'Journal.count' do
773 assert_difference 'Journal.count' do
744 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
774 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
745 end
775 end
746 assert_equal 1, Issue.find(1).status_id
776 assert_equal 1, Issue.find(1).status_id
747 end
777 end
748
778
749 should "accept authorized attributes changes" do
779 should "accept authorized attributes changes" do
750 assert_difference 'Journal.count' do
780 assert_difference 'Journal.count' do
751 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
781 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
752 end
782 end
753 issue = Issue.find(1)
783 issue = Issue.find(1)
754 assert_equal 2, issue.assigned_to_id
784 assert_equal 2, issue.assigned_to_id
755 end
785 end
756
786
757 should "ignore unauthorized attributes changes" do
787 should "ignore unauthorized attributes changes" do
758 assert_difference 'Journal.count' do
788 assert_difference 'Journal.count' do
759 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
789 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
760 end
790 end
761 issue = Issue.find(1)
791 issue = Issue.find(1)
762 assert_equal "Can't print recipes", issue.subject
792 assert_equal "Can't print recipes", issue.subject
763 end
793 end
764 end
794 end
765
795
766 context "and :edit_issues permission" do
796 context "and :edit_issues permission" do
767 setup do
797 setup do
768 Role.anonymous.add_permission! :add_issues, :edit_issues
798 Role.anonymous.add_permission! :add_issues, :edit_issues
769 end
799 end
770
800
771 should "accept authorized status" do
801 should "accept authorized status" do
772 assert_difference 'Journal.count' do
802 assert_difference 'Journal.count' do
773 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
803 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
774 end
804 end
775 assert_equal 3, Issue.find(1).status_id
805 assert_equal 3, Issue.find(1).status_id
776 end
806 end
777
807
778 should "ignore unauthorized status" do
808 should "ignore unauthorized status" do
779 assert_difference 'Journal.count' do
809 assert_difference 'Journal.count' do
780 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
810 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
781 end
811 end
782 assert_equal 1, Issue.find(1).status_id
812 assert_equal 1, Issue.find(1).status_id
783 end
813 end
784
814
785 should "accept authorized attributes changes" do
815 should "accept authorized attributes changes" do
786 assert_difference 'Journal.count' do
816 assert_difference 'Journal.count' do
787 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
817 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
788 end
818 end
789 issue = Issue.find(1)
819 issue = Issue.find(1)
790 assert_equal "changed", issue.subject
820 assert_equal "changed", issue.subject
791 assert_equal 2, issue.assigned_to_id
821 assert_equal 2, issue.assigned_to_id
792 end
822 end
793 end
823 end
794 end
824 end
795
825
796 def test_copy_issue
826 def test_copy_issue
797 @request.session[:user_id] = 2
827 @request.session[:user_id] = 2
798 get :new, :project_id => 1, :copy_from => 1
828 get :new, :project_id => 1, :copy_from => 1
799 assert_template 'new'
829 assert_template 'new'
800 assert_not_nil assigns(:issue)
830 assert_not_nil assigns(:issue)
801 orig = Issue.find(1)
831 orig = Issue.find(1)
802 assert_equal orig.subject, assigns(:issue).subject
832 assert_equal orig.subject, assigns(:issue).subject
803 end
833 end
804
834
805 def test_get_edit
835 def test_get_edit
806 @request.session[:user_id] = 2
836 @request.session[:user_id] = 2
807 get :edit, :id => 1
837 get :edit, :id => 1
808 assert_response :success
838 assert_response :success
809 assert_template 'edit'
839 assert_template 'edit'
810 assert_not_nil assigns(:issue)
840 assert_not_nil assigns(:issue)
811 assert_equal Issue.find(1), assigns(:issue)
841 assert_equal Issue.find(1), assigns(:issue)
812 end
842 end
813
843
814 def test_get_edit_with_params
844 def test_get_edit_with_params
815 @request.session[:user_id] = 2
845 @request.session[:user_id] = 2
816 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
846 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
817 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
847 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
818 assert_response :success
848 assert_response :success
819 assert_template 'edit'
849 assert_template 'edit'
820
850
821 issue = assigns(:issue)
851 issue = assigns(:issue)
822 assert_not_nil issue
852 assert_not_nil issue
823
853
824 assert_equal 5, issue.status_id
854 assert_equal 5, issue.status_id
825 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
855 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
826 :child => { :tag => 'option',
856 :child => { :tag => 'option',
827 :content => 'Closed',
857 :content => 'Closed',
828 :attributes => { :selected => 'selected' } }
858 :attributes => { :selected => 'selected' } }
829
859
830 assert_equal 7, issue.priority_id
860 assert_equal 7, issue.priority_id
831 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
861 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
832 :child => { :tag => 'option',
862 :child => { :tag => 'option',
833 :content => 'Urgent',
863 :content => 'Urgent',
834 :attributes => { :selected => 'selected' } }
864 :attributes => { :selected => 'selected' } }
835
865
836 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
866 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
837 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
867 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
838 :child => { :tag => 'option',
868 :child => { :tag => 'option',
839 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
869 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
840 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
870 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
841 end
871 end
842
872
843 def test_update_edit_form
873 def test_update_edit_form
844 @request.session[:user_id] = 2
874 @request.session[:user_id] = 2
845 xhr :post, :new, :project_id => 1,
875 xhr :post, :new, :project_id => 1,
846 :id => 1,
876 :id => 1,
847 :issue => {:tracker_id => 2,
877 :issue => {:tracker_id => 2,
848 :subject => 'This is the test_new issue',
878 :subject => 'This is the test_new issue',
849 :description => 'This is the description',
879 :description => 'This is the description',
850 :priority_id => 5}
880 :priority_id => 5}
851 assert_response :success
881 assert_response :success
852 assert_template 'attributes'
882 assert_template 'attributes'
853
883
854 issue = assigns(:issue)
884 issue = assigns(:issue)
855 assert_kind_of Issue, issue
885 assert_kind_of Issue, issue
856 assert_equal 1, issue.id
886 assert_equal 1, issue.id
857 assert_equal 1, issue.project_id
887 assert_equal 1, issue.project_id
858 assert_equal 2, issue.tracker_id
888 assert_equal 2, issue.tracker_id
859 assert_equal 'This is the test_new issue', issue.subject
889 assert_equal 'This is the test_new issue', issue.subject
860 end
890 end
861
891
862 def test_update_using_invalid_http_verbs
892 def test_update_using_invalid_http_verbs
863 @request.session[:user_id] = 2
893 @request.session[:user_id] = 2
864 subject = 'Updated by an invalid http verb'
894 subject = 'Updated by an invalid http verb'
865
895
866 get :update, :id => 1, :issue => {:subject => subject}
896 get :update, :id => 1, :issue => {:subject => subject}
867 assert_not_equal subject, Issue.find(1).subject
897 assert_not_equal subject, Issue.find(1).subject
868
898
869 post :update, :id => 1, :issue => {:subject => subject}
899 post :update, :id => 1, :issue => {:subject => subject}
870 assert_not_equal subject, Issue.find(1).subject
900 assert_not_equal subject, Issue.find(1).subject
871
901
872 delete :update, :id => 1, :issue => {:subject => subject}
902 delete :update, :id => 1, :issue => {:subject => subject}
873 assert_not_equal subject, Issue.find(1).subject
903 assert_not_equal subject, Issue.find(1).subject
874 end
904 end
875
905
876 def test_put_update_without_custom_fields_param
906 def test_put_update_without_custom_fields_param
877 @request.session[:user_id] = 2
907 @request.session[:user_id] = 2
878 ActionMailer::Base.deliveries.clear
908 ActionMailer::Base.deliveries.clear
879
909
880 issue = Issue.find(1)
910 issue = Issue.find(1)
881 assert_equal '125', issue.custom_value_for(2).value
911 assert_equal '125', issue.custom_value_for(2).value
882 old_subject = issue.subject
912 old_subject = issue.subject
883 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
913 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
884
914
885 assert_difference('Journal.count') do
915 assert_difference('Journal.count') do
886 assert_difference('JournalDetail.count', 2) do
916 assert_difference('JournalDetail.count', 2) do
887 put :update, :id => 1, :issue => {:subject => new_subject,
917 put :update, :id => 1, :issue => {:subject => new_subject,
888 :priority_id => '6',
918 :priority_id => '6',
889 :category_id => '1' # no change
919 :category_id => '1' # no change
890 }
920 }
891 end
921 end
892 end
922 end
893 assert_redirected_to :action => 'show', :id => '1'
923 assert_redirected_to :action => 'show', :id => '1'
894 issue.reload
924 issue.reload
895 assert_equal new_subject, issue.subject
925 assert_equal new_subject, issue.subject
896 # Make sure custom fields were not cleared
926 # Make sure custom fields were not cleared
897 assert_equal '125', issue.custom_value_for(2).value
927 assert_equal '125', issue.custom_value_for(2).value
898
928
899 mail = ActionMailer::Base.deliveries.last
929 mail = ActionMailer::Base.deliveries.last
900 assert_kind_of TMail::Mail, mail
930 assert_kind_of TMail::Mail, mail
901 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
931 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
902 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
932 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
903 end
933 end
904
934
905 def test_put_update_with_custom_field_change
935 def test_put_update_with_custom_field_change
906 @request.session[:user_id] = 2
936 @request.session[:user_id] = 2
907 issue = Issue.find(1)
937 issue = Issue.find(1)
908 assert_equal '125', issue.custom_value_for(2).value
938 assert_equal '125', issue.custom_value_for(2).value
909
939
910 assert_difference('Journal.count') do
940 assert_difference('Journal.count') do
911 assert_difference('JournalDetail.count', 3) do
941 assert_difference('JournalDetail.count', 3) do
912 put :update, :id => 1, :issue => {:subject => 'Custom field change',
942 put :update, :id => 1, :issue => {:subject => 'Custom field change',
913 :priority_id => '6',
943 :priority_id => '6',
914 :category_id => '1', # no change
944 :category_id => '1', # no change
915 :custom_field_values => { '2' => 'New custom value' }
945 :custom_field_values => { '2' => 'New custom value' }
916 }
946 }
917 end
947 end
918 end
948 end
919 assert_redirected_to :action => 'show', :id => '1'
949 assert_redirected_to :action => 'show', :id => '1'
920 issue.reload
950 issue.reload
921 assert_equal 'New custom value', issue.custom_value_for(2).value
951 assert_equal 'New custom value', issue.custom_value_for(2).value
922
952
923 mail = ActionMailer::Base.deliveries.last
953 mail = ActionMailer::Base.deliveries.last
924 assert_kind_of TMail::Mail, mail
954 assert_kind_of TMail::Mail, mail
925 assert mail.body.include?("Searchable field changed from 125 to New custom value")
955 assert mail.body.include?("Searchable field changed from 125 to New custom value")
926 end
956 end
927
957
928 def test_put_update_with_status_and_assignee_change
958 def test_put_update_with_status_and_assignee_change
929 issue = Issue.find(1)
959 issue = Issue.find(1)
930 assert_equal 1, issue.status_id
960 assert_equal 1, issue.status_id
931 @request.session[:user_id] = 2
961 @request.session[:user_id] = 2
932 assert_difference('TimeEntry.count', 0) do
962 assert_difference('TimeEntry.count', 0) do
933 put :update,
963 put :update,
934 :id => 1,
964 :id => 1,
935 :issue => { :status_id => 2, :assigned_to_id => 3 },
965 :issue => { :status_id => 2, :assigned_to_id => 3 },
936 :notes => 'Assigned to dlopper',
966 :notes => 'Assigned to dlopper',
937 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
967 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
938 end
968 end
939 assert_redirected_to :action => 'show', :id => '1'
969 assert_redirected_to :action => 'show', :id => '1'
940 issue.reload
970 issue.reload
941 assert_equal 2, issue.status_id
971 assert_equal 2, issue.status_id
942 j = Journal.find(:first, :order => 'id DESC')
972 j = Journal.find(:first, :order => 'id DESC')
943 assert_equal 'Assigned to dlopper', j.notes
973 assert_equal 'Assigned to dlopper', j.notes
944 assert_equal 2, j.details.size
974 assert_equal 2, j.details.size
945
975
946 mail = ActionMailer::Base.deliveries.last
976 mail = ActionMailer::Base.deliveries.last
947 assert mail.body.include?("Status changed from New to Assigned")
977 assert mail.body.include?("Status changed from New to Assigned")
948 # subject should contain the new status
978 # subject should contain the new status
949 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
979 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
950 end
980 end
951
981
952 def test_put_update_with_note_only
982 def test_put_update_with_note_only
953 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
983 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
954 # anonymous user
984 # anonymous user
955 put :update,
985 put :update,
956 :id => 1,
986 :id => 1,
957 :notes => notes
987 :notes => notes
958 assert_redirected_to :action => 'show', :id => '1'
988 assert_redirected_to :action => 'show', :id => '1'
959 j = Journal.find(:first, :order => 'id DESC')
989 j = Journal.find(:first, :order => 'id DESC')
960 assert_equal notes, j.notes
990 assert_equal notes, j.notes
961 assert_equal 0, j.details.size
991 assert_equal 0, j.details.size
962 assert_equal User.anonymous, j.user
992 assert_equal User.anonymous, j.user
963
993
964 mail = ActionMailer::Base.deliveries.last
994 mail = ActionMailer::Base.deliveries.last
965 assert mail.body.include?(notes)
995 assert mail.body.include?(notes)
966 end
996 end
967
997
968 def test_put_update_with_note_and_spent_time
998 def test_put_update_with_note_and_spent_time
969 @request.session[:user_id] = 2
999 @request.session[:user_id] = 2
970 spent_hours_before = Issue.find(1).spent_hours
1000 spent_hours_before = Issue.find(1).spent_hours
971 assert_difference('TimeEntry.count') do
1001 assert_difference('TimeEntry.count') do
972 put :update,
1002 put :update,
973 :id => 1,
1003 :id => 1,
974 :notes => '2.5 hours added',
1004 :notes => '2.5 hours added',
975 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
1005 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
976 end
1006 end
977 assert_redirected_to :action => 'show', :id => '1'
1007 assert_redirected_to :action => 'show', :id => '1'
978
1008
979 issue = Issue.find(1)
1009 issue = Issue.find(1)
980
1010
981 j = Journal.find(:first, :order => 'id DESC')
1011 j = Journal.find(:first, :order => 'id DESC')
982 assert_equal '2.5 hours added', j.notes
1012 assert_equal '2.5 hours added', j.notes
983 assert_equal 0, j.details.size
1013 assert_equal 0, j.details.size
984
1014
985 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
1015 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
986 assert_not_nil t
1016 assert_not_nil t
987 assert_equal 2.5, t.hours
1017 assert_equal 2.5, t.hours
988 assert_equal spent_hours_before + 2.5, issue.spent_hours
1018 assert_equal spent_hours_before + 2.5, issue.spent_hours
989 end
1019 end
990
1020
991 def test_put_update_with_attachment_only
1021 def test_put_update_with_attachment_only
992 set_tmp_attachments_directory
1022 set_tmp_attachments_directory
993
1023
994 # Delete all fixtured journals, a race condition can occur causing the wrong
1024 # Delete all fixtured journals, a race condition can occur causing the wrong
995 # journal to get fetched in the next find.
1025 # journal to get fetched in the next find.
996 Journal.delete_all
1026 Journal.delete_all
997
1027
998 # anonymous user
1028 # anonymous user
999 put :update,
1029 put :update,
1000 :id => 1,
1030 :id => 1,
1001 :notes => '',
1031 :notes => '',
1002 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1032 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1003 assert_redirected_to :action => 'show', :id => '1'
1033 assert_redirected_to :action => 'show', :id => '1'
1004 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
1034 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
1005 assert j.notes.blank?
1035 assert j.notes.blank?
1006 assert_equal 1, j.details.size
1036 assert_equal 1, j.details.size
1007 assert_equal 'testfile.txt', j.details.first.value
1037 assert_equal 'testfile.txt', j.details.first.value
1008 assert_equal User.anonymous, j.user
1038 assert_equal User.anonymous, j.user
1009
1039
1010 mail = ActionMailer::Base.deliveries.last
1040 mail = ActionMailer::Base.deliveries.last
1011 assert mail.body.include?('testfile.txt')
1041 assert mail.body.include?('testfile.txt')
1012 end
1042 end
1013
1043
1014 def test_put_update_with_attachment_that_fails_to_save
1044 def test_put_update_with_attachment_that_fails_to_save
1015 set_tmp_attachments_directory
1045 set_tmp_attachments_directory
1016
1046
1017 # Delete all fixtured journals, a race condition can occur causing the wrong
1047 # Delete all fixtured journals, a race condition can occur causing the wrong
1018 # journal to get fetched in the next find.
1048 # journal to get fetched in the next find.
1019 Journal.delete_all
1049 Journal.delete_all
1020
1050
1021 # Mock out the unsaved attachment
1051 # Mock out the unsaved attachment
1022 Attachment.any_instance.stubs(:create).returns(Attachment.new)
1052 Attachment.any_instance.stubs(:create).returns(Attachment.new)
1023
1053
1024 # anonymous user
1054 # anonymous user
1025 put :update,
1055 put :update,
1026 :id => 1,
1056 :id => 1,
1027 :notes => '',
1057 :notes => '',
1028 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1058 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1029 assert_redirected_to :action => 'show', :id => '1'
1059 assert_redirected_to :action => 'show', :id => '1'
1030 assert_equal '1 file(s) could not be saved.', flash[:warning]
1060 assert_equal '1 file(s) could not be saved.', flash[:warning]
1031
1061
1032 end if Object.const_defined?(:Mocha)
1062 end if Object.const_defined?(:Mocha)
1033
1063
1034 def test_put_update_with_no_change
1064 def test_put_update_with_no_change
1035 issue = Issue.find(1)
1065 issue = Issue.find(1)
1036 issue.journals.clear
1066 issue.journals.clear
1037 ActionMailer::Base.deliveries.clear
1067 ActionMailer::Base.deliveries.clear
1038
1068
1039 put :update,
1069 put :update,
1040 :id => 1,
1070 :id => 1,
1041 :notes => ''
1071 :notes => ''
1042 assert_redirected_to :action => 'show', :id => '1'
1072 assert_redirected_to :action => 'show', :id => '1'
1043
1073
1044 issue.reload
1074 issue.reload
1045 assert issue.journals.empty?
1075 assert issue.journals.empty?
1046 # No email should be sent
1076 # No email should be sent
1047 assert ActionMailer::Base.deliveries.empty?
1077 assert ActionMailer::Base.deliveries.empty?
1048 end
1078 end
1049
1079
1050 def test_put_update_should_send_a_notification
1080 def test_put_update_should_send_a_notification
1051 @request.session[:user_id] = 2
1081 @request.session[:user_id] = 2
1052 ActionMailer::Base.deliveries.clear
1082 ActionMailer::Base.deliveries.clear
1053 issue = Issue.find(1)
1083 issue = Issue.find(1)
1054 old_subject = issue.subject
1084 old_subject = issue.subject
1055 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1085 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1056
1086
1057 put :update, :id => 1, :issue => {:subject => new_subject,
1087 put :update, :id => 1, :issue => {:subject => new_subject,
1058 :priority_id => '6',
1088 :priority_id => '6',
1059 :category_id => '1' # no change
1089 :category_id => '1' # no change
1060 }
1090 }
1061 assert_equal 1, ActionMailer::Base.deliveries.size
1091 assert_equal 1, ActionMailer::Base.deliveries.size
1062 end
1092 end
1063
1093
1064 def test_put_update_with_invalid_spent_time_hours_only
1094 def test_put_update_with_invalid_spent_time_hours_only
1065 @request.session[:user_id] = 2
1095 @request.session[:user_id] = 2
1066 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1096 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1067
1097
1068 assert_no_difference('Journal.count') do
1098 assert_no_difference('Journal.count') do
1069 put :update,
1099 put :update,
1070 :id => 1,
1100 :id => 1,
1071 :notes => notes,
1101 :notes => notes,
1072 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1102 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1073 end
1103 end
1074 assert_response :success
1104 assert_response :success
1075 assert_template 'edit'
1105 assert_template 'edit'
1076
1106
1077 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1107 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1078 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1108 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1079 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1109 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1080 end
1110 end
1081
1111
1082 def test_put_update_with_invalid_spent_time_comments_only
1112 def test_put_update_with_invalid_spent_time_comments_only
1083 @request.session[:user_id] = 2
1113 @request.session[:user_id] = 2
1084 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1114 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1085
1115
1086 assert_no_difference('Journal.count') do
1116 assert_no_difference('Journal.count') do
1087 put :update,
1117 put :update,
1088 :id => 1,
1118 :id => 1,
1089 :notes => notes,
1119 :notes => notes,
1090 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1120 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1091 end
1121 end
1092 assert_response :success
1122 assert_response :success
1093 assert_template 'edit'
1123 assert_template 'edit'
1094
1124
1095 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1125 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1096 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1126 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1097 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1127 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1098 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1128 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1099 end
1129 end
1100
1130
1101 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1131 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1102 issue = Issue.find(2)
1132 issue = Issue.find(2)
1103 @request.session[:user_id] = 2
1133 @request.session[:user_id] = 2
1104
1134
1105 put :update,
1135 put :update,
1106 :id => issue.id,
1136 :id => issue.id,
1107 :issue => {
1137 :issue => {
1108 :fixed_version_id => 4
1138 :fixed_version_id => 4
1109 }
1139 }
1110
1140
1111 assert_response :redirect
1141 assert_response :redirect
1112 issue.reload
1142 issue.reload
1113 assert_equal 4, issue.fixed_version_id
1143 assert_equal 4, issue.fixed_version_id
1114 assert_not_equal issue.project_id, issue.fixed_version.project_id
1144 assert_not_equal issue.project_id, issue.fixed_version.project_id
1115 end
1145 end
1116
1146
1117 def test_put_update_should_redirect_back_using_the_back_url_parameter
1147 def test_put_update_should_redirect_back_using_the_back_url_parameter
1118 issue = Issue.find(2)
1148 issue = Issue.find(2)
1119 @request.session[:user_id] = 2
1149 @request.session[:user_id] = 2
1120
1150
1121 put :update,
1151 put :update,
1122 :id => issue.id,
1152 :id => issue.id,
1123 :issue => {
1153 :issue => {
1124 :fixed_version_id => 4
1154 :fixed_version_id => 4
1125 },
1155 },
1126 :back_url => '/issues'
1156 :back_url => '/issues'
1127
1157
1128 assert_response :redirect
1158 assert_response :redirect
1129 assert_redirected_to '/issues'
1159 assert_redirected_to '/issues'
1130 end
1160 end
1131
1161
1132 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1162 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1133 issue = Issue.find(2)
1163 issue = Issue.find(2)
1134 @request.session[:user_id] = 2
1164 @request.session[:user_id] = 2
1135
1165
1136 put :update,
1166 put :update,
1137 :id => issue.id,
1167 :id => issue.id,
1138 :issue => {
1168 :issue => {
1139 :fixed_version_id => 4
1169 :fixed_version_id => 4
1140 },
1170 },
1141 :back_url => 'http://google.com'
1171 :back_url => 'http://google.com'
1142
1172
1143 assert_response :redirect
1173 assert_response :redirect
1144 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
1174 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
1145 end
1175 end
1146
1176
1147 def test_get_bulk_edit
1177 def test_get_bulk_edit
1148 @request.session[:user_id] = 2
1178 @request.session[:user_id] = 2
1149 get :bulk_edit, :ids => [1, 2]
1179 get :bulk_edit, :ids => [1, 2]
1150 assert_response :success
1180 assert_response :success
1151 assert_template 'bulk_edit'
1181 assert_template 'bulk_edit'
1152
1182
1153 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1183 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1154
1184
1155 # Project specific custom field, date type
1185 # Project specific custom field, date type
1156 field = CustomField.find(9)
1186 field = CustomField.find(9)
1157 assert !field.is_for_all?
1187 assert !field.is_for_all?
1158 assert_equal 'date', field.field_format
1188 assert_equal 'date', field.field_format
1159 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1189 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1160
1190
1161 # System wide custom field
1191 # System wide custom field
1162 assert CustomField.find(1).is_for_all?
1192 assert CustomField.find(1).is_for_all?
1163 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
1193 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
1164 end
1194 end
1165
1195
1166 def test_get_bulk_edit_on_different_projects
1196 def test_get_bulk_edit_on_different_projects
1167 @request.session[:user_id] = 2
1197 @request.session[:user_id] = 2
1168 get :bulk_edit, :ids => [1, 2, 6]
1198 get :bulk_edit, :ids => [1, 2, 6]
1169 assert_response :success
1199 assert_response :success
1170 assert_template 'bulk_edit'
1200 assert_template 'bulk_edit'
1171
1201
1172 # Can not set issues from different projects as children of an issue
1202 # Can not set issues from different projects as children of an issue
1173 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1203 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1174
1204
1175 # Project specific custom field, date type
1205 # Project specific custom field, date type
1176 field = CustomField.find(9)
1206 field = CustomField.find(9)
1177 assert !field.is_for_all?
1207 assert !field.is_for_all?
1178 assert !field.project_ids.include?(Issue.find(6).project_id)
1208 assert !field.project_ids.include?(Issue.find(6).project_id)
1179 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1209 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1180 end
1210 end
1181
1211
1182 def test_get_bulk_edit_with_user_custom_field
1212 def test_get_bulk_edit_with_user_custom_field
1183 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
1213 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
1184
1214
1185 @request.session[:user_id] = 2
1215 @request.session[:user_id] = 2
1186 get :bulk_edit, :ids => [1, 2]
1216 get :bulk_edit, :ids => [1, 2]
1187 assert_response :success
1217 assert_response :success
1188 assert_template 'bulk_edit'
1218 assert_template 'bulk_edit'
1189
1219
1190 assert_tag :select,
1220 assert_tag :select,
1191 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1221 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1192 :children => {
1222 :children => {
1193 :only => {:tag => 'option'},
1223 :only => {:tag => 'option'},
1194 :count => Project.find(1).users.count + 1
1224 :count => Project.find(1).users.count + 1
1195 }
1225 }
1196 end
1226 end
1197
1227
1198 def test_get_bulk_edit_with_version_custom_field
1228 def test_get_bulk_edit_with_version_custom_field
1199 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
1229 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
1200
1230
1201 @request.session[:user_id] = 2
1231 @request.session[:user_id] = 2
1202 get :bulk_edit, :ids => [1, 2]
1232 get :bulk_edit, :ids => [1, 2]
1203 assert_response :success
1233 assert_response :success
1204 assert_template 'bulk_edit'
1234 assert_template 'bulk_edit'
1205
1235
1206 assert_tag :select,
1236 assert_tag :select,
1207 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1237 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1208 :children => {
1238 :children => {
1209 :only => {:tag => 'option'},
1239 :only => {:tag => 'option'},
1210 :count => Project.find(1).versions.count + 1
1240 :count => Project.find(1).versions.count + 1
1211 }
1241 }
1212 end
1242 end
1213
1243
1214 def test_bulk_update
1244 def test_bulk_update
1215 @request.session[:user_id] = 2
1245 @request.session[:user_id] = 2
1216 # update issues priority
1246 # update issues priority
1217 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1247 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1218 :issue => {:priority_id => 7,
1248 :issue => {:priority_id => 7,
1219 :assigned_to_id => '',
1249 :assigned_to_id => '',
1220 :custom_field_values => {'2' => ''}}
1250 :custom_field_values => {'2' => ''}}
1221
1251
1222 assert_response 302
1252 assert_response 302
1223 # check that the issues were updated
1253 # check that the issues were updated
1224 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
1254 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
1225
1255
1226 issue = Issue.find(1)
1256 issue = Issue.find(1)
1227 journal = issue.journals.find(:first, :order => 'created_on DESC')
1257 journal = issue.journals.find(:first, :order => 'created_on DESC')
1228 assert_equal '125', issue.custom_value_for(2).value
1258 assert_equal '125', issue.custom_value_for(2).value
1229 assert_equal 'Bulk editing', journal.notes
1259 assert_equal 'Bulk editing', journal.notes
1230 assert_equal 1, journal.details.size
1260 assert_equal 1, journal.details.size
1231 end
1261 end
1232
1262
1233 def test_bulk_update_on_different_projects
1263 def test_bulk_update_on_different_projects
1234 @request.session[:user_id] = 2
1264 @request.session[:user_id] = 2
1235 # update issues priority
1265 # update issues priority
1236 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
1266 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
1237 :issue => {:priority_id => 7,
1267 :issue => {:priority_id => 7,
1238 :assigned_to_id => '',
1268 :assigned_to_id => '',
1239 :custom_field_values => {'2' => ''}}
1269 :custom_field_values => {'2' => ''}}
1240
1270
1241 assert_response 302
1271 assert_response 302
1242 # check that the issues were updated
1272 # check that the issues were updated
1243 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
1273 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
1244
1274
1245 issue = Issue.find(1)
1275 issue = Issue.find(1)
1246 journal = issue.journals.find(:first, :order => 'created_on DESC')
1276 journal = issue.journals.find(:first, :order => 'created_on DESC')
1247 assert_equal '125', issue.custom_value_for(2).value
1277 assert_equal '125', issue.custom_value_for(2).value
1248 assert_equal 'Bulk editing', journal.notes
1278 assert_equal 'Bulk editing', journal.notes
1249 assert_equal 1, journal.details.size
1279 assert_equal 1, journal.details.size
1250 end
1280 end
1251
1281
1252 def test_bulk_update_on_different_projects_without_rights
1282 def test_bulk_update_on_different_projects_without_rights
1253 @request.session[:user_id] = 3
1283 @request.session[:user_id] = 3
1254 user = User.find(3)
1284 user = User.find(3)
1255 action = { :controller => "issues", :action => "bulk_update" }
1285 action = { :controller => "issues", :action => "bulk_update" }
1256 assert user.allowed_to?(action, Issue.find(1).project)
1286 assert user.allowed_to?(action, Issue.find(1).project)
1257 assert ! user.allowed_to?(action, Issue.find(6).project)
1287 assert ! user.allowed_to?(action, Issue.find(6).project)
1258 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
1288 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
1259 :issue => {:priority_id => 7,
1289 :issue => {:priority_id => 7,
1260 :assigned_to_id => '',
1290 :assigned_to_id => '',
1261 :custom_field_values => {'2' => ''}}
1291 :custom_field_values => {'2' => ''}}
1262 assert_response 403
1292 assert_response 403
1263 assert_not_equal "Bulk should fail", Journal.last.notes
1293 assert_not_equal "Bulk should fail", Journal.last.notes
1264 end
1294 end
1265
1295
1266 def test_bullk_update_should_send_a_notification
1296 def test_bullk_update_should_send_a_notification
1267 @request.session[:user_id] = 2
1297 @request.session[:user_id] = 2
1268 ActionMailer::Base.deliveries.clear
1298 ActionMailer::Base.deliveries.clear
1269 post(:bulk_update,
1299 post(:bulk_update,
1270 {
1300 {
1271 :ids => [1, 2],
1301 :ids => [1, 2],
1272 :notes => 'Bulk editing',
1302 :notes => 'Bulk editing',
1273 :issue => {
1303 :issue => {
1274 :priority_id => 7,
1304 :priority_id => 7,
1275 :assigned_to_id => '',
1305 :assigned_to_id => '',
1276 :custom_field_values => {'2' => ''}
1306 :custom_field_values => {'2' => ''}
1277 }
1307 }
1278 })
1308 })
1279
1309
1280 assert_response 302
1310 assert_response 302
1281 assert_equal 2, ActionMailer::Base.deliveries.size
1311 assert_equal 2, ActionMailer::Base.deliveries.size
1282 end
1312 end
1283
1313
1284 def test_bulk_update_status
1314 def test_bulk_update_status
1285 @request.session[:user_id] = 2
1315 @request.session[:user_id] = 2
1286 # update issues priority
1316 # update issues priority
1287 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
1317 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
1288 :issue => {:priority_id => '',
1318 :issue => {:priority_id => '',
1289 :assigned_to_id => '',
1319 :assigned_to_id => '',
1290 :status_id => '5'}
1320 :status_id => '5'}
1291
1321
1292 assert_response 302
1322 assert_response 302
1293 issue = Issue.find(1)
1323 issue = Issue.find(1)
1294 assert issue.closed?
1324 assert issue.closed?
1295 end
1325 end
1296
1326
1297 def test_bulk_update_parent_id
1327 def test_bulk_update_parent_id
1298 @request.session[:user_id] = 2
1328 @request.session[:user_id] = 2
1299 post :bulk_update, :ids => [1, 3],
1329 post :bulk_update, :ids => [1, 3],
1300 :notes => 'Bulk editing parent',
1330 :notes => 'Bulk editing parent',
1301 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
1331 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
1302
1332
1303 assert_response 302
1333 assert_response 302
1304 parent = Issue.find(2)
1334 parent = Issue.find(2)
1305 assert_equal parent.id, Issue.find(1).parent_id
1335 assert_equal parent.id, Issue.find(1).parent_id
1306 assert_equal parent.id, Issue.find(3).parent_id
1336 assert_equal parent.id, Issue.find(3).parent_id
1307 assert_equal [1, 3], parent.children.collect(&:id).sort
1337 assert_equal [1, 3], parent.children.collect(&:id).sort
1308 end
1338 end
1309
1339
1310 def test_bulk_update_custom_field
1340 def test_bulk_update_custom_field
1311 @request.session[:user_id] = 2
1341 @request.session[:user_id] = 2
1312 # update issues priority
1342 # update issues priority
1313 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
1343 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
1314 :issue => {:priority_id => '',
1344 :issue => {:priority_id => '',
1315 :assigned_to_id => '',
1345 :assigned_to_id => '',
1316 :custom_field_values => {'2' => '777'}}
1346 :custom_field_values => {'2' => '777'}}
1317
1347
1318 assert_response 302
1348 assert_response 302
1319
1349
1320 issue = Issue.find(1)
1350 issue = Issue.find(1)
1321 journal = issue.journals.find(:first, :order => 'created_on DESC')
1351 journal = issue.journals.find(:first, :order => 'created_on DESC')
1322 assert_equal '777', issue.custom_value_for(2).value
1352 assert_equal '777', issue.custom_value_for(2).value
1323 assert_equal 1, journal.details.size
1353 assert_equal 1, journal.details.size
1324 assert_equal '125', journal.details.first.old_value
1354 assert_equal '125', journal.details.first.old_value
1325 assert_equal '777', journal.details.first.value
1355 assert_equal '777', journal.details.first.value
1326 end
1356 end
1327
1357
1328 def test_bulk_update_unassign
1358 def test_bulk_update_unassign
1329 assert_not_nil Issue.find(2).assigned_to
1359 assert_not_nil Issue.find(2).assigned_to
1330 @request.session[:user_id] = 2
1360 @request.session[:user_id] = 2
1331 # unassign issues
1361 # unassign issues
1332 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
1362 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
1333 assert_response 302
1363 assert_response 302
1334 # check that the issues were updated
1364 # check that the issues were updated
1335 assert_nil Issue.find(2).assigned_to
1365 assert_nil Issue.find(2).assigned_to
1336 end
1366 end
1337
1367
1338 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
1368 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
1339 @request.session[:user_id] = 2
1369 @request.session[:user_id] = 2
1340
1370
1341 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
1371 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
1342
1372
1343 assert_response :redirect
1373 assert_response :redirect
1344 issues = Issue.find([1,2])
1374 issues = Issue.find([1,2])
1345 issues.each do |issue|
1375 issues.each do |issue|
1346 assert_equal 4, issue.fixed_version_id
1376 assert_equal 4, issue.fixed_version_id
1347 assert_not_equal issue.project_id, issue.fixed_version.project_id
1377 assert_not_equal issue.project_id, issue.fixed_version.project_id
1348 end
1378 end
1349 end
1379 end
1350
1380
1351 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1381 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1352 @request.session[:user_id] = 2
1382 @request.session[:user_id] = 2
1353 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1383 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1354
1384
1355 assert_response :redirect
1385 assert_response :redirect
1356 assert_redirected_to '/issues'
1386 assert_redirected_to '/issues'
1357 end
1387 end
1358
1388
1359 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1389 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1360 @request.session[:user_id] = 2
1390 @request.session[:user_id] = 2
1361 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1391 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1362
1392
1363 assert_response :redirect
1393 assert_response :redirect
1364 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1394 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1365 end
1395 end
1366
1396
1367 def test_destroy_issue_with_no_time_entries
1397 def test_destroy_issue_with_no_time_entries
1368 assert_nil TimeEntry.find_by_issue_id(2)
1398 assert_nil TimeEntry.find_by_issue_id(2)
1369 @request.session[:user_id] = 2
1399 @request.session[:user_id] = 2
1370 post :destroy, :id => 2
1400 post :destroy, :id => 2
1371 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1401 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1372 assert_nil Issue.find_by_id(2)
1402 assert_nil Issue.find_by_id(2)
1373 end
1403 end
1374
1404
1375 def test_destroy_issues_with_time_entries
1405 def test_destroy_issues_with_time_entries
1376 @request.session[:user_id] = 2
1406 @request.session[:user_id] = 2
1377 post :destroy, :ids => [1, 3]
1407 post :destroy, :ids => [1, 3]
1378 assert_response :success
1408 assert_response :success
1379 assert_template 'destroy'
1409 assert_template 'destroy'
1380 assert_not_nil assigns(:hours)
1410 assert_not_nil assigns(:hours)
1381 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1411 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1382 end
1412 end
1383
1413
1384 def test_destroy_issues_and_destroy_time_entries
1414 def test_destroy_issues_and_destroy_time_entries
1385 @request.session[:user_id] = 2
1415 @request.session[:user_id] = 2
1386 post :destroy, :ids => [1, 3], :todo => 'destroy'
1416 post :destroy, :ids => [1, 3], :todo => 'destroy'
1387 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1417 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1388 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1418 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1389 assert_nil TimeEntry.find_by_id([1, 2])
1419 assert_nil TimeEntry.find_by_id([1, 2])
1390 end
1420 end
1391
1421
1392 def test_destroy_issues_and_assign_time_entries_to_project
1422 def test_destroy_issues_and_assign_time_entries_to_project
1393 @request.session[:user_id] = 2
1423 @request.session[:user_id] = 2
1394 post :destroy, :ids => [1, 3], :todo => 'nullify'
1424 post :destroy, :ids => [1, 3], :todo => 'nullify'
1395 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1425 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1396 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1426 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1397 assert_nil TimeEntry.find(1).issue_id
1427 assert_nil TimeEntry.find(1).issue_id
1398 assert_nil TimeEntry.find(2).issue_id
1428 assert_nil TimeEntry.find(2).issue_id
1399 end
1429 end
1400
1430
1401 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1431 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1402 @request.session[:user_id] = 2
1432 @request.session[:user_id] = 2
1403 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1433 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1404 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1434 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1405 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1435 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1406 assert_equal 2, TimeEntry.find(1).issue_id
1436 assert_equal 2, TimeEntry.find(1).issue_id
1407 assert_equal 2, TimeEntry.find(2).issue_id
1437 assert_equal 2, TimeEntry.find(2).issue_id
1408 end
1438 end
1409
1439
1410 def test_destroy_issues_from_different_projects
1440 def test_destroy_issues_from_different_projects
1411 @request.session[:user_id] = 2
1441 @request.session[:user_id] = 2
1412 post :destroy, :ids => [1, 2, 6], :todo => 'destroy'
1442 post :destroy, :ids => [1, 2, 6], :todo => 'destroy'
1413 assert_redirected_to :controller => 'issues', :action => 'index'
1443 assert_redirected_to :controller => 'issues', :action => 'index'
1414 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
1444 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
1415 end
1445 end
1416
1446
1417 def test_destroy_parent_and_child_issues
1447 def test_destroy_parent_and_child_issues
1418 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
1448 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
1419 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
1449 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
1420 assert child.is_descendant_of?(parent.reload)
1450 assert child.is_descendant_of?(parent.reload)
1421
1451
1422 @request.session[:user_id] = 2
1452 @request.session[:user_id] = 2
1423 assert_difference 'Issue.count', -2 do
1453 assert_difference 'Issue.count', -2 do
1424 post :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
1454 post :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
1425 end
1455 end
1426 assert_response 302
1456 assert_response 302
1427 end
1457 end
1428
1458
1429 def test_default_search_scope
1459 def test_default_search_scope
1430 get :index
1460 get :index
1431 assert_tag :div, :attributes => {:id => 'quick-search'},
1461 assert_tag :div, :attributes => {:id => 'quick-search'},
1432 :child => {:tag => 'form',
1462 :child => {:tag => 'form',
1433 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1463 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1434 end
1464 end
1435 end
1465 end
General Comments 0
You need to be logged in to leave comments. Login now