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