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