##// END OF EJS Templates
Fixed "Create and continue" redirection broken by recent changes. #6333...
Jean-Baptiste Barth -
r3969:12e10f6956fc
parent child
Show More
@@ -1,326 +1,326
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 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 :find_project, :only => [:new, :create]
24 before_filter :find_project, :only => [:new, :create]
25 before_filter :authorize, :except => [:index]
25 before_filter :authorize, :except => [:index]
26 before_filter :find_optional_project, :only => [:index]
26 before_filter :find_optional_project, :only => [:index]
27 before_filter :check_for_default_issue_status, :only => [:new, :create]
27 before_filter :check_for_default_issue_status, :only => [:new, :create]
28 before_filter :build_new_issue_from_params, :only => [:new, :create]
28 before_filter :build_new_issue_from_params, :only => [:new, :create]
29 accept_key_auth :index, :show
29 accept_key_auth :index, :show
30
30
31 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
31 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
32
32
33 helper :journals
33 helper :journals
34 helper :projects
34 helper :projects
35 include ProjectsHelper
35 include ProjectsHelper
36 helper :custom_fields
36 helper :custom_fields
37 include CustomFieldsHelper
37 include CustomFieldsHelper
38 helper :issue_relations
38 helper :issue_relations
39 include IssueRelationsHelper
39 include IssueRelationsHelper
40 helper :watchers
40 helper :watchers
41 include WatchersHelper
41 include WatchersHelper
42 helper :attachments
42 helper :attachments
43 include AttachmentsHelper
43 include AttachmentsHelper
44 helper :queries
44 helper :queries
45 include QueriesHelper
45 include QueriesHelper
46 helper :sort
46 helper :sort
47 include SortHelper
47 include SortHelper
48 include IssuesHelper
48 include IssuesHelper
49 helper :timelog
49 helper :timelog
50 helper :gantt
50 helper :gantt
51 include Redmine::Export::PDF
51 include Redmine::Export::PDF
52
52
53 verify :method => [:post, :delete],
53 verify :method => [:post, :delete],
54 :only => :destroy,
54 :only => :destroy,
55 :render => { :nothing => true, :status => :method_not_allowed }
55 :render => { :nothing => true, :status => :method_not_allowed }
56
56
57 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
57 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
58 verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed }
58 verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed }
59 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
59 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
60
60
61 def index
61 def index
62 retrieve_query
62 retrieve_query
63 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
63 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
64 sort_update(@query.sortable_columns)
64 sort_update(@query.sortable_columns)
65
65
66 if @query.valid?
66 if @query.valid?
67 limit = case params[:format]
67 limit = case params[:format]
68 when 'csv', 'pdf'
68 when 'csv', 'pdf'
69 Setting.issues_export_limit.to_i
69 Setting.issues_export_limit.to_i
70 when 'atom'
70 when 'atom'
71 Setting.feeds_limit.to_i
71 Setting.feeds_limit.to_i
72 else
72 else
73 per_page_option
73 per_page_option
74 end
74 end
75
75
76 @issue_count = @query.issue_count
76 @issue_count = @query.issue_count
77 @issue_pages = Paginator.new self, @issue_count, limit, params['page']
77 @issue_pages = Paginator.new self, @issue_count, limit, params['page']
78 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
78 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
79 :order => sort_clause,
79 :order => sort_clause,
80 :offset => @issue_pages.current.offset,
80 :offset => @issue_pages.current.offset,
81 :limit => limit)
81 :limit => limit)
82 @issue_count_by_group = @query.issue_count_by_group
82 @issue_count_by_group = @query.issue_count_by_group
83
83
84 respond_to do |format|
84 respond_to do |format|
85 format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
85 format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
86 format.xml { render :layout => false }
86 format.xml { render :layout => false }
87 format.json { render :text => @issues.to_json, :layout => false }
87 format.json { render :text => @issues.to_json, :layout => false }
88 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
88 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
89 format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }
89 format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }
90 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
90 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
91 end
91 end
92 else
92 else
93 # Send html if the query is not valid
93 # Send html if the query is not valid
94 render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
94 render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
95 end
95 end
96 rescue ActiveRecord::RecordNotFound
96 rescue ActiveRecord::RecordNotFound
97 render_404
97 render_404
98 end
98 end
99
99
100 def show
100 def show
101 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
101 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
102 @journals.each_with_index {|j,i| j.indice = i+1}
102 @journals.each_with_index {|j,i| j.indice = i+1}
103 @journals.reverse! if User.current.wants_comments_in_reverse_order?
103 @journals.reverse! if User.current.wants_comments_in_reverse_order?
104 @changesets = @issue.changesets.visible.all
104 @changesets = @issue.changesets.visible.all
105 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
105 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
106 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
106 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
107 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
107 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
108 @priorities = IssuePriority.all
108 @priorities = IssuePriority.all
109 @time_entry = TimeEntry.new
109 @time_entry = TimeEntry.new
110 respond_to do |format|
110 respond_to do |format|
111 format.html { render :template => 'issues/show.rhtml' }
111 format.html { render :template => 'issues/show.rhtml' }
112 format.xml { render :layout => false }
112 format.xml { render :layout => false }
113 format.json { render :text => @issue.to_json, :layout => false }
113 format.json { render :text => @issue.to_json, :layout => false }
114 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
114 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
115 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
115 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
116 end
116 end
117 end
117 end
118
118
119 # Add a new issue
119 # Add a new issue
120 # The new issue will be created from an existing one if copy_from parameter is given
120 # The new issue will be created from an existing one if copy_from parameter is given
121 def new
121 def new
122 respond_to do |format|
122 respond_to do |format|
123 format.html { render :action => 'new', :layout => !request.xhr? }
123 format.html { render :action => 'new', :layout => !request.xhr? }
124 format.js { render :partial => 'attributes' }
124 format.js { render :partial => 'attributes' }
125 end
125 end
126 end
126 end
127
127
128 def create
128 def create
129 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
129 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
130 if @issue.save
130 if @issue.save
131 attachments = Attachment.attach_files(@issue, params[:attachments])
131 attachments = Attachment.attach_files(@issue, params[:attachments])
132 render_attachment_warning_if_needed(@issue)
132 render_attachment_warning_if_needed(@issue)
133 flash[:notice] = l(:notice_successful_create)
133 flash[:notice] = l(:notice_successful_create)
134 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
134 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
135 respond_to do |format|
135 respond_to do |format|
136 format.html {
136 format.html {
137 redirect_to(params[:continue] ? { :action => 'new', :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
137 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?} } :
138 { :action => 'show', :id => @issue })
138 { :action => 'show', :id => @issue })
139 }
139 }
140 format.xml { render :action => 'show', :status => :created, :location => url_for(:controller => 'issues', :action => 'show', :id => @issue) }
140 format.xml { render :action => 'show', :status => :created, :location => url_for(:controller => 'issues', :action => 'show', :id => @issue) }
141 format.json { render :text => @issue.to_json, :status => :created, :location => url_for(:controller => 'issues', :action => 'show'), :layout => false }
141 format.json { render :text => @issue.to_json, :status => :created, :location => url_for(:controller => 'issues', :action => 'show'), :layout => false }
142 end
142 end
143 return
143 return
144 else
144 else
145 respond_to do |format|
145 respond_to do |format|
146 format.html { render :action => 'new' }
146 format.html { render :action => 'new' }
147 format.xml { render(:xml => @issue.errors, :status => :unprocessable_entity); return }
147 format.xml { render(:xml => @issue.errors, :status => :unprocessable_entity); return }
148 format.json { render :text => object_errors_to_json(@issue), :status => :unprocessable_entity, :layout => false }
148 format.json { render :text => object_errors_to_json(@issue), :status => :unprocessable_entity, :layout => false }
149 end
149 end
150 end
150 end
151 end
151 end
152
152
153 # Attributes that can be updated on workflow transition (without :edit permission)
153 # Attributes that can be updated on workflow transition (without :edit permission)
154 # TODO: make it configurable (at least per role)
154 # TODO: make it configurable (at least per role)
155 UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id fixed_version_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION)
155 UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id fixed_version_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION)
156
156
157 def edit
157 def edit
158 update_issue_from_params
158 update_issue_from_params
159
159
160 @journal = @issue.current_journal
160 @journal = @issue.current_journal
161
161
162 respond_to do |format|
162 respond_to do |format|
163 format.html { }
163 format.html { }
164 format.xml { }
164 format.xml { }
165 end
165 end
166 end
166 end
167
167
168 def update
168 def update
169 update_issue_from_params
169 update_issue_from_params
170
170
171 if @issue.save_issue_with_child_records(params, @time_entry)
171 if @issue.save_issue_with_child_records(params, @time_entry)
172 render_attachment_warning_if_needed(@issue)
172 render_attachment_warning_if_needed(@issue)
173 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
173 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
174
174
175 respond_to do |format|
175 respond_to do |format|
176 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
176 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
177 format.xml { head :ok }
177 format.xml { head :ok }
178 format.json { head :ok }
178 format.json { head :ok }
179 end
179 end
180 else
180 else
181 render_attachment_warning_if_needed(@issue)
181 render_attachment_warning_if_needed(@issue)
182 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
182 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
183 @journal = @issue.current_journal
183 @journal = @issue.current_journal
184
184
185 respond_to do |format|
185 respond_to do |format|
186 format.html { render :action => 'edit' }
186 format.html { render :action => 'edit' }
187 format.xml { render :xml => @issue.errors, :status => :unprocessable_entity }
187 format.xml { render :xml => @issue.errors, :status => :unprocessable_entity }
188 format.json { render :text => object_errors_to_json(@issue), :status => :unprocessable_entity, :layout => false }
188 format.json { render :text => object_errors_to_json(@issue), :status => :unprocessable_entity, :layout => false }
189 end
189 end
190 end
190 end
191 end
191 end
192
192
193 # Bulk edit a set of issues
193 # Bulk edit a set of issues
194 def bulk_edit
194 def bulk_edit
195 @issues.sort!
195 @issues.sort!
196 @available_statuses = Workflow.available_statuses(@project)
196 @available_statuses = Workflow.available_statuses(@project)
197 @custom_fields = @project.all_issue_custom_fields
197 @custom_fields = @project.all_issue_custom_fields
198 end
198 end
199
199
200 def bulk_update
200 def bulk_update
201 @issues.sort!
201 @issues.sort!
202 attributes = parse_params_for_bulk_issue_attributes(params)
202 attributes = parse_params_for_bulk_issue_attributes(params)
203
203
204 unsaved_issue_ids = []
204 unsaved_issue_ids = []
205 @issues.each do |issue|
205 @issues.each do |issue|
206 issue.reload
206 issue.reload
207 journal = issue.init_journal(User.current, params[:notes])
207 journal = issue.init_journal(User.current, params[:notes])
208 issue.safe_attributes = attributes
208 issue.safe_attributes = attributes
209 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
209 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
210 unless issue.save
210 unless issue.save
211 # Keep unsaved issue ids to display them in flash error
211 # Keep unsaved issue ids to display them in flash error
212 unsaved_issue_ids << issue.id
212 unsaved_issue_ids << issue.id
213 end
213 end
214 end
214 end
215 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
215 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
216 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
216 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
217 end
217 end
218
218
219 def destroy
219 def destroy
220 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
220 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
221 if @hours > 0
221 if @hours > 0
222 case params[:todo]
222 case params[:todo]
223 when 'destroy'
223 when 'destroy'
224 # nothing to do
224 # nothing to do
225 when 'nullify'
225 when 'nullify'
226 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
226 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
227 when 'reassign'
227 when 'reassign'
228 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
228 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
229 if reassign_to.nil?
229 if reassign_to.nil?
230 flash.now[:error] = l(:error_issue_not_found_in_project)
230 flash.now[:error] = l(:error_issue_not_found_in_project)
231 return
231 return
232 else
232 else
233 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
233 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
234 end
234 end
235 else
235 else
236 unless params[:format] == 'xml' || params[:format] == 'json'
236 unless params[:format] == 'xml' || params[:format] == 'json'
237 # display the destroy form if it's a user request
237 # display the destroy form if it's a user request
238 return
238 return
239 end
239 end
240 end
240 end
241 end
241 end
242 @issues.each(&:destroy)
242 @issues.each(&:destroy)
243 respond_to do |format|
243 respond_to do |format|
244 format.html { redirect_to :action => 'index', :project_id => @project }
244 format.html { redirect_to :action => 'index', :project_id => @project }
245 format.xml { head :ok }
245 format.xml { head :ok }
246 format.json { head :ok }
246 format.json { head :ok }
247 end
247 end
248 end
248 end
249
249
250 private
250 private
251 def find_issue
251 def find_issue
252 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
252 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
253 @project = @issue.project
253 @project = @issue.project
254 rescue ActiveRecord::RecordNotFound
254 rescue ActiveRecord::RecordNotFound
255 render_404
255 render_404
256 end
256 end
257
257
258 def find_project
258 def find_project
259 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
259 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
260 @project = Project.find(project_id)
260 @project = Project.find(project_id)
261 rescue ActiveRecord::RecordNotFound
261 rescue ActiveRecord::RecordNotFound
262 render_404
262 render_404
263 end
263 end
264
264
265 # Used by #edit and #update to set some common instance variables
265 # Used by #edit and #update to set some common instance variables
266 # from the params
266 # from the params
267 # TODO: Refactor, not everything in here is needed by #edit
267 # TODO: Refactor, not everything in here is needed by #edit
268 def update_issue_from_params
268 def update_issue_from_params
269 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
269 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
270 @priorities = IssuePriority.all
270 @priorities = IssuePriority.all
271 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
271 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
272 @time_entry = TimeEntry.new
272 @time_entry = TimeEntry.new
273
273
274 @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
274 @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
275 @issue.init_journal(User.current, @notes)
275 @issue.init_journal(User.current, @notes)
276 # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed
276 # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed
277 if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue]
277 if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue]
278 attrs = params[:issue].dup
278 attrs = params[:issue].dup
279 attrs.delete_if {|k,v| !UPDATABLE_ATTRS_ON_TRANSITION.include?(k) } unless @edit_allowed
279 attrs.delete_if {|k,v| !UPDATABLE_ATTRS_ON_TRANSITION.include?(k) } unless @edit_allowed
280 attrs.delete(:status_id) unless @allowed_statuses.detect {|s| s.id.to_s == attrs[:status_id].to_s}
280 attrs.delete(:status_id) unless @allowed_statuses.detect {|s| s.id.to_s == attrs[:status_id].to_s}
281 @issue.safe_attributes = attrs
281 @issue.safe_attributes = attrs
282 end
282 end
283
283
284 end
284 end
285
285
286 # TODO: Refactor, lots of extra code in here
286 # TODO: Refactor, lots of extra code in here
287 def build_new_issue_from_params
287 def build_new_issue_from_params
288 if params[:id].blank?
288 if params[:id].blank?
289 @issue = Issue.new
289 @issue = Issue.new
290 @issue.copy_from(params[:copy_from]) if params[:copy_from]
290 @issue.copy_from(params[:copy_from]) if params[:copy_from]
291 @issue.project = @project
291 @issue.project = @project
292 else
292 else
293 @issue = @project.issues.visible.find(params[:id])
293 @issue = @project.issues.visible.find(params[:id])
294 end
294 end
295
295
296 @issue.project = @project
296 @issue.project = @project
297 # Tracker must be set before custom field values
297 # Tracker must be set before custom field values
298 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
298 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
299 if @issue.tracker.nil?
299 if @issue.tracker.nil?
300 render_error l(:error_no_tracker_in_project)
300 render_error l(:error_no_tracker_in_project)
301 return false
301 return false
302 end
302 end
303 if params[:issue].is_a?(Hash)
303 if params[:issue].is_a?(Hash)
304 @issue.safe_attributes = params[:issue]
304 @issue.safe_attributes = params[:issue]
305 @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project)
305 @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project)
306 end
306 end
307 @issue.author = User.current
307 @issue.author = User.current
308 @issue.start_date ||= Date.today
308 @issue.start_date ||= Date.today
309 @priorities = IssuePriority.all
309 @priorities = IssuePriority.all
310 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
310 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
311 end
311 end
312
312
313 def check_for_default_issue_status
313 def check_for_default_issue_status
314 if IssueStatus.default.nil?
314 if IssueStatus.default.nil?
315 render_error l(:error_no_default_issue_status)
315 render_error l(:error_no_default_issue_status)
316 return false
316 return false
317 end
317 end
318 end
318 end
319
319
320 def parse_params_for_bulk_issue_attributes(params)
320 def parse_params_for_bulk_issue_attributes(params)
321 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
321 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
322 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
322 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
323 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
323 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
324 attributes
324 attributes
325 end
325 end
326 end
326 end
@@ -1,1069 +1,1070
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 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.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
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_with_project
95 def test_index_with_project
96 Setting.display_subprojects_issues = 0
96 Setting.display_subprojects_issues = 0
97 get :index, :project_id => 1
97 get :index, :project_id => 1
98 assert_response :success
98 assert_response :success
99 assert_template 'index.rhtml'
99 assert_template 'index.rhtml'
100 assert_not_nil assigns(:issues)
100 assert_not_nil assigns(:issues)
101 assert_tag :tag => 'a', :content => /Can't print recipes/
101 assert_tag :tag => 'a', :content => /Can't print recipes/
102 assert_no_tag :tag => 'a', :content => /Subproject issue/
102 assert_no_tag :tag => 'a', :content => /Subproject issue/
103 end
103 end
104
104
105 def test_index_with_project_and_subprojects
105 def test_index_with_project_and_subprojects
106 Setting.display_subprojects_issues = 1
106 Setting.display_subprojects_issues = 1
107 get :index, :project_id => 1
107 get :index, :project_id => 1
108 assert_response :success
108 assert_response :success
109 assert_template 'index.rhtml'
109 assert_template 'index.rhtml'
110 assert_not_nil assigns(:issues)
110 assert_not_nil assigns(:issues)
111 assert_tag :tag => 'a', :content => /Can't print recipes/
111 assert_tag :tag => 'a', :content => /Can't print recipes/
112 assert_tag :tag => 'a', :content => /Subproject issue/
112 assert_tag :tag => 'a', :content => /Subproject issue/
113 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
113 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
114 end
114 end
115
115
116 def test_index_with_project_and_subprojects_should_show_private_subprojects
116 def test_index_with_project_and_subprojects_should_show_private_subprojects
117 @request.session[:user_id] = 2
117 @request.session[:user_id] = 2
118 Setting.display_subprojects_issues = 1
118 Setting.display_subprojects_issues = 1
119 get :index, :project_id => 1
119 get :index, :project_id => 1
120 assert_response :success
120 assert_response :success
121 assert_template 'index.rhtml'
121 assert_template 'index.rhtml'
122 assert_not_nil assigns(:issues)
122 assert_not_nil assigns(:issues)
123 assert_tag :tag => 'a', :content => /Can't print recipes/
123 assert_tag :tag => 'a', :content => /Can't print recipes/
124 assert_tag :tag => 'a', :content => /Subproject issue/
124 assert_tag :tag => 'a', :content => /Subproject issue/
125 assert_tag :tag => 'a', :content => /Issue of a private subproject/
125 assert_tag :tag => 'a', :content => /Issue of a private subproject/
126 end
126 end
127
127
128 def test_index_with_project_and_filter
128 def test_index_with_project_and_filter
129 get :index, :project_id => 1, :set_filter => 1
129 get :index, :project_id => 1, :set_filter => 1
130 assert_response :success
130 assert_response :success
131 assert_template 'index.rhtml'
131 assert_template 'index.rhtml'
132 assert_not_nil assigns(:issues)
132 assert_not_nil assigns(:issues)
133 end
133 end
134
134
135 def test_index_with_query
135 def test_index_with_query
136 get :index, :project_id => 1, :query_id => 5
136 get :index, :project_id => 1, :query_id => 5
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 assert_nil assigns(:issue_count_by_group)
140 assert_nil assigns(:issue_count_by_group)
141 end
141 end
142
142
143 def test_index_with_query_grouped_by_tracker
143 def test_index_with_query_grouped_by_tracker
144 get :index, :project_id => 1, :query_id => 6
144 get :index, :project_id => 1, :query_id => 6
145 assert_response :success
145 assert_response :success
146 assert_template 'index.rhtml'
146 assert_template 'index.rhtml'
147 assert_not_nil assigns(:issues)
147 assert_not_nil assigns(:issues)
148 assert_not_nil assigns(:issue_count_by_group)
148 assert_not_nil assigns(:issue_count_by_group)
149 end
149 end
150
150
151 def test_index_with_query_grouped_by_list_custom_field
151 def test_index_with_query_grouped_by_list_custom_field
152 get :index, :project_id => 1, :query_id => 9
152 get :index, :project_id => 1, :query_id => 9
153 assert_response :success
153 assert_response :success
154 assert_template 'index.rhtml'
154 assert_template 'index.rhtml'
155 assert_not_nil assigns(:issues)
155 assert_not_nil assigns(:issues)
156 assert_not_nil assigns(:issue_count_by_group)
156 assert_not_nil assigns(:issue_count_by_group)
157 end
157 end
158
158
159 def test_index_sort_by_field_not_included_in_columns
159 def test_index_sort_by_field_not_included_in_columns
160 Setting.issue_list_default_columns = %w(subject author)
160 Setting.issue_list_default_columns = %w(subject author)
161 get :index, :sort => 'tracker'
161 get :index, :sort => 'tracker'
162 end
162 end
163
163
164 def test_index_csv_with_project
164 def test_index_csv_with_project
165 Setting.default_language = 'en'
165 Setting.default_language = 'en'
166
166
167 get :index, :format => 'csv'
167 get :index, :format => 'csv'
168 assert_response :success
168 assert_response :success
169 assert_not_nil assigns(:issues)
169 assert_not_nil assigns(:issues)
170 assert_equal 'text/csv', @response.content_type
170 assert_equal 'text/csv', @response.content_type
171 assert @response.body.starts_with?("#,")
171 assert @response.body.starts_with?("#,")
172
172
173 get :index, :project_id => 1, :format => 'csv'
173 get :index, :project_id => 1, :format => 'csv'
174 assert_response :success
174 assert_response :success
175 assert_not_nil assigns(:issues)
175 assert_not_nil assigns(:issues)
176 assert_equal 'text/csv', @response.content_type
176 assert_equal 'text/csv', @response.content_type
177 end
177 end
178
178
179 def test_index_pdf
179 def test_index_pdf
180 get :index, :format => 'pdf'
180 get :index, :format => 'pdf'
181 assert_response :success
181 assert_response :success
182 assert_not_nil assigns(:issues)
182 assert_not_nil assigns(:issues)
183 assert_equal 'application/pdf', @response.content_type
183 assert_equal 'application/pdf', @response.content_type
184
184
185 get :index, :project_id => 1, :format => 'pdf'
185 get :index, :project_id => 1, :format => 'pdf'
186 assert_response :success
186 assert_response :success
187 assert_not_nil assigns(:issues)
187 assert_not_nil assigns(:issues)
188 assert_equal 'application/pdf', @response.content_type
188 assert_equal 'application/pdf', @response.content_type
189
189
190 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
190 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
191 assert_response :success
191 assert_response :success
192 assert_not_nil assigns(:issues)
192 assert_not_nil assigns(:issues)
193 assert_equal 'application/pdf', @response.content_type
193 assert_equal 'application/pdf', @response.content_type
194 end
194 end
195
195
196 def test_index_pdf_with_query_grouped_by_list_custom_field
196 def test_index_pdf_with_query_grouped_by_list_custom_field
197 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
197 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
198 assert_response :success
198 assert_response :success
199 assert_not_nil assigns(:issues)
199 assert_not_nil assigns(:issues)
200 assert_not_nil assigns(:issue_count_by_group)
200 assert_not_nil assigns(:issue_count_by_group)
201 assert_equal 'application/pdf', @response.content_type
201 assert_equal 'application/pdf', @response.content_type
202 end
202 end
203
203
204 def test_index_sort
204 def test_index_sort
205 get :index, :sort => 'tracker,id:desc'
205 get :index, :sort => 'tracker,id:desc'
206 assert_response :success
206 assert_response :success
207
207
208 sort_params = @request.session['issues_index_sort']
208 sort_params = @request.session['issues_index_sort']
209 assert sort_params.is_a?(String)
209 assert sort_params.is_a?(String)
210 assert_equal 'tracker,id:desc', sort_params
210 assert_equal 'tracker,id:desc', sort_params
211
211
212 issues = assigns(:issues)
212 issues = assigns(:issues)
213 assert_not_nil issues
213 assert_not_nil issues
214 assert !issues.empty?
214 assert !issues.empty?
215 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
215 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
216 end
216 end
217
217
218 def test_index_with_columns
218 def test_index_with_columns
219 columns = ['tracker', 'subject', 'assigned_to']
219 columns = ['tracker', 'subject', 'assigned_to']
220 get :index, :set_filter => 1, :query => { 'column_names' => columns}
220 get :index, :set_filter => 1, :query => { 'column_names' => columns}
221 assert_response :success
221 assert_response :success
222
222
223 # query should use specified columns
223 # query should use specified columns
224 query = assigns(:query)
224 query = assigns(:query)
225 assert_kind_of Query, query
225 assert_kind_of Query, query
226 assert_equal columns, query.column_names.map(&:to_s)
226 assert_equal columns, query.column_names.map(&:to_s)
227
227
228 # columns should be stored in session
228 # columns should be stored in session
229 assert_kind_of Hash, session[:query]
229 assert_kind_of Hash, session[:query]
230 assert_kind_of Array, session[:query][:column_names]
230 assert_kind_of Array, session[:query][:column_names]
231 assert_equal columns, session[:query][:column_names].map(&:to_s)
231 assert_equal columns, session[:query][:column_names].map(&:to_s)
232 end
232 end
233
233
234 def test_show_by_anonymous
234 def test_show_by_anonymous
235 get :show, :id => 1
235 get :show, :id => 1
236 assert_response :success
236 assert_response :success
237 assert_template 'show.rhtml'
237 assert_template 'show.rhtml'
238 assert_not_nil assigns(:issue)
238 assert_not_nil assigns(:issue)
239 assert_equal Issue.find(1), assigns(:issue)
239 assert_equal Issue.find(1), assigns(:issue)
240
240
241 # anonymous role is allowed to add a note
241 # anonymous role is allowed to add a note
242 assert_tag :tag => 'form',
242 assert_tag :tag => 'form',
243 :descendant => { :tag => 'fieldset',
243 :descendant => { :tag => 'fieldset',
244 :child => { :tag => 'legend',
244 :child => { :tag => 'legend',
245 :content => /Notes/ } }
245 :content => /Notes/ } }
246 end
246 end
247
247
248 def test_show_by_manager
248 def test_show_by_manager
249 @request.session[:user_id] = 2
249 @request.session[:user_id] = 2
250 get :show, :id => 1
250 get :show, :id => 1
251 assert_response :success
251 assert_response :success
252
252
253 assert_tag :tag => 'form',
253 assert_tag :tag => 'form',
254 :descendant => { :tag => 'fieldset',
254 :descendant => { :tag => 'fieldset',
255 :child => { :tag => 'legend',
255 :child => { :tag => 'legend',
256 :content => /Change properties/ } },
256 :content => /Change properties/ } },
257 :descendant => { :tag => 'fieldset',
257 :descendant => { :tag => 'fieldset',
258 :child => { :tag => 'legend',
258 :child => { :tag => 'legend',
259 :content => /Log time/ } },
259 :content => /Log time/ } },
260 :descendant => { :tag => 'fieldset',
260 :descendant => { :tag => 'fieldset',
261 :child => { :tag => 'legend',
261 :child => { :tag => 'legend',
262 :content => /Notes/ } }
262 :content => /Notes/ } }
263 end
263 end
264
264
265 def test_show_should_deny_anonymous_access_without_permission
265 def test_show_should_deny_anonymous_access_without_permission
266 Role.anonymous.remove_permission!(:view_issues)
266 Role.anonymous.remove_permission!(:view_issues)
267 get :show, :id => 1
267 get :show, :id => 1
268 assert_response :redirect
268 assert_response :redirect
269 end
269 end
270
270
271 def test_show_should_deny_non_member_access_without_permission
271 def test_show_should_deny_non_member_access_without_permission
272 Role.non_member.remove_permission!(:view_issues)
272 Role.non_member.remove_permission!(:view_issues)
273 @request.session[:user_id] = 9
273 @request.session[:user_id] = 9
274 get :show, :id => 1
274 get :show, :id => 1
275 assert_response 403
275 assert_response 403
276 end
276 end
277
277
278 def test_show_should_deny_member_access_without_permission
278 def test_show_should_deny_member_access_without_permission
279 Role.find(1).remove_permission!(:view_issues)
279 Role.find(1).remove_permission!(:view_issues)
280 @request.session[:user_id] = 2
280 @request.session[:user_id] = 2
281 get :show, :id => 1
281 get :show, :id => 1
282 assert_response 403
282 assert_response 403
283 end
283 end
284
284
285 def test_show_should_not_disclose_relations_to_invisible_issues
285 def test_show_should_not_disclose_relations_to_invisible_issues
286 Setting.cross_project_issue_relations = '1'
286 Setting.cross_project_issue_relations = '1'
287 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
287 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
288 # Relation to a private project issue
288 # Relation to a private project issue
289 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
289 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
290
290
291 get :show, :id => 1
291 get :show, :id => 1
292 assert_response :success
292 assert_response :success
293
293
294 assert_tag :div, :attributes => { :id => 'relations' },
294 assert_tag :div, :attributes => { :id => 'relations' },
295 :descendant => { :tag => 'a', :content => /#2$/ }
295 :descendant => { :tag => 'a', :content => /#2$/ }
296 assert_no_tag :div, :attributes => { :id => 'relations' },
296 assert_no_tag :div, :attributes => { :id => 'relations' },
297 :descendant => { :tag => 'a', :content => /#4$/ }
297 :descendant => { :tag => 'a', :content => /#4$/ }
298 end
298 end
299
299
300 def test_show_atom
300 def test_show_atom
301 get :show, :id => 2, :format => 'atom'
301 get :show, :id => 2, :format => 'atom'
302 assert_response :success
302 assert_response :success
303 assert_template 'journals/index.rxml'
303 assert_template 'journals/index.rxml'
304 # Inline image
304 # Inline image
305 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
305 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
306 end
306 end
307
307
308 def test_show_export_to_pdf
308 def test_show_export_to_pdf
309 get :show, :id => 3, :format => 'pdf'
309 get :show, :id => 3, :format => 'pdf'
310 assert_response :success
310 assert_response :success
311 assert_equal 'application/pdf', @response.content_type
311 assert_equal 'application/pdf', @response.content_type
312 assert @response.body.starts_with?('%PDF')
312 assert @response.body.starts_with?('%PDF')
313 assert_not_nil assigns(:issue)
313 assert_not_nil assigns(:issue)
314 end
314 end
315
315
316 def test_get_new
316 def test_get_new
317 @request.session[:user_id] = 2
317 @request.session[:user_id] = 2
318 get :new, :project_id => 1, :tracker_id => 1
318 get :new, :project_id => 1, :tracker_id => 1
319 assert_response :success
319 assert_response :success
320 assert_template 'new'
320 assert_template 'new'
321
321
322 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
322 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
323 :value => 'Default string' }
323 :value => 'Default string' }
324 end
324 end
325
325
326 def test_get_new_without_tracker_id
326 def test_get_new_without_tracker_id
327 @request.session[:user_id] = 2
327 @request.session[:user_id] = 2
328 get :new, :project_id => 1
328 get :new, :project_id => 1
329 assert_response :success
329 assert_response :success
330 assert_template 'new'
330 assert_template 'new'
331
331
332 issue = assigns(:issue)
332 issue = assigns(:issue)
333 assert_not_nil issue
333 assert_not_nil issue
334 assert_equal Project.find(1).trackers.first, issue.tracker
334 assert_equal Project.find(1).trackers.first, issue.tracker
335 end
335 end
336
336
337 def test_get_new_with_no_default_status_should_display_an_error
337 def test_get_new_with_no_default_status_should_display_an_error
338 @request.session[:user_id] = 2
338 @request.session[:user_id] = 2
339 IssueStatus.delete_all
339 IssueStatus.delete_all
340
340
341 get :new, :project_id => 1
341 get :new, :project_id => 1
342 assert_response 500
342 assert_response 500
343 assert_not_nil flash[:error]
343 assert_not_nil flash[:error]
344 assert_tag :tag => 'div', :attributes => { :class => /error/ },
344 assert_tag :tag => 'div', :attributes => { :class => /error/ },
345 :content => /No default issue/
345 :content => /No default issue/
346 end
346 end
347
347
348 def test_get_new_with_no_tracker_should_display_an_error
348 def test_get_new_with_no_tracker_should_display_an_error
349 @request.session[:user_id] = 2
349 @request.session[:user_id] = 2
350 Tracker.delete_all
350 Tracker.delete_all
351
351
352 get :new, :project_id => 1
352 get :new, :project_id => 1
353 assert_response 500
353 assert_response 500
354 assert_not_nil flash[:error]
354 assert_not_nil flash[:error]
355 assert_tag :tag => 'div', :attributes => { :class => /error/ },
355 assert_tag :tag => 'div', :attributes => { :class => /error/ },
356 :content => /No tracker/
356 :content => /No tracker/
357 end
357 end
358
358
359 def test_update_new_form
359 def test_update_new_form
360 @request.session[:user_id] = 2
360 @request.session[:user_id] = 2
361 xhr :post, :new, :project_id => 1,
361 xhr :post, :new, :project_id => 1,
362 :issue => {:tracker_id => 2,
362 :issue => {:tracker_id => 2,
363 :subject => 'This is the test_new issue',
363 :subject => 'This is the test_new issue',
364 :description => 'This is the description',
364 :description => 'This is the description',
365 :priority_id => 5}
365 :priority_id => 5}
366 assert_response :success
366 assert_response :success
367 assert_template 'attributes'
367 assert_template 'attributes'
368
368
369 issue = assigns(:issue)
369 issue = assigns(:issue)
370 assert_kind_of Issue, issue
370 assert_kind_of Issue, issue
371 assert_equal 1, issue.project_id
371 assert_equal 1, issue.project_id
372 assert_equal 2, issue.tracker_id
372 assert_equal 2, issue.tracker_id
373 assert_equal 'This is the test_new issue', issue.subject
373 assert_equal 'This is the test_new issue', issue.subject
374 end
374 end
375
375
376 def test_post_create
376 def test_post_create
377 @request.session[:user_id] = 2
377 @request.session[:user_id] = 2
378 assert_difference 'Issue.count' do
378 assert_difference 'Issue.count' do
379 post :create, :project_id => 1,
379 post :create, :project_id => 1,
380 :issue => {:tracker_id => 3,
380 :issue => {:tracker_id => 3,
381 :status_id => 2,
381 :status_id => 2,
382 :subject => 'This is the test_new issue',
382 :subject => 'This is the test_new issue',
383 :description => 'This is the description',
383 :description => 'This is the description',
384 :priority_id => 5,
384 :priority_id => 5,
385 :estimated_hours => '',
385 :estimated_hours => '',
386 :custom_field_values => {'2' => 'Value for field 2'}}
386 :custom_field_values => {'2' => 'Value for field 2'}}
387 end
387 end
388 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
388 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
389
389
390 issue = Issue.find_by_subject('This is the test_new issue')
390 issue = Issue.find_by_subject('This is the test_new issue')
391 assert_not_nil issue
391 assert_not_nil issue
392 assert_equal 2, issue.author_id
392 assert_equal 2, issue.author_id
393 assert_equal 3, issue.tracker_id
393 assert_equal 3, issue.tracker_id
394 assert_equal 2, issue.status_id
394 assert_equal 2, issue.status_id
395 assert_nil issue.estimated_hours
395 assert_nil issue.estimated_hours
396 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
396 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
397 assert_not_nil v
397 assert_not_nil v
398 assert_equal 'Value for field 2', v.value
398 assert_equal 'Value for field 2', v.value
399 end
399 end
400
400
401 def test_post_create_and_continue
401 def test_post_create_and_continue
402 @request.session[:user_id] = 2
402 @request.session[:user_id] = 2
403 post :create, :project_id => 1,
403 post :create, :project_id => 1,
404 :issue => {:tracker_id => 3,
404 :issue => {:tracker_id => 3,
405 :subject => 'This is first issue',
405 :subject => 'This is first issue',
406 :priority_id => 5},
406 :priority_id => 5},
407 :continue => ''
407 :continue => ''
408 assert_redirected_to :controller => 'issues', :action => 'new', :issue => {:tracker_id => 3}
408 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook',
409 :issue => {:tracker_id => 3}
409 end
410 end
410
411
411 def test_post_create_without_custom_fields_param
412 def test_post_create_without_custom_fields_param
412 @request.session[:user_id] = 2
413 @request.session[:user_id] = 2
413 assert_difference 'Issue.count' do
414 assert_difference 'Issue.count' do
414 post :create, :project_id => 1,
415 post :create, :project_id => 1,
415 :issue => {:tracker_id => 1,
416 :issue => {:tracker_id => 1,
416 :subject => 'This is the test_new issue',
417 :subject => 'This is the test_new issue',
417 :description => 'This is the description',
418 :description => 'This is the description',
418 :priority_id => 5}
419 :priority_id => 5}
419 end
420 end
420 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
421 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
421 end
422 end
422
423
423 def test_post_create_with_required_custom_field_and_without_custom_fields_param
424 def test_post_create_with_required_custom_field_and_without_custom_fields_param
424 field = IssueCustomField.find_by_name('Database')
425 field = IssueCustomField.find_by_name('Database')
425 field.update_attribute(:is_required, true)
426 field.update_attribute(:is_required, true)
426
427
427 @request.session[:user_id] = 2
428 @request.session[:user_id] = 2
428 post :create, :project_id => 1,
429 post :create, :project_id => 1,
429 :issue => {:tracker_id => 1,
430 :issue => {:tracker_id => 1,
430 :subject => 'This is the test_new issue',
431 :subject => 'This is the test_new issue',
431 :description => 'This is the description',
432 :description => 'This is the description',
432 :priority_id => 5}
433 :priority_id => 5}
433 assert_response :success
434 assert_response :success
434 assert_template 'new'
435 assert_template 'new'
435 issue = assigns(:issue)
436 issue = assigns(:issue)
436 assert_not_nil issue
437 assert_not_nil issue
437 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
438 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
438 end
439 end
439
440
440 def test_post_create_with_watchers
441 def test_post_create_with_watchers
441 @request.session[:user_id] = 2
442 @request.session[:user_id] = 2
442 ActionMailer::Base.deliveries.clear
443 ActionMailer::Base.deliveries.clear
443
444
444 assert_difference 'Watcher.count', 2 do
445 assert_difference 'Watcher.count', 2 do
445 post :create, :project_id => 1,
446 post :create, :project_id => 1,
446 :issue => {:tracker_id => 1,
447 :issue => {:tracker_id => 1,
447 :subject => 'This is a new issue with watchers',
448 :subject => 'This is a new issue with watchers',
448 :description => 'This is the description',
449 :description => 'This is the description',
449 :priority_id => 5,
450 :priority_id => 5,
450 :watcher_user_ids => ['2', '3']}
451 :watcher_user_ids => ['2', '3']}
451 end
452 end
452 issue = Issue.find_by_subject('This is a new issue with watchers')
453 issue = Issue.find_by_subject('This is a new issue with watchers')
453 assert_not_nil issue
454 assert_not_nil issue
454 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
455 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
455
456
456 # Watchers added
457 # Watchers added
457 assert_equal [2, 3], issue.watcher_user_ids.sort
458 assert_equal [2, 3], issue.watcher_user_ids.sort
458 assert issue.watched_by?(User.find(3))
459 assert issue.watched_by?(User.find(3))
459 # Watchers notified
460 # Watchers notified
460 mail = ActionMailer::Base.deliveries.last
461 mail = ActionMailer::Base.deliveries.last
461 assert_kind_of TMail::Mail, mail
462 assert_kind_of TMail::Mail, mail
462 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
463 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
463 end
464 end
464
465
465 def test_post_create_subissue
466 def test_post_create_subissue
466 @request.session[:user_id] = 2
467 @request.session[:user_id] = 2
467
468
468 assert_difference 'Issue.count' do
469 assert_difference 'Issue.count' do
469 post :create, :project_id => 1,
470 post :create, :project_id => 1,
470 :issue => {:tracker_id => 1,
471 :issue => {:tracker_id => 1,
471 :subject => 'This is a child issue',
472 :subject => 'This is a child issue',
472 :parent_issue_id => 2}
473 :parent_issue_id => 2}
473 end
474 end
474 issue = Issue.find_by_subject('This is a child issue')
475 issue = Issue.find_by_subject('This is a child issue')
475 assert_not_nil issue
476 assert_not_nil issue
476 assert_equal Issue.find(2), issue.parent
477 assert_equal Issue.find(2), issue.parent
477 end
478 end
478
479
479 def test_post_create_should_send_a_notification
480 def test_post_create_should_send_a_notification
480 ActionMailer::Base.deliveries.clear
481 ActionMailer::Base.deliveries.clear
481 @request.session[:user_id] = 2
482 @request.session[:user_id] = 2
482 assert_difference 'Issue.count' do
483 assert_difference 'Issue.count' do
483 post :create, :project_id => 1,
484 post :create, :project_id => 1,
484 :issue => {:tracker_id => 3,
485 :issue => {:tracker_id => 3,
485 :subject => 'This is the test_new issue',
486 :subject => 'This is the test_new issue',
486 :description => 'This is the description',
487 :description => 'This is the description',
487 :priority_id => 5,
488 :priority_id => 5,
488 :estimated_hours => '',
489 :estimated_hours => '',
489 :custom_field_values => {'2' => 'Value for field 2'}}
490 :custom_field_values => {'2' => 'Value for field 2'}}
490 end
491 end
491 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
492 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
492
493
493 assert_equal 1, ActionMailer::Base.deliveries.size
494 assert_equal 1, ActionMailer::Base.deliveries.size
494 end
495 end
495
496
496 def test_post_create_should_preserve_fields_values_on_validation_failure
497 def test_post_create_should_preserve_fields_values_on_validation_failure
497 @request.session[:user_id] = 2
498 @request.session[:user_id] = 2
498 post :create, :project_id => 1,
499 post :create, :project_id => 1,
499 :issue => {:tracker_id => 1,
500 :issue => {:tracker_id => 1,
500 # empty subject
501 # empty subject
501 :subject => '',
502 :subject => '',
502 :description => 'This is a description',
503 :description => 'This is a description',
503 :priority_id => 6,
504 :priority_id => 6,
504 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
505 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
505 assert_response :success
506 assert_response :success
506 assert_template 'new'
507 assert_template 'new'
507
508
508 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
509 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
509 :content => 'This is a description'
510 :content => 'This is a description'
510 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
511 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
511 :child => { :tag => 'option', :attributes => { :selected => 'selected',
512 :child => { :tag => 'option', :attributes => { :selected => 'selected',
512 :value => '6' },
513 :value => '6' },
513 :content => 'High' }
514 :content => 'High' }
514 # Custom fields
515 # Custom fields
515 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
516 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
516 :child => { :tag => 'option', :attributes => { :selected => 'selected',
517 :child => { :tag => 'option', :attributes => { :selected => 'selected',
517 :value => 'Oracle' },
518 :value => 'Oracle' },
518 :content => 'Oracle' }
519 :content => 'Oracle' }
519 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
520 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
520 :value => 'Value for field 2'}
521 :value => 'Value for field 2'}
521 end
522 end
522
523
523 def test_post_create_should_ignore_non_safe_attributes
524 def test_post_create_should_ignore_non_safe_attributes
524 @request.session[:user_id] = 2
525 @request.session[:user_id] = 2
525 assert_nothing_raised do
526 assert_nothing_raised do
526 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
527 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
527 end
528 end
528 end
529 end
529
530
530 context "without workflow privilege" do
531 context "without workflow privilege" do
531 setup do
532 setup do
532 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
533 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
533 Role.anonymous.add_permission! :add_issues
534 Role.anonymous.add_permission! :add_issues
534 end
535 end
535
536
536 context "#new" do
537 context "#new" do
537 should "propose default status only" do
538 should "propose default status only" do
538 get :new, :project_id => 1
539 get :new, :project_id => 1
539 assert_response :success
540 assert_response :success
540 assert_template 'new'
541 assert_template 'new'
541 assert_tag :tag => 'select',
542 assert_tag :tag => 'select',
542 :attributes => {:name => 'issue[status_id]'},
543 :attributes => {:name => 'issue[status_id]'},
543 :children => {:count => 1},
544 :children => {:count => 1},
544 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
545 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
545 end
546 end
546
547
547 should "accept default status" do
548 should "accept default status" do
548 assert_difference 'Issue.count' do
549 assert_difference 'Issue.count' do
549 post :create, :project_id => 1,
550 post :create, :project_id => 1,
550 :issue => {:tracker_id => 1,
551 :issue => {:tracker_id => 1,
551 :subject => 'This is an issue',
552 :subject => 'This is an issue',
552 :status_id => 1}
553 :status_id => 1}
553 end
554 end
554 issue = Issue.last(:order => 'id')
555 issue = Issue.last(:order => 'id')
555 assert_equal IssueStatus.default, issue.status
556 assert_equal IssueStatus.default, issue.status
556 end
557 end
557
558
558 should "ignore unauthorized status" do
559 should "ignore unauthorized status" do
559 assert_difference 'Issue.count' do
560 assert_difference 'Issue.count' do
560 post :create, :project_id => 1,
561 post :create, :project_id => 1,
561 :issue => {:tracker_id => 1,
562 :issue => {:tracker_id => 1,
562 :subject => 'This is an issue',
563 :subject => 'This is an issue',
563 :status_id => 3}
564 :status_id => 3}
564 end
565 end
565 issue = Issue.last(:order => 'id')
566 issue = Issue.last(:order => 'id')
566 assert_equal IssueStatus.default, issue.status
567 assert_equal IssueStatus.default, issue.status
567 end
568 end
568 end
569 end
569 end
570 end
570
571
571 def test_copy_issue
572 def test_copy_issue
572 @request.session[:user_id] = 2
573 @request.session[:user_id] = 2
573 get :new, :project_id => 1, :copy_from => 1
574 get :new, :project_id => 1, :copy_from => 1
574 assert_template 'new'
575 assert_template 'new'
575 assert_not_nil assigns(:issue)
576 assert_not_nil assigns(:issue)
576 orig = Issue.find(1)
577 orig = Issue.find(1)
577 assert_equal orig.subject, assigns(:issue).subject
578 assert_equal orig.subject, assigns(:issue).subject
578 end
579 end
579
580
580 def test_get_edit
581 def test_get_edit
581 @request.session[:user_id] = 2
582 @request.session[:user_id] = 2
582 get :edit, :id => 1
583 get :edit, :id => 1
583 assert_response :success
584 assert_response :success
584 assert_template 'edit'
585 assert_template 'edit'
585 assert_not_nil assigns(:issue)
586 assert_not_nil assigns(:issue)
586 assert_equal Issue.find(1), assigns(:issue)
587 assert_equal Issue.find(1), assigns(:issue)
587 end
588 end
588
589
589 def test_get_edit_with_params
590 def test_get_edit_with_params
590 @request.session[:user_id] = 2
591 @request.session[:user_id] = 2
591 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }
592 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }
592 assert_response :success
593 assert_response :success
593 assert_template 'edit'
594 assert_template 'edit'
594
595
595 issue = assigns(:issue)
596 issue = assigns(:issue)
596 assert_not_nil issue
597 assert_not_nil issue
597
598
598 assert_equal 5, issue.status_id
599 assert_equal 5, issue.status_id
599 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
600 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
600 :child => { :tag => 'option',
601 :child => { :tag => 'option',
601 :content => 'Closed',
602 :content => 'Closed',
602 :attributes => { :selected => 'selected' } }
603 :attributes => { :selected => 'selected' } }
603
604
604 assert_equal 7, issue.priority_id
605 assert_equal 7, issue.priority_id
605 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
606 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
606 :child => { :tag => 'option',
607 :child => { :tag => 'option',
607 :content => 'Urgent',
608 :content => 'Urgent',
608 :attributes => { :selected => 'selected' } }
609 :attributes => { :selected => 'selected' } }
609 end
610 end
610
611
611 def test_update_edit_form
612 def test_update_edit_form
612 @request.session[:user_id] = 2
613 @request.session[:user_id] = 2
613 xhr :post, :new, :project_id => 1,
614 xhr :post, :new, :project_id => 1,
614 :id => 1,
615 :id => 1,
615 :issue => {:tracker_id => 2,
616 :issue => {:tracker_id => 2,
616 :subject => 'This is the test_new issue',
617 :subject => 'This is the test_new issue',
617 :description => 'This is the description',
618 :description => 'This is the description',
618 :priority_id => 5}
619 :priority_id => 5}
619 assert_response :success
620 assert_response :success
620 assert_template 'attributes'
621 assert_template 'attributes'
621
622
622 issue = assigns(:issue)
623 issue = assigns(:issue)
623 assert_kind_of Issue, issue
624 assert_kind_of Issue, issue
624 assert_equal 1, issue.id
625 assert_equal 1, issue.id
625 assert_equal 1, issue.project_id
626 assert_equal 1, issue.project_id
626 assert_equal 2, issue.tracker_id
627 assert_equal 2, issue.tracker_id
627 assert_equal 'This is the test_new issue', issue.subject
628 assert_equal 'This is the test_new issue', issue.subject
628 end
629 end
629
630
630 def test_update_using_invalid_http_verbs
631 def test_update_using_invalid_http_verbs
631 @request.session[:user_id] = 2
632 @request.session[:user_id] = 2
632 subject = 'Updated by an invalid http verb'
633 subject = 'Updated by an invalid http verb'
633
634
634 get :update, :id => 1, :issue => {:subject => subject}
635 get :update, :id => 1, :issue => {:subject => subject}
635 assert_not_equal subject, Issue.find(1).subject
636 assert_not_equal subject, Issue.find(1).subject
636
637
637 post :update, :id => 1, :issue => {:subject => subject}
638 post :update, :id => 1, :issue => {:subject => subject}
638 assert_not_equal subject, Issue.find(1).subject
639 assert_not_equal subject, Issue.find(1).subject
639
640
640 delete :update, :id => 1, :issue => {:subject => subject}
641 delete :update, :id => 1, :issue => {:subject => subject}
641 assert_not_equal subject, Issue.find(1).subject
642 assert_not_equal subject, Issue.find(1).subject
642 end
643 end
643
644
644 def test_put_update_without_custom_fields_param
645 def test_put_update_without_custom_fields_param
645 @request.session[:user_id] = 2
646 @request.session[:user_id] = 2
646 ActionMailer::Base.deliveries.clear
647 ActionMailer::Base.deliveries.clear
647
648
648 issue = Issue.find(1)
649 issue = Issue.find(1)
649 assert_equal '125', issue.custom_value_for(2).value
650 assert_equal '125', issue.custom_value_for(2).value
650 old_subject = issue.subject
651 old_subject = issue.subject
651 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
652 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
652
653
653 assert_difference('Journal.count') do
654 assert_difference('Journal.count') do
654 assert_difference('JournalDetail.count', 2) do
655 assert_difference('JournalDetail.count', 2) do
655 put :update, :id => 1, :issue => {:subject => new_subject,
656 put :update, :id => 1, :issue => {:subject => new_subject,
656 :priority_id => '6',
657 :priority_id => '6',
657 :category_id => '1' # no change
658 :category_id => '1' # no change
658 }
659 }
659 end
660 end
660 end
661 end
661 assert_redirected_to :action => 'show', :id => '1'
662 assert_redirected_to :action => 'show', :id => '1'
662 issue.reload
663 issue.reload
663 assert_equal new_subject, issue.subject
664 assert_equal new_subject, issue.subject
664 # Make sure custom fields were not cleared
665 # Make sure custom fields were not cleared
665 assert_equal '125', issue.custom_value_for(2).value
666 assert_equal '125', issue.custom_value_for(2).value
666
667
667 mail = ActionMailer::Base.deliveries.last
668 mail = ActionMailer::Base.deliveries.last
668 assert_kind_of TMail::Mail, mail
669 assert_kind_of TMail::Mail, mail
669 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
670 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
670 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
671 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
671 end
672 end
672
673
673 def test_put_update_with_custom_field_change
674 def test_put_update_with_custom_field_change
674 @request.session[:user_id] = 2
675 @request.session[:user_id] = 2
675 issue = Issue.find(1)
676 issue = Issue.find(1)
676 assert_equal '125', issue.custom_value_for(2).value
677 assert_equal '125', issue.custom_value_for(2).value
677
678
678 assert_difference('Journal.count') do
679 assert_difference('Journal.count') do
679 assert_difference('JournalDetail.count', 3) do
680 assert_difference('JournalDetail.count', 3) do
680 put :update, :id => 1, :issue => {:subject => 'Custom field change',
681 put :update, :id => 1, :issue => {:subject => 'Custom field change',
681 :priority_id => '6',
682 :priority_id => '6',
682 :category_id => '1', # no change
683 :category_id => '1', # no change
683 :custom_field_values => { '2' => 'New custom value' }
684 :custom_field_values => { '2' => 'New custom value' }
684 }
685 }
685 end
686 end
686 end
687 end
687 assert_redirected_to :action => 'show', :id => '1'
688 assert_redirected_to :action => 'show', :id => '1'
688 issue.reload
689 issue.reload
689 assert_equal 'New custom value', issue.custom_value_for(2).value
690 assert_equal 'New custom value', issue.custom_value_for(2).value
690
691
691 mail = ActionMailer::Base.deliveries.last
692 mail = ActionMailer::Base.deliveries.last
692 assert_kind_of TMail::Mail, mail
693 assert_kind_of TMail::Mail, mail
693 assert mail.body.include?("Searchable field changed from 125 to New custom value")
694 assert mail.body.include?("Searchable field changed from 125 to New custom value")
694 end
695 end
695
696
696 def test_put_update_with_status_and_assignee_change
697 def test_put_update_with_status_and_assignee_change
697 issue = Issue.find(1)
698 issue = Issue.find(1)
698 assert_equal 1, issue.status_id
699 assert_equal 1, issue.status_id
699 @request.session[:user_id] = 2
700 @request.session[:user_id] = 2
700 assert_difference('TimeEntry.count', 0) do
701 assert_difference('TimeEntry.count', 0) do
701 put :update,
702 put :update,
702 :id => 1,
703 :id => 1,
703 :issue => { :status_id => 2, :assigned_to_id => 3 },
704 :issue => { :status_id => 2, :assigned_to_id => 3 },
704 :notes => 'Assigned to dlopper',
705 :notes => 'Assigned to dlopper',
705 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
706 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
706 end
707 end
707 assert_redirected_to :action => 'show', :id => '1'
708 assert_redirected_to :action => 'show', :id => '1'
708 issue.reload
709 issue.reload
709 assert_equal 2, issue.status_id
710 assert_equal 2, issue.status_id
710 j = Journal.find(:first, :order => 'id DESC')
711 j = Journal.find(:first, :order => 'id DESC')
711 assert_equal 'Assigned to dlopper', j.notes
712 assert_equal 'Assigned to dlopper', j.notes
712 assert_equal 2, j.details.size
713 assert_equal 2, j.details.size
713
714
714 mail = ActionMailer::Base.deliveries.last
715 mail = ActionMailer::Base.deliveries.last
715 assert mail.body.include?("Status changed from New to Assigned")
716 assert mail.body.include?("Status changed from New to Assigned")
716 # subject should contain the new status
717 # subject should contain the new status
717 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
718 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
718 end
719 end
719
720
720 def test_put_update_with_note_only
721 def test_put_update_with_note_only
721 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
722 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
722 # anonymous user
723 # anonymous user
723 put :update,
724 put :update,
724 :id => 1,
725 :id => 1,
725 :notes => notes
726 :notes => notes
726 assert_redirected_to :action => 'show', :id => '1'
727 assert_redirected_to :action => 'show', :id => '1'
727 j = Journal.find(:first, :order => 'id DESC')
728 j = Journal.find(:first, :order => 'id DESC')
728 assert_equal notes, j.notes
729 assert_equal notes, j.notes
729 assert_equal 0, j.details.size
730 assert_equal 0, j.details.size
730 assert_equal User.anonymous, j.user
731 assert_equal User.anonymous, j.user
731
732
732 mail = ActionMailer::Base.deliveries.last
733 mail = ActionMailer::Base.deliveries.last
733 assert mail.body.include?(notes)
734 assert mail.body.include?(notes)
734 end
735 end
735
736
736 def test_put_update_with_note_and_spent_time
737 def test_put_update_with_note_and_spent_time
737 @request.session[:user_id] = 2
738 @request.session[:user_id] = 2
738 spent_hours_before = Issue.find(1).spent_hours
739 spent_hours_before = Issue.find(1).spent_hours
739 assert_difference('TimeEntry.count') do
740 assert_difference('TimeEntry.count') do
740 put :update,
741 put :update,
741 :id => 1,
742 :id => 1,
742 :notes => '2.5 hours added',
743 :notes => '2.5 hours added',
743 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
744 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
744 end
745 end
745 assert_redirected_to :action => 'show', :id => '1'
746 assert_redirected_to :action => 'show', :id => '1'
746
747
747 issue = Issue.find(1)
748 issue = Issue.find(1)
748
749
749 j = Journal.find(:first, :order => 'id DESC')
750 j = Journal.find(:first, :order => 'id DESC')
750 assert_equal '2.5 hours added', j.notes
751 assert_equal '2.5 hours added', j.notes
751 assert_equal 0, j.details.size
752 assert_equal 0, j.details.size
752
753
753 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
754 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
754 assert_not_nil t
755 assert_not_nil t
755 assert_equal 2.5, t.hours
756 assert_equal 2.5, t.hours
756 assert_equal spent_hours_before + 2.5, issue.spent_hours
757 assert_equal spent_hours_before + 2.5, issue.spent_hours
757 end
758 end
758
759
759 def test_put_update_with_attachment_only
760 def test_put_update_with_attachment_only
760 set_tmp_attachments_directory
761 set_tmp_attachments_directory
761
762
762 # Delete all fixtured journals, a race condition can occur causing the wrong
763 # Delete all fixtured journals, a race condition can occur causing the wrong
763 # journal to get fetched in the next find.
764 # journal to get fetched in the next find.
764 Journal.delete_all
765 Journal.delete_all
765
766
766 # anonymous user
767 # anonymous user
767 put :update,
768 put :update,
768 :id => 1,
769 :id => 1,
769 :notes => '',
770 :notes => '',
770 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
771 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
771 assert_redirected_to :action => 'show', :id => '1'
772 assert_redirected_to :action => 'show', :id => '1'
772 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
773 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
773 assert j.notes.blank?
774 assert j.notes.blank?
774 assert_equal 1, j.details.size
775 assert_equal 1, j.details.size
775 assert_equal 'testfile.txt', j.details.first.value
776 assert_equal 'testfile.txt', j.details.first.value
776 assert_equal User.anonymous, j.user
777 assert_equal User.anonymous, j.user
777
778
778 mail = ActionMailer::Base.deliveries.last
779 mail = ActionMailer::Base.deliveries.last
779 assert mail.body.include?('testfile.txt')
780 assert mail.body.include?('testfile.txt')
780 end
781 end
781
782
782 def test_put_update_with_attachment_that_fails_to_save
783 def test_put_update_with_attachment_that_fails_to_save
783 set_tmp_attachments_directory
784 set_tmp_attachments_directory
784
785
785 # Delete all fixtured journals, a race condition can occur causing the wrong
786 # Delete all fixtured journals, a race condition can occur causing the wrong
786 # journal to get fetched in the next find.
787 # journal to get fetched in the next find.
787 Journal.delete_all
788 Journal.delete_all
788
789
789 # Mock out the unsaved attachment
790 # Mock out the unsaved attachment
790 Attachment.any_instance.stubs(:create).returns(Attachment.new)
791 Attachment.any_instance.stubs(:create).returns(Attachment.new)
791
792
792 # anonymous user
793 # anonymous user
793 put :update,
794 put :update,
794 :id => 1,
795 :id => 1,
795 :notes => '',
796 :notes => '',
796 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
797 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
797 assert_redirected_to :action => 'show', :id => '1'
798 assert_redirected_to :action => 'show', :id => '1'
798 assert_equal '1 file(s) could not be saved.', flash[:warning]
799 assert_equal '1 file(s) could not be saved.', flash[:warning]
799
800
800 end if Object.const_defined?(:Mocha)
801 end if Object.const_defined?(:Mocha)
801
802
802 def test_put_update_with_no_change
803 def test_put_update_with_no_change
803 issue = Issue.find(1)
804 issue = Issue.find(1)
804 issue.journals.clear
805 issue.journals.clear
805 ActionMailer::Base.deliveries.clear
806 ActionMailer::Base.deliveries.clear
806
807
807 put :update,
808 put :update,
808 :id => 1,
809 :id => 1,
809 :notes => ''
810 :notes => ''
810 assert_redirected_to :action => 'show', :id => '1'
811 assert_redirected_to :action => 'show', :id => '1'
811
812
812 issue.reload
813 issue.reload
813 assert issue.journals.empty?
814 assert issue.journals.empty?
814 # No email should be sent
815 # No email should be sent
815 assert ActionMailer::Base.deliveries.empty?
816 assert ActionMailer::Base.deliveries.empty?
816 end
817 end
817
818
818 def test_put_update_should_send_a_notification
819 def test_put_update_should_send_a_notification
819 @request.session[:user_id] = 2
820 @request.session[:user_id] = 2
820 ActionMailer::Base.deliveries.clear
821 ActionMailer::Base.deliveries.clear
821 issue = Issue.find(1)
822 issue = Issue.find(1)
822 old_subject = issue.subject
823 old_subject = issue.subject
823 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
824 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
824
825
825 put :update, :id => 1, :issue => {:subject => new_subject,
826 put :update, :id => 1, :issue => {:subject => new_subject,
826 :priority_id => '6',
827 :priority_id => '6',
827 :category_id => '1' # no change
828 :category_id => '1' # no change
828 }
829 }
829 assert_equal 1, ActionMailer::Base.deliveries.size
830 assert_equal 1, ActionMailer::Base.deliveries.size
830 end
831 end
831
832
832 def test_put_update_with_invalid_spent_time
833 def test_put_update_with_invalid_spent_time
833 @request.session[:user_id] = 2
834 @request.session[:user_id] = 2
834 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
835 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
835
836
836 assert_no_difference('Journal.count') do
837 assert_no_difference('Journal.count') do
837 put :update,
838 put :update,
838 :id => 1,
839 :id => 1,
839 :notes => notes,
840 :notes => notes,
840 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
841 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
841 end
842 end
842 assert_response :success
843 assert_response :success
843 assert_template 'edit'
844 assert_template 'edit'
844
845
845 assert_tag :textarea, :attributes => { :name => 'notes' },
846 assert_tag :textarea, :attributes => { :name => 'notes' },
846 :content => notes
847 :content => notes
847 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
848 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
848 end
849 end
849
850
850 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
851 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
851 issue = Issue.find(2)
852 issue = Issue.find(2)
852 @request.session[:user_id] = 2
853 @request.session[:user_id] = 2
853
854
854 put :update,
855 put :update,
855 :id => issue.id,
856 :id => issue.id,
856 :issue => {
857 :issue => {
857 :fixed_version_id => 4
858 :fixed_version_id => 4
858 }
859 }
859
860
860 assert_response :redirect
861 assert_response :redirect
861 issue.reload
862 issue.reload
862 assert_equal 4, issue.fixed_version_id
863 assert_equal 4, issue.fixed_version_id
863 assert_not_equal issue.project_id, issue.fixed_version.project_id
864 assert_not_equal issue.project_id, issue.fixed_version.project_id
864 end
865 end
865
866
866 def test_put_update_should_redirect_back_using_the_back_url_parameter
867 def test_put_update_should_redirect_back_using_the_back_url_parameter
867 issue = Issue.find(2)
868 issue = Issue.find(2)
868 @request.session[:user_id] = 2
869 @request.session[:user_id] = 2
869
870
870 put :update,
871 put :update,
871 :id => issue.id,
872 :id => issue.id,
872 :issue => {
873 :issue => {
873 :fixed_version_id => 4
874 :fixed_version_id => 4
874 },
875 },
875 :back_url => '/issues'
876 :back_url => '/issues'
876
877
877 assert_response :redirect
878 assert_response :redirect
878 assert_redirected_to '/issues'
879 assert_redirected_to '/issues'
879 end
880 end
880
881
881 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
882 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
882 issue = Issue.find(2)
883 issue = Issue.find(2)
883 @request.session[:user_id] = 2
884 @request.session[:user_id] = 2
884
885
885 put :update,
886 put :update,
886 :id => issue.id,
887 :id => issue.id,
887 :issue => {
888 :issue => {
888 :fixed_version_id => 4
889 :fixed_version_id => 4
889 },
890 },
890 :back_url => 'http://google.com'
891 :back_url => 'http://google.com'
891
892
892 assert_response :redirect
893 assert_response :redirect
893 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
894 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
894 end
895 end
895
896
896 def test_get_bulk_edit
897 def test_get_bulk_edit
897 @request.session[:user_id] = 2
898 @request.session[:user_id] = 2
898 get :bulk_edit, :ids => [1, 2]
899 get :bulk_edit, :ids => [1, 2]
899 assert_response :success
900 assert_response :success
900 assert_template 'bulk_edit'
901 assert_template 'bulk_edit'
901
902
902 # Project specific custom field, date type
903 # Project specific custom field, date type
903 field = CustomField.find(9)
904 field = CustomField.find(9)
904 assert !field.is_for_all?
905 assert !field.is_for_all?
905 assert_equal 'date', field.field_format
906 assert_equal 'date', field.field_format
906 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
907 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
907
908
908 # System wide custom field
909 # System wide custom field
909 assert CustomField.find(1).is_for_all?
910 assert CustomField.find(1).is_for_all?
910 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
911 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
911 end
912 end
912
913
913 def test_bulk_update
914 def test_bulk_update
914 @request.session[:user_id] = 2
915 @request.session[:user_id] = 2
915 # update issues priority
916 # update issues priority
916 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
917 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
917 :issue => {:priority_id => 7,
918 :issue => {:priority_id => 7,
918 :assigned_to_id => '',
919 :assigned_to_id => '',
919 :custom_field_values => {'2' => ''}}
920 :custom_field_values => {'2' => ''}}
920
921
921 assert_response 302
922 assert_response 302
922 # check that the issues were updated
923 # check that the issues were updated
923 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
924 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
924
925
925 issue = Issue.find(1)
926 issue = Issue.find(1)
926 journal = issue.journals.find(:first, :order => 'created_on DESC')
927 journal = issue.journals.find(:first, :order => 'created_on DESC')
927 assert_equal '125', issue.custom_value_for(2).value
928 assert_equal '125', issue.custom_value_for(2).value
928 assert_equal 'Bulk editing', journal.notes
929 assert_equal 'Bulk editing', journal.notes
929 assert_equal 1, journal.details.size
930 assert_equal 1, journal.details.size
930 end
931 end
931
932
932 def test_bullk_update_should_send_a_notification
933 def test_bullk_update_should_send_a_notification
933 @request.session[:user_id] = 2
934 @request.session[:user_id] = 2
934 ActionMailer::Base.deliveries.clear
935 ActionMailer::Base.deliveries.clear
935 post(:bulk_update,
936 post(:bulk_update,
936 {
937 {
937 :ids => [1, 2],
938 :ids => [1, 2],
938 :notes => 'Bulk editing',
939 :notes => 'Bulk editing',
939 :issue => {
940 :issue => {
940 :priority_id => 7,
941 :priority_id => 7,
941 :assigned_to_id => '',
942 :assigned_to_id => '',
942 :custom_field_values => {'2' => ''}
943 :custom_field_values => {'2' => ''}
943 }
944 }
944 })
945 })
945
946
946 assert_response 302
947 assert_response 302
947 assert_equal 2, ActionMailer::Base.deliveries.size
948 assert_equal 2, ActionMailer::Base.deliveries.size
948 end
949 end
949
950
950 def test_bulk_update_status
951 def test_bulk_update_status
951 @request.session[:user_id] = 2
952 @request.session[:user_id] = 2
952 # update issues priority
953 # update issues priority
953 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
954 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
954 :issue => {:priority_id => '',
955 :issue => {:priority_id => '',
955 :assigned_to_id => '',
956 :assigned_to_id => '',
956 :status_id => '5'}
957 :status_id => '5'}
957
958
958 assert_response 302
959 assert_response 302
959 issue = Issue.find(1)
960 issue = Issue.find(1)
960 assert issue.closed?
961 assert issue.closed?
961 end
962 end
962
963
963 def test_bulk_update_custom_field
964 def test_bulk_update_custom_field
964 @request.session[:user_id] = 2
965 @request.session[:user_id] = 2
965 # update issues priority
966 # update issues priority
966 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
967 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
967 :issue => {:priority_id => '',
968 :issue => {:priority_id => '',
968 :assigned_to_id => '',
969 :assigned_to_id => '',
969 :custom_field_values => {'2' => '777'}}
970 :custom_field_values => {'2' => '777'}}
970
971
971 assert_response 302
972 assert_response 302
972
973
973 issue = Issue.find(1)
974 issue = Issue.find(1)
974 journal = issue.journals.find(:first, :order => 'created_on DESC')
975 journal = issue.journals.find(:first, :order => 'created_on DESC')
975 assert_equal '777', issue.custom_value_for(2).value
976 assert_equal '777', issue.custom_value_for(2).value
976 assert_equal 1, journal.details.size
977 assert_equal 1, journal.details.size
977 assert_equal '125', journal.details.first.old_value
978 assert_equal '125', journal.details.first.old_value
978 assert_equal '777', journal.details.first.value
979 assert_equal '777', journal.details.first.value
979 end
980 end
980
981
981 def test_bulk_update_unassign
982 def test_bulk_update_unassign
982 assert_not_nil Issue.find(2).assigned_to
983 assert_not_nil Issue.find(2).assigned_to
983 @request.session[:user_id] = 2
984 @request.session[:user_id] = 2
984 # unassign issues
985 # unassign issues
985 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
986 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
986 assert_response 302
987 assert_response 302
987 # check that the issues were updated
988 # check that the issues were updated
988 assert_nil Issue.find(2).assigned_to
989 assert_nil Issue.find(2).assigned_to
989 end
990 end
990
991
991 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
992 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
992 @request.session[:user_id] = 2
993 @request.session[:user_id] = 2
993
994
994 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
995 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
995
996
996 assert_response :redirect
997 assert_response :redirect
997 issues = Issue.find([1,2])
998 issues = Issue.find([1,2])
998 issues.each do |issue|
999 issues.each do |issue|
999 assert_equal 4, issue.fixed_version_id
1000 assert_equal 4, issue.fixed_version_id
1000 assert_not_equal issue.project_id, issue.fixed_version.project_id
1001 assert_not_equal issue.project_id, issue.fixed_version.project_id
1001 end
1002 end
1002 end
1003 end
1003
1004
1004 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1005 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1005 @request.session[:user_id] = 2
1006 @request.session[:user_id] = 2
1006 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1007 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1007
1008
1008 assert_response :redirect
1009 assert_response :redirect
1009 assert_redirected_to '/issues'
1010 assert_redirected_to '/issues'
1010 end
1011 end
1011
1012
1012 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1013 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1013 @request.session[:user_id] = 2
1014 @request.session[:user_id] = 2
1014 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1015 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1015
1016
1016 assert_response :redirect
1017 assert_response :redirect
1017 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1018 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1018 end
1019 end
1019
1020
1020 def test_destroy_issue_with_no_time_entries
1021 def test_destroy_issue_with_no_time_entries
1021 assert_nil TimeEntry.find_by_issue_id(2)
1022 assert_nil TimeEntry.find_by_issue_id(2)
1022 @request.session[:user_id] = 2
1023 @request.session[:user_id] = 2
1023 post :destroy, :id => 2
1024 post :destroy, :id => 2
1024 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1025 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1025 assert_nil Issue.find_by_id(2)
1026 assert_nil Issue.find_by_id(2)
1026 end
1027 end
1027
1028
1028 def test_destroy_issues_with_time_entries
1029 def test_destroy_issues_with_time_entries
1029 @request.session[:user_id] = 2
1030 @request.session[:user_id] = 2
1030 post :destroy, :ids => [1, 3]
1031 post :destroy, :ids => [1, 3]
1031 assert_response :success
1032 assert_response :success
1032 assert_template 'destroy'
1033 assert_template 'destroy'
1033 assert_not_nil assigns(:hours)
1034 assert_not_nil assigns(:hours)
1034 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1035 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1035 end
1036 end
1036
1037
1037 def test_destroy_issues_and_destroy_time_entries
1038 def test_destroy_issues_and_destroy_time_entries
1038 @request.session[:user_id] = 2
1039 @request.session[:user_id] = 2
1039 post :destroy, :ids => [1, 3], :todo => 'destroy'
1040 post :destroy, :ids => [1, 3], :todo => 'destroy'
1040 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1041 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1041 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1042 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1042 assert_nil TimeEntry.find_by_id([1, 2])
1043 assert_nil TimeEntry.find_by_id([1, 2])
1043 end
1044 end
1044
1045
1045 def test_destroy_issues_and_assign_time_entries_to_project
1046 def test_destroy_issues_and_assign_time_entries_to_project
1046 @request.session[:user_id] = 2
1047 @request.session[:user_id] = 2
1047 post :destroy, :ids => [1, 3], :todo => 'nullify'
1048 post :destroy, :ids => [1, 3], :todo => 'nullify'
1048 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1049 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1049 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1050 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1050 assert_nil TimeEntry.find(1).issue_id
1051 assert_nil TimeEntry.find(1).issue_id
1051 assert_nil TimeEntry.find(2).issue_id
1052 assert_nil TimeEntry.find(2).issue_id
1052 end
1053 end
1053
1054
1054 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1055 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1055 @request.session[:user_id] = 2
1056 @request.session[:user_id] = 2
1056 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1057 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1057 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1058 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1058 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1059 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1059 assert_equal 2, TimeEntry.find(1).issue_id
1060 assert_equal 2, TimeEntry.find(1).issue_id
1060 assert_equal 2, TimeEntry.find(2).issue_id
1061 assert_equal 2, TimeEntry.find(2).issue_id
1061 end
1062 end
1062
1063
1063 def test_default_search_scope
1064 def test_default_search_scope
1064 get :index
1065 get :index
1065 assert_tag :div, :attributes => {:id => 'quick-search'},
1066 assert_tag :div, :attributes => {:id => 'quick-search'},
1066 :child => {:tag => 'form',
1067 :child => {:tag => 'form',
1067 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1068 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1068 end
1069 end
1069 end
1070 end
General Comments 0
You need to be logged in to leave comments. Login now