##// END OF EJS Templates
Changed IssuesController#destroy to DELETE only....
Jean-Philippe Lang -
r8030:52a7fa6176c8
parent child
Show More
@@ -1,341 +1,338
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class IssuesController < ApplicationController
18 class IssuesController < ApplicationController
19 menu_item :new_issue, :only => [:new, :create]
19 menu_item :new_issue, :only => [:new, :create]
20 default_search_scope :issues
20 default_search_scope :issues
21
21
22 before_filter :find_issue, :only => [:show, :edit, :update]
22 before_filter :find_issue, :only => [:show, :edit, :update]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy]
23 before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy]
24 before_filter :check_project_uniqueness, :only => [:move, :perform_move]
24 before_filter :check_project_uniqueness, :only => [:move, :perform_move]
25 before_filter :find_project, :only => [:new, :create]
25 before_filter :find_project, :only => [:new, :create]
26 before_filter :authorize, :except => [:index]
26 before_filter :authorize, :except => [:index]
27 before_filter :find_optional_project, :only => [:index]
27 before_filter :find_optional_project, :only => [:index]
28 before_filter :check_for_default_issue_status, :only => [:new, :create]
28 before_filter :check_for_default_issue_status, :only => [:new, :create]
29 before_filter :build_new_issue_from_params, :only => [:new, :create]
29 before_filter :build_new_issue_from_params, :only => [:new, :create]
30 accept_rss_auth :index, :show
30 accept_rss_auth :index, :show
31 accept_api_auth :index, :show, :create, :update, :destroy
31 accept_api_auth :index, :show, :create, :update, :destroy
32
32
33 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
33 rescue_from Query::StatementInvalid, :with => :query_statement_invalid
34
34
35 helper :journals
35 helper :journals
36 helper :projects
36 helper :projects
37 include ProjectsHelper
37 include ProjectsHelper
38 helper :custom_fields
38 helper :custom_fields
39 include CustomFieldsHelper
39 include CustomFieldsHelper
40 helper :issue_relations
40 helper :issue_relations
41 include IssueRelationsHelper
41 include IssueRelationsHelper
42 helper :watchers
42 helper :watchers
43 include WatchersHelper
43 include WatchersHelper
44 helper :attachments
44 helper :attachments
45 include AttachmentsHelper
45 include AttachmentsHelper
46 helper :queries
46 helper :queries
47 include QueriesHelper
47 include QueriesHelper
48 helper :repositories
48 helper :repositories
49 include RepositoriesHelper
49 include RepositoriesHelper
50 helper :sort
50 helper :sort
51 include SortHelper
51 include SortHelper
52 include IssuesHelper
52 include IssuesHelper
53 helper :timelog
53 helper :timelog
54 helper :gantt
54 helper :gantt
55 include Redmine::Export::PDF
55 include Redmine::Export::PDF
56
56
57 verify :method => [:post, :delete],
58 :only => :destroy,
59 :render => { :nothing => true, :status => :method_not_allowed }
60
61 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
57 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
62 verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed }
58 verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed }
63 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
59 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
64
60
65 def index
61 def index
66 retrieve_query
62 retrieve_query
67 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
63 sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)
68 sort_update(@query.sortable_columns)
64 sort_update(@query.sortable_columns)
69
65
70 if @query.valid?
66 if @query.valid?
71 case params[:format]
67 case params[:format]
72 when 'csv', 'pdf'
68 when 'csv', 'pdf'
73 @limit = Setting.issues_export_limit.to_i
69 @limit = Setting.issues_export_limit.to_i
74 when 'atom'
70 when 'atom'
75 @limit = Setting.feeds_limit.to_i
71 @limit = Setting.feeds_limit.to_i
76 when 'xml', 'json'
72 when 'xml', 'json'
77 @offset, @limit = api_offset_and_limit
73 @offset, @limit = api_offset_and_limit
78 else
74 else
79 @limit = per_page_option
75 @limit = per_page_option
80 end
76 end
81
77
82 @issue_count = @query.issue_count
78 @issue_count = @query.issue_count
83 @issue_pages = Paginator.new self, @issue_count, @limit, params['page']
79 @issue_pages = Paginator.new self, @issue_count, @limit, params['page']
84 @offset ||= @issue_pages.current.offset
80 @offset ||= @issue_pages.current.offset
85 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
81 @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
86 :order => sort_clause,
82 :order => sort_clause,
87 :offset => @offset,
83 :offset => @offset,
88 :limit => @limit)
84 :limit => @limit)
89 @issue_count_by_group = @query.issue_count_by_group
85 @issue_count_by_group = @query.issue_count_by_group
90
86
91 respond_to do |format|
87 respond_to do |format|
92 format.html { render :template => 'issues/index', :layout => !request.xhr? }
88 format.html { render :template => 'issues/index', :layout => !request.xhr? }
93 format.api {
89 format.api {
94 Issue.load_relations(@issues) if include_in_api_response?('relations')
90 Issue.load_relations(@issues) if include_in_api_response?('relations')
95 }
91 }
96 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
92 format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
97 format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
93 format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
98 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
94 format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
99 end
95 end
100 else
96 else
101 respond_to do |format|
97 respond_to do |format|
102 format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
98 format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
103 format.any(:atom, :csv, :pdf) { render(:nothing => true) }
99 format.any(:atom, :csv, :pdf) { render(:nothing => true) }
104 format.api { render_validation_errors(@query) }
100 format.api { render_validation_errors(@query) }
105 end
101 end
106 end
102 end
107 rescue ActiveRecord::RecordNotFound
103 rescue ActiveRecord::RecordNotFound
108 render_404
104 render_404
109 end
105 end
110
106
111 def show
107 def show
112 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
108 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
113 @journals.each_with_index {|j,i| j.indice = i+1}
109 @journals.each_with_index {|j,i| j.indice = i+1}
114 @journals.reverse! if User.current.wants_comments_in_reverse_order?
110 @journals.reverse! if User.current.wants_comments_in_reverse_order?
115
111
116 if User.current.allowed_to?(:view_changesets, @project)
112 if User.current.allowed_to?(:view_changesets, @project)
117 @changesets = @issue.changesets.visible.all
113 @changesets = @issue.changesets.visible.all
118 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
114 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
119 end
115 end
120
116
121 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
117 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
122 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
118 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
123 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
119 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
124 @priorities = IssuePriority.active
120 @priorities = IssuePriority.active
125 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
121 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
126 respond_to do |format|
122 respond_to do |format|
127 format.html { render :template => 'issues/show' }
123 format.html { render :template => 'issues/show' }
128 format.api
124 format.api
129 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
125 format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
130 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
126 format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
131 end
127 end
132 end
128 end
133
129
134 # Add a new issue
130 # Add a new issue
135 # The new issue will be created from an existing one if copy_from parameter is given
131 # The new issue will be created from an existing one if copy_from parameter is given
136 def new
132 def new
137 respond_to do |format|
133 respond_to do |format|
138 format.html { render :action => 'new', :layout => !request.xhr? }
134 format.html { render :action => 'new', :layout => !request.xhr? }
139 format.js { render :partial => 'attributes' }
135 format.js { render :partial => 'attributes' }
140 end
136 end
141 end
137 end
142
138
143 def create
139 def create
144 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
140 call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
145 if @issue.save
141 if @issue.save
146 attachments = Attachment.attach_files(@issue, params[:attachments])
142 attachments = Attachment.attach_files(@issue, params[:attachments])
147 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
143 call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
148 respond_to do |format|
144 respond_to do |format|
149 format.html {
145 format.html {
150 render_attachment_warning_if_needed(@issue)
146 render_attachment_warning_if_needed(@issue)
151 flash[:notice] = l(:notice_issue_successful_create, :id => "<a href='#{issue_path(@issue)}'>##{@issue.id}</a>")
147 flash[:notice] = l(:notice_issue_successful_create, :id => "<a href='#{issue_path(@issue)}'>##{@issue.id}</a>")
152 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?} } :
148 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?} } :
153 { :action => 'show', :id => @issue })
149 { :action => 'show', :id => @issue })
154 }
150 }
155 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
151 format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
156 end
152 end
157 return
153 return
158 else
154 else
159 respond_to do |format|
155 respond_to do |format|
160 format.html { render :action => 'new' }
156 format.html { render :action => 'new' }
161 format.api { render_validation_errors(@issue) }
157 format.api { render_validation_errors(@issue) }
162 end
158 end
163 end
159 end
164 end
160 end
165
161
166 def edit
162 def edit
167 update_issue_from_params
163 update_issue_from_params
168
164
169 @journal = @issue.current_journal
165 @journal = @issue.current_journal
170
166
171 respond_to do |format|
167 respond_to do |format|
172 format.html { }
168 format.html { }
173 format.xml { }
169 format.xml { }
174 end
170 end
175 end
171 end
176
172
177 def update
173 def update
178 update_issue_from_params
174 update_issue_from_params
179
175
180 if @issue.save_issue_with_child_records(params, @time_entry)
176 if @issue.save_issue_with_child_records(params, @time_entry)
181 render_attachment_warning_if_needed(@issue)
177 render_attachment_warning_if_needed(@issue)
182 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
178 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
183
179
184 respond_to do |format|
180 respond_to do |format|
185 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
181 format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
186 format.api { head :ok }
182 format.api { head :ok }
187 end
183 end
188 else
184 else
189 render_attachment_warning_if_needed(@issue)
185 render_attachment_warning_if_needed(@issue)
190 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
186 flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
191 @journal = @issue.current_journal
187 @journal = @issue.current_journal
192
188
193 respond_to do |format|
189 respond_to do |format|
194 format.html { render :action => 'edit' }
190 format.html { render :action => 'edit' }
195 format.api { render_validation_errors(@issue) }
191 format.api { render_validation_errors(@issue) }
196 end
192 end
197 end
193 end
198 end
194 end
199
195
200 # Bulk edit a set of issues
196 # Bulk edit a set of issues
201 def bulk_edit
197 def bulk_edit
202 @issues.sort!
198 @issues.sort!
203 @available_statuses = @projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w}
199 @available_statuses = @projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w}
204 @custom_fields = @projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c}
200 @custom_fields = @projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c}
205 @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
201 @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a}
206 @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
202 @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
207 end
203 end
208
204
209 def bulk_update
205 def bulk_update
210 @issues.sort!
206 @issues.sort!
211 attributes = parse_params_for_bulk_issue_attributes(params)
207 attributes = parse_params_for_bulk_issue_attributes(params)
212
208
213 unsaved_issue_ids = []
209 unsaved_issue_ids = []
214 @issues.each do |issue|
210 @issues.each do |issue|
215 issue.reload
211 issue.reload
216 journal = issue.init_journal(User.current, params[:notes])
212 journal = issue.init_journal(User.current, params[:notes])
217 issue.safe_attributes = attributes
213 issue.safe_attributes = attributes
218 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
214 call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
219 unless issue.save
215 unless issue.save
220 # Keep unsaved issue ids to display them in flash error
216 # Keep unsaved issue ids to display them in flash error
221 unsaved_issue_ids << issue.id
217 unsaved_issue_ids << issue.id
222 end
218 end
223 end
219 end
224 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
220 set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids)
225 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
221 redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
226 end
222 end
227
223
224 verify :method => :delete, :only => :destroy, :render => { :nothing => true, :status => :method_not_allowed }
228 def destroy
225 def destroy
229 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
226 @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f
230 if @hours > 0
227 if @hours > 0
231 case params[:todo]
228 case params[:todo]
232 when 'destroy'
229 when 'destroy'
233 # nothing to do
230 # nothing to do
234 when 'nullify'
231 when 'nullify'
235 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
232 TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues])
236 when 'reassign'
233 when 'reassign'
237 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
234 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
238 if reassign_to.nil?
235 if reassign_to.nil?
239 flash.now[:error] = l(:error_issue_not_found_in_project)
236 flash.now[:error] = l(:error_issue_not_found_in_project)
240 return
237 return
241 else
238 else
242 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
239 TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues])
243 end
240 end
244 else
241 else
245 # display the destroy form if it's a user request
242 # display the destroy form if it's a user request
246 return unless api_request?
243 return unless api_request?
247 end
244 end
248 end
245 end
249 @issues.each do |issue|
246 @issues.each do |issue|
250 begin
247 begin
251 issue.reload.destroy
248 issue.reload.destroy
252 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
249 rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
253 # nothing to do, issue was already deleted (eg. by a parent)
250 # nothing to do, issue was already deleted (eg. by a parent)
254 end
251 end
255 end
252 end
256 respond_to do |format|
253 respond_to do |format|
257 format.html { redirect_back_or_default(:action => 'index', :project_id => @project) }
254 format.html { redirect_back_or_default(:action => 'index', :project_id => @project) }
258 format.api { head :ok }
255 format.api { head :ok }
259 end
256 end
260 end
257 end
261
258
262 private
259 private
263 def find_issue
260 def find_issue
264 # Issue.visible.find(...) can not be used to redirect user to the login form
261 # Issue.visible.find(...) can not be used to redirect user to the login form
265 # if the issue actually exists but requires authentication
262 # if the issue actually exists but requires authentication
266 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
263 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
267 unless @issue.visible?
264 unless @issue.visible?
268 deny_access
265 deny_access
269 return
266 return
270 end
267 end
271 @project = @issue.project
268 @project = @issue.project
272 rescue ActiveRecord::RecordNotFound
269 rescue ActiveRecord::RecordNotFound
273 render_404
270 render_404
274 end
271 end
275
272
276 def find_project
273 def find_project
277 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
274 project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id]
278 @project = Project.find(project_id)
275 @project = Project.find(project_id)
279 rescue ActiveRecord::RecordNotFound
276 rescue ActiveRecord::RecordNotFound
280 render_404
277 render_404
281 end
278 end
282
279
283 # Used by #edit and #update to set some common instance variables
280 # Used by #edit and #update to set some common instance variables
284 # from the params
281 # from the params
285 # TODO: Refactor, not everything in here is needed by #edit
282 # TODO: Refactor, not everything in here is needed by #edit
286 def update_issue_from_params
283 def update_issue_from_params
287 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
284 @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
288 @priorities = IssuePriority.active
285 @priorities = IssuePriority.active
289 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
286 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
290 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
287 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
291 @time_entry.attributes = params[:time_entry]
288 @time_entry.attributes = params[:time_entry]
292
289
293 @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
290 @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
294 @issue.init_journal(User.current, @notes)
291 @issue.init_journal(User.current, @notes)
295 @issue.safe_attributes = params[:issue]
292 @issue.safe_attributes = params[:issue]
296 end
293 end
297
294
298 # TODO: Refactor, lots of extra code in here
295 # TODO: Refactor, lots of extra code in here
299 # TODO: Changing tracker on an existing issue should not trigger this
296 # TODO: Changing tracker on an existing issue should not trigger this
300 def build_new_issue_from_params
297 def build_new_issue_from_params
301 if params[:id].blank?
298 if params[:id].blank?
302 @issue = Issue.new
299 @issue = Issue.new
303 @issue.copy_from(params[:copy_from]) if params[:copy_from]
300 @issue.copy_from(params[:copy_from]) if params[:copy_from]
304 @issue.project = @project
301 @issue.project = @project
305 else
302 else
306 @issue = @project.issues.visible.find(params[:id])
303 @issue = @project.issues.visible.find(params[:id])
307 end
304 end
308
305
309 @issue.project = @project
306 @issue.project = @project
310 @issue.author = User.current
307 @issue.author = User.current
311 # Tracker must be set before custom field values
308 # Tracker must be set before custom field values
312 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
309 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
313 if @issue.tracker.nil?
310 if @issue.tracker.nil?
314 render_error l(:error_no_tracker_in_project)
311 render_error l(:error_no_tracker_in_project)
315 return false
312 return false
316 end
313 end
317 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
314 @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
318 if params[:issue].is_a?(Hash)
315 if params[:issue].is_a?(Hash)
319 @issue.safe_attributes = params[:issue]
316 @issue.safe_attributes = params[:issue]
320 if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record?
317 if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record?
321 @issue.watcher_user_ids = params[:issue]['watcher_user_ids']
318 @issue.watcher_user_ids = params[:issue]['watcher_user_ids']
322 end
319 end
323 end
320 end
324 @priorities = IssuePriority.active
321 @priorities = IssuePriority.active
325 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
322 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
326 end
323 end
327
324
328 def check_for_default_issue_status
325 def check_for_default_issue_status
329 if IssueStatus.default.nil?
326 if IssueStatus.default.nil?
330 render_error l(:error_no_default_issue_status)
327 render_error l(:error_no_default_issue_status)
331 return false
328 return false
332 end
329 end
333 end
330 end
334
331
335 def parse_params_for_bulk_issue_attributes(params)
332 def parse_params_for_bulk_issue_attributes(params)
336 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
333 attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
337 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
334 attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
338 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
335 attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
339 attributes
336 attributes
340 end
337 end
341 end
338 end
@@ -1,121 +1,121
1 <ul>
1 <ul>
2 <%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %>
2 <%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %>
3
3
4 <% if !@issue.nil? -%>
4 <% if !@issue.nil? -%>
5 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
5 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
6 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
6 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
7 <% else %>
7 <% else %>
8 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
8 <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
9 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
9 :class => 'icon-edit', :disabled => !@can[:edit] %></li>
10 <% end %>
10 <% end %>
11
11
12 <% if @allowed_statuses.present? %>
12 <% if @allowed_statuses.present? %>
13 <li class="folder">
13 <li class="folder">
14 <a href="#" class="submenu" onclick="return false;"><%= l(:field_status) %></a>
14 <a href="#" class="submenu" onclick="return false;"><%= l(:field_status) %></a>
15 <ul>
15 <ul>
16 <% @statuses.each do |s| -%>
16 <% @statuses.each do |s| -%>
17 <li><%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post,
17 <li><%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post,
18 :selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %></li>
18 :selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %></li>
19 <% end -%>
19 <% end -%>
20 </ul>
20 </ul>
21 </li>
21 </li>
22 <% end %>
22 <% end %>
23
23
24 <% unless @trackers.nil? %>
24 <% unless @trackers.nil? %>
25 <li class="folder">
25 <li class="folder">
26 <a href="#" class="submenu"><%= l(:field_tracker) %></a>
26 <a href="#" class="submenu"><%= l(:field_tracker) %></a>
27 <ul>
27 <ul>
28 <% @trackers.each do |t| -%>
28 <% @trackers.each do |t| -%>
29 <li><%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post,
29 <li><%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post,
30 :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %></li>
30 :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %></li>
31 <% end -%>
31 <% end -%>
32 </ul>
32 </ul>
33 </li>
33 </li>
34 <% end %>
34 <% end %>
35
35
36 <li class="folder">
36 <li class="folder">
37 <a href="#" class="submenu"><%= l(:field_priority) %></a>
37 <a href="#" class="submenu"><%= l(:field_priority) %></a>
38 <ul>
38 <ul>
39 <% @priorities.each do |p| -%>
39 <% @priorities.each do |p| -%>
40 <li><%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post,
40 <li><%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post,
41 :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
41 :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
42 <% end -%>
42 <% end -%>
43 </ul>
43 </ul>
44 </li>
44 </li>
45
45
46 <% #TODO: allow editing versions when multiple projects %>
46 <% #TODO: allow editing versions when multiple projects %>
47 <% unless @project.nil? || @project.shared_versions.open.empty? -%>
47 <% unless @project.nil? || @project.shared_versions.open.empty? -%>
48 <li class="folder">
48 <li class="folder">
49 <a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
49 <a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
50 <ul>
50 <ul>
51 <% @project.shared_versions.open.sort.each do |v| -%>
51 <% @project.shared_versions.open.sort.each do |v| -%>
52 <li><%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post,
52 <li><%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post,
53 :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %></li>
53 :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %></li>
54 <% end -%>
54 <% end -%>
55 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post,
55 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post,
56 :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %></li>
56 :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %></li>
57 </ul>
57 </ul>
58 </li>
58 </li>
59 <% end %>
59 <% end %>
60 <% if @assignables.present? -%>
60 <% if @assignables.present? -%>
61 <li class="folder">
61 <li class="folder">
62 <a href="#" class="submenu"><%= l(:field_assigned_to) %></a>
62 <a href="#" class="submenu"><%= l(:field_assigned_to) %></a>
63 <ul>
63 <ul>
64 <% @assignables.each do |u| -%>
64 <% @assignables.each do |u| -%>
65 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post,
65 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post,
66 :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %></li>
66 :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %></li>
67 <% end -%>
67 <% end -%>
68 <li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post,
68 <li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post,
69 :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %></li>
69 :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %></li>
70 </ul>
70 </ul>
71 </li>
71 </li>
72 <% end %>
72 <% end %>
73 <% unless @project.nil? || @project.issue_categories.empty? -%>
73 <% unless @project.nil? || @project.issue_categories.empty? -%>
74 <li class="folder">
74 <li class="folder">
75 <a href="#" class="submenu"><%= l(:field_category) %></a>
75 <a href="#" class="submenu"><%= l(:field_category) %></a>
76 <ul>
76 <ul>
77 <% @project.issue_categories.each do |u| -%>
77 <% @project.issue_categories.each do |u| -%>
78 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post,
78 <li><%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post,
79 :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %></li>
79 :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %></li>
80 <% end -%>
80 <% end -%>
81 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post,
81 <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post,
82 :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %></li>
82 :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %></li>
83 </ul>
83 </ul>
84 </li>
84 </li>
85 <% end -%>
85 <% end -%>
86
86
87 <% if Issue.use_field_for_done_ratio? %>
87 <% if Issue.use_field_for_done_ratio? %>
88 <li class="folder">
88 <li class="folder">
89 <a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
89 <a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
90 <ul>
90 <ul>
91 <% (0..10).map{|x|x*10}.each do |p| -%>
91 <% (0..10).map{|x|x*10}.each do |p| -%>
92 <li><%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post,
92 <li><%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post,
93 :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
93 :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %></li>
94 <% end -%>
94 <% end -%>
95 </ul>
95 </ul>
96 </li>
96 </li>
97 <% end %>
97 <% end %>
98
98
99 <% if !@issue.nil? %>
99 <% if !@issue.nil? %>
100 <% if @can[:log_time] -%>
100 <% if @can[:log_time] -%>
101 <li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue},
101 <li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue},
102 :class => 'icon-time-add' %></li>
102 :class => 'icon-time-add' %></li>
103 <% end %>
103 <% end %>
104 <% if User.current.logged? %>
104 <% if User.current.logged? %>
105 <li><%= watcher_link(@issue, User.current) %></li>
105 <li><%= watcher_link(@issue, User.current) %></li>
106 <% end %>
106 <% end %>
107 <% end %>
107 <% end %>
108
108
109 <% if @issue.present? %>
109 <% if @issue.present? %>
110 <li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
110 <li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
111 :class => 'icon-duplicate', :disabled => !@can[:copy] %></li>
111 :class => 'icon-duplicate', :disabled => !@can[:copy] %></li>
112 <% end %>
112 <% end %>
113 <li><%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}),
113 <li><%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}),
114 :class => 'icon-copy', :disabled => !@can[:move] %></li>
114 :class => 'icon-copy', :disabled => !@can[:move] %></li>
115 <li><%= context_menu_link l(:button_move), new_issue_move_path(:ids => @issues.collect(&:id)),
115 <li><%= context_menu_link l(:button_move), new_issue_move_path(:ids => @issues.collect(&:id)),
116 :class => 'icon-move', :disabled => !@can[:move] %></li>
116 :class => 'icon-move', :disabled => !@can[:move] %></li>
117 <li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id), :back_url => @back},
117 <li><%= context_menu_link l(:button_delete), issues_path(:ids => @issues.collect(&:id), :back_url => @back),
118 :method => :post, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li>
118 :method => :delete, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %></li>
119
119
120 <%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %>
120 <%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %>
121 </ul>
121 </ul>
@@ -1,9 +1,9
1 <div class="contextual">
1 <div class="contextual">
2 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
2 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
3 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %>
3 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %>
4 <%= watcher_tag(@issue, User.current) %>
4 <%= watcher_tag(@issue, User.current) %>
5 <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %>
5 <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %>
6 <%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %>
6 <%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %>
7 <%= link_to_if_authorized l(:button_move), {:controller => 'issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move' %>
7 <%= link_to_if_authorized l(:button_move), {:controller => 'issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move' %>
8 <%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => issues_destroy_confirmation_message(@issue), :method => :post, :class => 'icon icon-del' %>
8 <%= link_to l(:button_delete), issue_path(@issue), :confirm => issues_destroy_confirmation_message(@issue), :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
9 </div>
9 </div>
@@ -1,202 +1,203
1 ActionController::Routing::Routes.draw do |map|
1 ActionController::Routing::Routes.draw do |map|
2 # Add your own custom routes here.
2 # Add your own custom routes here.
3 # The priority is based upon order of creation: first created -> highest priority.
3 # The priority is based upon order of creation: first created -> highest priority.
4
4
5 # Here's a sample route:
5 # Here's a sample route:
6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
7 # Keep in mind you can assign values other than :controller and :action
7 # Keep in mind you can assign values other than :controller and :action
8
8
9 map.home '', :controller => 'welcome'
9 map.home '', :controller => 'welcome'
10
10
11 map.signin 'login', :controller => 'account', :action => 'login'
11 map.signin 'login', :controller => 'account', :action => 'login'
12 map.signout 'logout', :controller => 'account', :action => 'logout'
12 map.signout 'logout', :controller => 'account', :action => 'logout'
13
13
14 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
14 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
15 map.connect 'help/:ctrl/:page', :controller => 'help'
15 map.connect 'help/:ctrl/:page', :controller => 'help'
16
16
17 map.time_entries_context_menu '/time_entries/context_menu',
17 map.time_entries_context_menu '/time_entries/context_menu',
18 :controller => 'context_menus', :action => 'time_entries'
18 :controller => 'context_menus', :action => 'time_entries'
19
19
20 map.resources :time_entries, :controller => 'timelog', :collection => {:report => :get, :bulk_edit => :get, :bulk_update => :post}
20 map.resources :time_entries, :controller => 'timelog', :collection => {:report => :get, :bulk_edit => :get, :bulk_update => :post}
21
21
22 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
22 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
23 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
23 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
24 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
24 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
25
25
26 map.with_options :controller => 'messages' do |messages_routes|
26 map.with_options :controller => 'messages' do |messages_routes|
27 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
27 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
28 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
28 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
29 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
29 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
30 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
30 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
31 end
31 end
32 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
32 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
33 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
33 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
34 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
34 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
35 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
35 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
36 end
36 end
37 end
37 end
38
38
39 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
39 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
40 map.resources :queries, :except => [:show]
40 map.resources :queries, :except => [:show]
41
41
42 # Misc issue routes. TODO: move into resources
42 # Misc issue routes. TODO: move into resources
43 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues', :conditions => { :method => :get }
43 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues', :conditions => { :method => :get }
44 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' # TODO: would look nicer as /issues/:id/preview
44 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' # TODO: would look nicer as /issues/:id/preview
45 map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues'
45 map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues'
46 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
46 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
47 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/, :conditions => { :method => :post }
47 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/, :conditions => { :method => :post }
48 map.connect '/issues/:id/destroy', :controller => 'issues', :action => 'destroy', :conditions => { :method => :post } # legacy
49
48
50 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
49 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
51 gantts_routes.connect '/projects/:project_id/issues/gantt'
50 gantts_routes.connect '/projects/:project_id/issues/gantt'
52 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
51 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
53 gantts_routes.connect '/issues/gantt.:format'
52 gantts_routes.connect '/issues/gantt.:format'
54 end
53 end
55
54
56 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
55 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
57 calendars_routes.connect '/projects/:project_id/issues/calendar'
56 calendars_routes.connect '/projects/:project_id/issues/calendar'
58 calendars_routes.connect '/issues/calendar'
57 calendars_routes.connect '/issues/calendar'
59 end
58 end
60
59
61 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
60 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
62 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
61 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
63 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
62 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
64 end
63 end
65
64
66 map.resources :issues, :collection => {:bulk_edit => :get, :bulk_update => :post} do |issues|
65 map.resources :issues, :collection => {:bulk_edit => :get, :bulk_update => :post} do |issues|
67 issues.resources :time_entries, :controller => 'timelog', :collection => {:report => :get}
66 issues.resources :time_entries, :controller => 'timelog', :collection => {:report => :get}
68 issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
67 issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
69 end
68 end
69 # Bulk deletion
70 map.connect '/issues', :controller => 'issues', :action => 'destroy', :conditions => {:method => :delete}
70
71
71 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
72 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
72
73
73 map.resources :users
74 map.resources :users
74 map.with_options :controller => 'users' do |users|
75 map.with_options :controller => 'users' do |users|
75 users.user_memberships 'users/:id/memberships', :action => 'edit_membership', :conditions => {:method => :post}
76 users.user_memberships 'users/:id/memberships', :action => 'edit_membership', :conditions => {:method => :post}
76 users.user_membership 'users/:id/memberships/:membership_id', :action => 'edit_membership', :conditions => {:method => :put}
77 users.user_membership 'users/:id/memberships/:membership_id', :action => 'edit_membership', :conditions => {:method => :put}
77 users.connect 'users/:id/memberships/:membership_id', :action => 'destroy_membership', :conditions => {:method => :delete}
78 users.connect 'users/:id/memberships/:membership_id', :action => 'destroy_membership', :conditions => {:method => :delete}
78 end
79 end
79
80
80 # For nice "roadmap" in the url for the index action
81 # For nice "roadmap" in the url for the index action
81 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
82 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
82
83
83 map.all_news 'news', :controller => 'news', :action => 'index'
84 map.all_news 'news', :controller => 'news', :action => 'index'
84 map.formatted_all_news 'news.:format', :controller => 'news', :action => 'index'
85 map.formatted_all_news 'news.:format', :controller => 'news', :action => 'index'
85 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
86 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
86 map.connect 'news/:id/comments', :controller => 'comments', :action => 'create', :conditions => {:method => :post}
87 map.connect 'news/:id/comments', :controller => 'comments', :action => 'create', :conditions => {:method => :post}
87 map.connect 'news/:id/comments/:comment_id', :controller => 'comments', :action => 'destroy', :conditions => {:method => :delete}
88 map.connect 'news/:id/comments/:comment_id', :controller => 'comments', :action => 'destroy', :conditions => {:method => :delete}
88
89
89 map.resources :projects, :member => {
90 map.resources :projects, :member => {
90 :copy => [:get, :post],
91 :copy => [:get, :post],
91 :settings => :get,
92 :settings => :get,
92 :modules => :post,
93 :modules => :post,
93 :archive => :post,
94 :archive => :post,
94 :unarchive => :post
95 :unarchive => :post
95 } do |project|
96 } do |project|
96 project.resource :project_enumerations, :as => 'enumerations', :only => [:update, :destroy]
97 project.resource :project_enumerations, :as => 'enumerations', :only => [:update, :destroy]
97 project.resources :issues, :only => [:index, :new, :create] do |issues|
98 project.resources :issues, :only => [:index, :new, :create] do |issues|
98 issues.resources :time_entries, :controller => 'timelog', :collection => {:report => :get}
99 issues.resources :time_entries, :controller => 'timelog', :collection => {:report => :get}
99 end
100 end
100 project.resources :files, :only => [:index, :new, :create]
101 project.resources :files, :only => [:index, :new, :create]
101 project.resources :versions, :shallow => true, :collection => {:close_completed => :put}, :member => {:status_by => :post}
102 project.resources :versions, :shallow => true, :collection => {:close_completed => :put}, :member => {:status_by => :post}
102 project.resources :news, :shallow => true
103 project.resources :news, :shallow => true
103 project.resources :time_entries, :controller => 'timelog', :path_prefix => 'projects/:project_id', :collection => {:report => :get}
104 project.resources :time_entries, :controller => 'timelog', :path_prefix => 'projects/:project_id', :collection => {:report => :get}
104 project.resources :queries, :only => [:new, :create]
105 project.resources :queries, :only => [:new, :create]
105 project.resources :issue_categories, :shallow => true
106 project.resources :issue_categories, :shallow => true
106 project.resources :documents, :shallow => true, :member => {:add_attachment => :post}
107 project.resources :documents, :shallow => true, :member => {:add_attachment => :post}
107 project.resources :boards
108 project.resources :boards
108
109
109 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
110 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
110 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
111 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
111 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
112 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
112 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
113 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
113 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
114 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
114 project.resources :wiki, :except => [:new, :create], :member => {
115 project.resources :wiki, :except => [:new, :create], :member => {
115 :rename => [:get, :post],
116 :rename => [:get, :post],
116 :history => :get,
117 :history => :get,
117 :preview => :any,
118 :preview => :any,
118 :protect => :post,
119 :protect => :post,
119 :add_attachment => :post
120 :add_attachment => :post
120 }, :collection => {
121 }, :collection => {
121 :export => :get,
122 :export => :get,
122 :date_index => :get
123 :date_index => :get
123 }
124 }
124
125
125 end
126 end
126
127
127 # Destroy uses a get request to prompt the user before the actual DELETE request
128 # Destroy uses a get request to prompt the user before the actual DELETE request
128 map.project_destroy_confirm 'projects/:id/destroy', :controller => 'projects', :action => 'destroy', :conditions => {:method => :get}
129 map.project_destroy_confirm 'projects/:id/destroy', :controller => 'projects', :action => 'destroy', :conditions => {:method => :get}
129
130
130 # TODO: port to be part of the resources route(s)
131 # TODO: port to be part of the resources route(s)
131 map.with_options :controller => 'projects' do |project_mapper|
132 map.with_options :controller => 'projects' do |project_mapper|
132 project_mapper.with_options :conditions => {:method => :get} do |project_views|
133 project_mapper.with_options :conditions => {:method => :get} do |project_views|
133 project_views.connect 'projects/:id/settings/:tab', :controller => 'projects', :action => 'settings'
134 project_views.connect 'projects/:id/settings/:tab', :controller => 'projects', :action => 'settings'
134 project_views.connect 'projects/:project_id/issues/:copy_from/copy', :controller => 'issues', :action => 'new'
135 project_views.connect 'projects/:project_id/issues/:copy_from/copy', :controller => 'issues', :action => 'new'
135 end
136 end
136 end
137 end
137
138
138 map.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity|
139 map.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity|
139 activity.connect 'projects/:id/activity'
140 activity.connect 'projects/:id/activity'
140 activity.connect 'projects/:id/activity.:format'
141 activity.connect 'projects/:id/activity.:format'
141 activity.connect 'activity', :id => nil
142 activity.connect 'activity', :id => nil
142 activity.connect 'activity.:format', :id => nil
143 activity.connect 'activity.:format', :id => nil
143 end
144 end
144
145
145 map.with_options :controller => 'repositories' do |repositories|
146 map.with_options :controller => 'repositories' do |repositories|
146 repositories.with_options :conditions => {:method => :get} do |repository_views|
147 repositories.with_options :conditions => {:method => :get} do |repository_views|
147 repository_views.connect 'projects/:id/repository', :action => 'show'
148 repository_views.connect 'projects/:id/repository', :action => 'show'
148 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
149 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
149 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
150 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
150 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
151 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
151 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
152 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
152 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
153 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
153 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
154 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
154 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
155 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
155 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
156 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
156 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
157 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
157 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
158 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
158 # TODO: why the following route is required?
159 # TODO: why the following route is required?
159 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
160 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
160 repository_views.connect 'projects/:id/repository/:action/*path'
161 repository_views.connect 'projects/:id/repository/:action/*path'
161 end
162 end
162
163
163 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
164 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
164 end
165 end
165
166
166 map.resources :attachments, :only => [:show, :destroy]
167 map.resources :attachments, :only => [:show, :destroy]
167 # additional routes for having the file name at the end of url
168 # additional routes for having the file name at the end of url
168 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
169 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
169 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
170 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
170
171
171 map.resources :groups, :member => {:autocomplete_for_user => :get}
172 map.resources :groups, :member => {:autocomplete_for_user => :get}
172 map.group_users 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :conditions => {:method => :post}
173 map.group_users 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :conditions => {:method => :post}
173 map.group_user 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :conditions => {:method => :delete}
174 map.group_user 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :conditions => {:method => :delete}
174
175
175 map.resources :trackers, :except => :show
176 map.resources :trackers, :except => :show
176 map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
177 map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
177 map.resources :custom_fields, :except => :show
178 map.resources :custom_fields, :except => :show
178 map.resources :roles, :except => :show, :collection => {:permissions => [:get, :post]}
179 map.resources :roles, :except => :show, :collection => {:permissions => [:get, :post]}
179
180
180 #left old routes at the bottom for backwards compat
181 #left old routes at the bottom for backwards compat
181 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
182 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
182 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
183 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
183 map.with_options :controller => 'repositories' do |omap|
184 map.with_options :controller => 'repositories' do |omap|
184 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
185 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
185 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
186 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
186 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
187 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
187 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
188 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
188 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
189 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
189 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
190 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
190 end
191 end
191
192
192 map.with_options :controller => 'sys' do |sys|
193 map.with_options :controller => 'sys' do |sys|
193 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
194 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
194 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
195 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
195 end
196 end
196
197
197 # Install the default route as the lowest priority.
198 # Install the default route as the lowest priority.
198 map.connect ':controller/:action/:id'
199 map.connect ':controller/:action/:id'
199 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
200 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
200 # Used for OpenID
201 # Used for OpenID
201 map.root :controller => 'account', :action => 'login'
202 map.root :controller => 'account', :action => 'login'
202 end
203 end
@@ -1,2065 +1,2065
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'issues_controller'
19 require 'issues_controller'
20
20
21 class IssuesControllerTest < ActionController::TestCase
21 class IssuesControllerTest < ActionController::TestCase
22 fixtures :projects,
22 fixtures :projects,
23 :users,
23 :users,
24 :roles,
24 :roles,
25 :members,
25 :members,
26 :member_roles,
26 :member_roles,
27 :issues,
27 :issues,
28 :issue_statuses,
28 :issue_statuses,
29 :versions,
29 :versions,
30 :trackers,
30 :trackers,
31 :projects_trackers,
31 :projects_trackers,
32 :issue_categories,
32 :issue_categories,
33 :enabled_modules,
33 :enabled_modules,
34 :enumerations,
34 :enumerations,
35 :attachments,
35 :attachments,
36 :workflows,
36 :workflows,
37 :custom_fields,
37 :custom_fields,
38 :custom_values,
38 :custom_values,
39 :custom_fields_projects,
39 :custom_fields_projects,
40 :custom_fields_trackers,
40 :custom_fields_trackers,
41 :time_entries,
41 :time_entries,
42 :journals,
42 :journals,
43 :journal_details,
43 :journal_details,
44 :queries
44 :queries
45
45
46 include Redmine::I18n
46 include Redmine::I18n
47
47
48 def setup
48 def setup
49 @controller = IssuesController.new
49 @controller = IssuesController.new
50 @request = ActionController::TestRequest.new
50 @request = ActionController::TestRequest.new
51 @response = ActionController::TestResponse.new
51 @response = ActionController::TestResponse.new
52 User.current = nil
52 User.current = nil
53 end
53 end
54
54
55 def test_index
55 def test_index
56 Setting.default_language = 'en'
56 Setting.default_language = 'en'
57
57
58 get :index
58 get :index
59 assert_response :success
59 assert_response :success
60 assert_template 'index'
60 assert_template 'index'
61 assert_not_nil assigns(:issues)
61 assert_not_nil assigns(:issues)
62 assert_nil assigns(:project)
62 assert_nil assigns(:project)
63 assert_tag :tag => 'a', :content => /Can't print recipes/
63 assert_tag :tag => 'a', :content => /Can't print recipes/
64 assert_tag :tag => 'a', :content => /Subproject issue/
64 assert_tag :tag => 'a', :content => /Subproject issue/
65 # private projects hidden
65 # private projects hidden
66 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
66 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
67 assert_no_tag :tag => 'a', :content => /Issue on project 2/
67 assert_no_tag :tag => 'a', :content => /Issue on project 2/
68 # project column
68 # project column
69 assert_tag :tag => 'th', :content => /Project/
69 assert_tag :tag => 'th', :content => /Project/
70 end
70 end
71
71
72 def test_index_should_not_list_issues_when_module_disabled
72 def test_index_should_not_list_issues_when_module_disabled
73 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
73 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
74 get :index
74 get :index
75 assert_response :success
75 assert_response :success
76 assert_template 'index'
76 assert_template 'index'
77 assert_not_nil assigns(:issues)
77 assert_not_nil assigns(:issues)
78 assert_nil assigns(:project)
78 assert_nil assigns(:project)
79 assert_no_tag :tag => 'a', :content => /Can't print recipes/
79 assert_no_tag :tag => 'a', :content => /Can't print recipes/
80 assert_tag :tag => 'a', :content => /Subproject issue/
80 assert_tag :tag => 'a', :content => /Subproject issue/
81 end
81 end
82
82
83 def test_index_should_list_visible_issues_only
83 def test_index_should_list_visible_issues_only
84 get :index, :per_page => 100
84 get :index, :per_page => 100
85 assert_response :success
85 assert_response :success
86 assert_not_nil assigns(:issues)
86 assert_not_nil assigns(:issues)
87 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
87 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
88 end
88 end
89
89
90 def test_index_with_project
90 def test_index_with_project
91 Setting.display_subprojects_issues = 0
91 Setting.display_subprojects_issues = 0
92 get :index, :project_id => 1
92 get :index, :project_id => 1
93 assert_response :success
93 assert_response :success
94 assert_template 'index'
94 assert_template 'index'
95 assert_not_nil assigns(:issues)
95 assert_not_nil assigns(:issues)
96 assert_tag :tag => 'a', :content => /Can't print recipes/
96 assert_tag :tag => 'a', :content => /Can't print recipes/
97 assert_no_tag :tag => 'a', :content => /Subproject issue/
97 assert_no_tag :tag => 'a', :content => /Subproject issue/
98 end
98 end
99
99
100 def test_index_with_project_and_subprojects
100 def test_index_with_project_and_subprojects
101 Setting.display_subprojects_issues = 1
101 Setting.display_subprojects_issues = 1
102 get :index, :project_id => 1
102 get :index, :project_id => 1
103 assert_response :success
103 assert_response :success
104 assert_template 'index'
104 assert_template 'index'
105 assert_not_nil assigns(:issues)
105 assert_not_nil assigns(:issues)
106 assert_tag :tag => 'a', :content => /Can't print recipes/
106 assert_tag :tag => 'a', :content => /Can't print recipes/
107 assert_tag :tag => 'a', :content => /Subproject issue/
107 assert_tag :tag => 'a', :content => /Subproject issue/
108 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
108 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
109 end
109 end
110
110
111 def test_index_with_project_and_subprojects_should_show_private_subprojects
111 def test_index_with_project_and_subprojects_should_show_private_subprojects
112 @request.session[:user_id] = 2
112 @request.session[:user_id] = 2
113 Setting.display_subprojects_issues = 1
113 Setting.display_subprojects_issues = 1
114 get :index, :project_id => 1
114 get :index, :project_id => 1
115 assert_response :success
115 assert_response :success
116 assert_template 'index'
116 assert_template 'index'
117 assert_not_nil assigns(:issues)
117 assert_not_nil assigns(:issues)
118 assert_tag :tag => 'a', :content => /Can't print recipes/
118 assert_tag :tag => 'a', :content => /Can't print recipes/
119 assert_tag :tag => 'a', :content => /Subproject issue/
119 assert_tag :tag => 'a', :content => /Subproject issue/
120 assert_tag :tag => 'a', :content => /Issue of a private subproject/
120 assert_tag :tag => 'a', :content => /Issue of a private subproject/
121 end
121 end
122
122
123 def test_index_with_project_and_default_filter
123 def test_index_with_project_and_default_filter
124 get :index, :project_id => 1, :set_filter => 1
124 get :index, :project_id => 1, :set_filter => 1
125 assert_response :success
125 assert_response :success
126 assert_template 'index'
126 assert_template 'index'
127 assert_not_nil assigns(:issues)
127 assert_not_nil assigns(:issues)
128
128
129 query = assigns(:query)
129 query = assigns(:query)
130 assert_not_nil query
130 assert_not_nil query
131 # default filter
131 # default filter
132 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
132 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
133 end
133 end
134
134
135 def test_index_with_project_and_filter
135 def test_index_with_project_and_filter
136 get :index, :project_id => 1, :set_filter => 1,
136 get :index, :project_id => 1, :set_filter => 1,
137 :f => ['tracker_id'],
137 :f => ['tracker_id'],
138 :op => {'tracker_id' => '='},
138 :op => {'tracker_id' => '='},
139 :v => {'tracker_id' => ['1']}
139 :v => {'tracker_id' => ['1']}
140 assert_response :success
140 assert_response :success
141 assert_template 'index'
141 assert_template 'index'
142 assert_not_nil assigns(:issues)
142 assert_not_nil assigns(:issues)
143
143
144 query = assigns(:query)
144 query = assigns(:query)
145 assert_not_nil query
145 assert_not_nil query
146 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
146 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
147 end
147 end
148
148
149 def test_index_with_short_filters
149 def test_index_with_short_filters
150
150
151 to_test = {
151 to_test = {
152 'status_id' => {
152 'status_id' => {
153 'o' => { :op => 'o', :values => [''] },
153 'o' => { :op => 'o', :values => [''] },
154 'c' => { :op => 'c', :values => [''] },
154 'c' => { :op => 'c', :values => [''] },
155 '7' => { :op => '=', :values => ['7'] },
155 '7' => { :op => '=', :values => ['7'] },
156 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
156 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
157 '=7' => { :op => '=', :values => ['7'] },
157 '=7' => { :op => '=', :values => ['7'] },
158 '!3' => { :op => '!', :values => ['3'] },
158 '!3' => { :op => '!', :values => ['3'] },
159 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
159 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
160 'subject' => {
160 'subject' => {
161 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
161 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
162 'o' => { :op => '=', :values => ['o'] },
162 'o' => { :op => '=', :values => ['o'] },
163 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
163 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
164 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
164 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
165 'tracker_id' => {
165 'tracker_id' => {
166 '3' => { :op => '=', :values => ['3'] },
166 '3' => { :op => '=', :values => ['3'] },
167 '=3' => { :op => '=', :values => ['3'] }},
167 '=3' => { :op => '=', :values => ['3'] }},
168 'start_date' => {
168 'start_date' => {
169 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
169 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
170 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
170 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
171 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
171 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
172 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
172 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
173 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
173 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
174 '<t+2' => { :op => '<t+', :values => ['2'] },
174 '<t+2' => { :op => '<t+', :values => ['2'] },
175 '>t+2' => { :op => '>t+', :values => ['2'] },
175 '>t+2' => { :op => '>t+', :values => ['2'] },
176 't+2' => { :op => 't+', :values => ['2'] },
176 't+2' => { :op => 't+', :values => ['2'] },
177 't' => { :op => 't', :values => [''] },
177 't' => { :op => 't', :values => [''] },
178 'w' => { :op => 'w', :values => [''] },
178 'w' => { :op => 'w', :values => [''] },
179 '>t-2' => { :op => '>t-', :values => ['2'] },
179 '>t-2' => { :op => '>t-', :values => ['2'] },
180 '<t-2' => { :op => '<t-', :values => ['2'] },
180 '<t-2' => { :op => '<t-', :values => ['2'] },
181 't-2' => { :op => 't-', :values => ['2'] }},
181 't-2' => { :op => 't-', :values => ['2'] }},
182 'created_on' => {
182 'created_on' => {
183 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
183 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
184 '<t+2' => { :op => '=', :values => ['<t+2'] },
184 '<t+2' => { :op => '=', :values => ['<t+2'] },
185 '>t+2' => { :op => '=', :values => ['>t+2'] },
185 '>t+2' => { :op => '=', :values => ['>t+2'] },
186 't+2' => { :op => 't', :values => ['+2'] }},
186 't+2' => { :op => 't', :values => ['+2'] }},
187 'cf_1' => {
187 'cf_1' => {
188 'c' => { :op => '=', :values => ['c'] },
188 'c' => { :op => '=', :values => ['c'] },
189 '!c' => { :op => '!', :values => ['c'] },
189 '!c' => { :op => '!', :values => ['c'] },
190 '!*' => { :op => '!*', :values => [''] },
190 '!*' => { :op => '!*', :values => [''] },
191 '*' => { :op => '*', :values => [''] }},
191 '*' => { :op => '*', :values => [''] }},
192 'estimated_hours' => {
192 'estimated_hours' => {
193 '=13.4' => { :op => '=', :values => ['13.4'] },
193 '=13.4' => { :op => '=', :values => ['13.4'] },
194 '>=45' => { :op => '>=', :values => ['45'] },
194 '>=45' => { :op => '>=', :values => ['45'] },
195 '<=125' => { :op => '<=', :values => ['125'] },
195 '<=125' => { :op => '<=', :values => ['125'] },
196 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
196 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
197 '!*' => { :op => '!*', :values => [''] },
197 '!*' => { :op => '!*', :values => [''] },
198 '*' => { :op => '*', :values => [''] }}
198 '*' => { :op => '*', :values => [''] }}
199 }
199 }
200
200
201 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
201 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
202
202
203 to_test.each do |field, expression_and_expected|
203 to_test.each do |field, expression_and_expected|
204 expression_and_expected.each do |filter_expression, expected|
204 expression_and_expected.each do |filter_expression, expected|
205
205
206 get :index, :set_filter => 1, field => filter_expression
206 get :index, :set_filter => 1, field => filter_expression
207
207
208 assert_response :success
208 assert_response :success
209 assert_template 'index'
209 assert_template 'index'
210 assert_not_nil assigns(:issues)
210 assert_not_nil assigns(:issues)
211
211
212 query = assigns(:query)
212 query = assigns(:query)
213 assert_not_nil query
213 assert_not_nil query
214 assert query.has_filter?(field)
214 assert query.has_filter?(field)
215 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
215 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
216 end
216 end
217 end
217 end
218
218
219 end
219 end
220
220
221 def test_index_with_project_and_empty_filters
221 def test_index_with_project_and_empty_filters
222 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
222 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
223 assert_response :success
223 assert_response :success
224 assert_template 'index'
224 assert_template 'index'
225 assert_not_nil assigns(:issues)
225 assert_not_nil assigns(:issues)
226
226
227 query = assigns(:query)
227 query = assigns(:query)
228 assert_not_nil query
228 assert_not_nil query
229 # no filter
229 # no filter
230 assert_equal({}, query.filters)
230 assert_equal({}, query.filters)
231 end
231 end
232
232
233 def test_index_with_query
233 def test_index_with_query
234 get :index, :project_id => 1, :query_id => 5
234 get :index, :project_id => 1, :query_id => 5
235 assert_response :success
235 assert_response :success
236 assert_template 'index'
236 assert_template 'index'
237 assert_not_nil assigns(:issues)
237 assert_not_nil assigns(:issues)
238 assert_nil assigns(:issue_count_by_group)
238 assert_nil assigns(:issue_count_by_group)
239 end
239 end
240
240
241 def test_index_with_query_grouped_by_tracker
241 def test_index_with_query_grouped_by_tracker
242 get :index, :project_id => 1, :query_id => 6
242 get :index, :project_id => 1, :query_id => 6
243 assert_response :success
243 assert_response :success
244 assert_template 'index'
244 assert_template 'index'
245 assert_not_nil assigns(:issues)
245 assert_not_nil assigns(:issues)
246 assert_not_nil assigns(:issue_count_by_group)
246 assert_not_nil assigns(:issue_count_by_group)
247 end
247 end
248
248
249 def test_index_with_query_grouped_by_list_custom_field
249 def test_index_with_query_grouped_by_list_custom_field
250 get :index, :project_id => 1, :query_id => 9
250 get :index, :project_id => 1, :query_id => 9
251 assert_response :success
251 assert_response :success
252 assert_template 'index'
252 assert_template 'index'
253 assert_not_nil assigns(:issues)
253 assert_not_nil assigns(:issues)
254 assert_not_nil assigns(:issue_count_by_group)
254 assert_not_nil assigns(:issue_count_by_group)
255 end
255 end
256
256
257 def test_index_with_query_id_and_project_id_should_set_session_query
257 def test_index_with_query_id_and_project_id_should_set_session_query
258 get :index, :project_id => 1, :query_id => 4
258 get :index, :project_id => 1, :query_id => 4
259 assert_response :success
259 assert_response :success
260 assert_kind_of Hash, session[:query]
260 assert_kind_of Hash, session[:query]
261 assert_equal 4, session[:query][:id]
261 assert_equal 4, session[:query][:id]
262 assert_equal 1, session[:query][:project_id]
262 assert_equal 1, session[:query][:project_id]
263 end
263 end
264
264
265 def test_index_with_cross_project_query_in_session_should_show_project_issues
265 def test_index_with_cross_project_query_in_session_should_show_project_issues
266 q = Query.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil)
266 q = Query.create!(:name => "test", :user_id => 2, :is_public => false, :project => nil)
267 @request.session[:query] = {:id => q.id, :project_id => 1}
267 @request.session[:query] = {:id => q.id, :project_id => 1}
268
268
269 with_settings :display_subprojects_issues => '0' do
269 with_settings :display_subprojects_issues => '0' do
270 get :index, :project_id => 1
270 get :index, :project_id => 1
271 end
271 end
272 assert_response :success
272 assert_response :success
273 assert_not_nil assigns(:query)
273 assert_not_nil assigns(:query)
274 assert_equal q.id, assigns(:query).id
274 assert_equal q.id, assigns(:query).id
275 assert_equal 1, assigns(:query).project_id
275 assert_equal 1, assigns(:query).project_id
276 assert_equal [1], assigns(:issues).map(&:project_id).uniq
276 assert_equal [1], assigns(:issues).map(&:project_id).uniq
277 end
277 end
278
278
279 def test_private_query_should_not_be_available_to_other_users
279 def test_private_query_should_not_be_available_to_other_users
280 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
280 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
281 @request.session[:user_id] = 3
281 @request.session[:user_id] = 3
282
282
283 get :index, :query_id => q.id
283 get :index, :query_id => q.id
284 assert_response 403
284 assert_response 403
285 end
285 end
286
286
287 def test_private_query_should_be_available_to_its_user
287 def test_private_query_should_be_available_to_its_user
288 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
288 q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
289 @request.session[:user_id] = 2
289 @request.session[:user_id] = 2
290
290
291 get :index, :query_id => q.id
291 get :index, :query_id => q.id
292 assert_response :success
292 assert_response :success
293 end
293 end
294
294
295 def test_public_query_should_be_available_to_other_users
295 def test_public_query_should_be_available_to_other_users
296 q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
296 q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
297 @request.session[:user_id] = 3
297 @request.session[:user_id] = 3
298
298
299 get :index, :query_id => q.id
299 get :index, :query_id => q.id
300 assert_response :success
300 assert_response :success
301 end
301 end
302
302
303 def test_index_csv
303 def test_index_csv
304 get :index, :format => 'csv'
304 get :index, :format => 'csv'
305 assert_response :success
305 assert_response :success
306 assert_not_nil assigns(:issues)
306 assert_not_nil assigns(:issues)
307 assert_equal 'text/csv', @response.content_type
307 assert_equal 'text/csv', @response.content_type
308 assert @response.body.starts_with?("#,")
308 assert @response.body.starts_with?("#,")
309 lines = @response.body.chomp.split("\n")
309 lines = @response.body.chomp.split("\n")
310 assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size
310 assert_equal assigns(:query).columns.size + 1, lines[0].split(',').size
311 end
311 end
312
312
313 def test_index_csv_with_project
313 def test_index_csv_with_project
314 get :index, :project_id => 1, :format => 'csv'
314 get :index, :project_id => 1, :format => 'csv'
315 assert_response :success
315 assert_response :success
316 assert_not_nil assigns(:issues)
316 assert_not_nil assigns(:issues)
317 assert_equal 'text/csv', @response.content_type
317 assert_equal 'text/csv', @response.content_type
318 end
318 end
319
319
320 def test_index_csv_with_description
320 def test_index_csv_with_description
321 get :index, :format => 'csv', :description => '1'
321 get :index, :format => 'csv', :description => '1'
322 assert_response :success
322 assert_response :success
323 assert_not_nil assigns(:issues)
323 assert_not_nil assigns(:issues)
324 assert_equal 'text/csv', @response.content_type
324 assert_equal 'text/csv', @response.content_type
325 assert @response.body.starts_with?("#,")
325 assert @response.body.starts_with?("#,")
326 lines = @response.body.chomp.split("\n")
326 lines = @response.body.chomp.split("\n")
327 assert_equal assigns(:query).columns.size + 2, lines[0].split(',').size
327 assert_equal assigns(:query).columns.size + 2, lines[0].split(',').size
328 end
328 end
329
329
330 def test_index_csv_with_all_columns
330 def test_index_csv_with_all_columns
331 get :index, :format => 'csv', :columns => 'all'
331 get :index, :format => 'csv', :columns => 'all'
332 assert_response :success
332 assert_response :success
333 assert_not_nil assigns(:issues)
333 assert_not_nil assigns(:issues)
334 assert_equal 'text/csv', @response.content_type
334 assert_equal 'text/csv', @response.content_type
335 assert @response.body.starts_with?("#,")
335 assert @response.body.starts_with?("#,")
336 lines = @response.body.chomp.split("\n")
336 lines = @response.body.chomp.split("\n")
337 assert_equal assigns(:query).available_columns.size + 1, lines[0].split(',').size
337 assert_equal assigns(:query).available_columns.size + 1, lines[0].split(',').size
338 end
338 end
339
339
340 def test_index_csv_big_5
340 def test_index_csv_big_5
341 with_settings :default_language => "zh-TW" do
341 with_settings :default_language => "zh-TW" do
342 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
342 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
343 str_big5 = "\xa4@\xa4\xeb"
343 str_big5 = "\xa4@\xa4\xeb"
344 if str_utf8.respond_to?(:force_encoding)
344 if str_utf8.respond_to?(:force_encoding)
345 str_utf8.force_encoding('UTF-8')
345 str_utf8.force_encoding('UTF-8')
346 str_big5.force_encoding('Big5')
346 str_big5.force_encoding('Big5')
347 end
347 end
348 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
348 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
349 :status_id => 1, :priority => IssuePriority.all.first,
349 :status_id => 1, :priority => IssuePriority.all.first,
350 :subject => str_utf8)
350 :subject => str_utf8)
351 assert issue.save
351 assert issue.save
352
352
353 get :index, :project_id => 1,
353 get :index, :project_id => 1,
354 :f => ['subject'],
354 :f => ['subject'],
355 :op => '=', :values => [str_utf8],
355 :op => '=', :values => [str_utf8],
356 :format => 'csv'
356 :format => 'csv'
357 assert_equal 'text/csv', @response.content_type
357 assert_equal 'text/csv', @response.content_type
358 lines = @response.body.chomp.split("\n")
358 lines = @response.body.chomp.split("\n")
359 s1 = "\xaa\xac\xbaA"
359 s1 = "\xaa\xac\xbaA"
360 if str_utf8.respond_to?(:force_encoding)
360 if str_utf8.respond_to?(:force_encoding)
361 s1.force_encoding('Big5')
361 s1.force_encoding('Big5')
362 end
362 end
363 assert lines[0].include?(s1)
363 assert lines[0].include?(s1)
364 assert lines[1].include?(str_big5)
364 assert lines[1].include?(str_big5)
365 end
365 end
366 end
366 end
367
367
368 def test_index_csv_cannot_convert_should_be_replaced_big_5
368 def test_index_csv_cannot_convert_should_be_replaced_big_5
369 with_settings :default_language => "zh-TW" do
369 with_settings :default_language => "zh-TW" do
370 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
370 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
371 if str_utf8.respond_to?(:force_encoding)
371 if str_utf8.respond_to?(:force_encoding)
372 str_utf8.force_encoding('UTF-8')
372 str_utf8.force_encoding('UTF-8')
373 end
373 end
374 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
374 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
375 :status_id => 1, :priority => IssuePriority.all.first,
375 :status_id => 1, :priority => IssuePriority.all.first,
376 :subject => str_utf8)
376 :subject => str_utf8)
377 assert issue.save
377 assert issue.save
378
378
379 get :index, :project_id => 1,
379 get :index, :project_id => 1,
380 :f => ['subject'],
380 :f => ['subject'],
381 :op => '=', :values => [str_utf8],
381 :op => '=', :values => [str_utf8],
382 :c => ['status', 'subject'],
382 :c => ['status', 'subject'],
383 :format => 'csv',
383 :format => 'csv',
384 :set_filter => 1
384 :set_filter => 1
385 assert_equal 'text/csv', @response.content_type
385 assert_equal 'text/csv', @response.content_type
386 lines = @response.body.chomp.split("\n")
386 lines = @response.body.chomp.split("\n")
387 s1 = "\xaa\xac\xbaA" # status
387 s1 = "\xaa\xac\xbaA" # status
388 if str_utf8.respond_to?(:force_encoding)
388 if str_utf8.respond_to?(:force_encoding)
389 s1.force_encoding('Big5')
389 s1.force_encoding('Big5')
390 end
390 end
391 assert lines[0].include?(s1)
391 assert lines[0].include?(s1)
392 s2 = lines[1].split(",")[2]
392 s2 = lines[1].split(",")[2]
393 if s1.respond_to?(:force_encoding)
393 if s1.respond_to?(:force_encoding)
394 s3 = "\xa5H?" # subject
394 s3 = "\xa5H?" # subject
395 s3.force_encoding('Big5')
395 s3.force_encoding('Big5')
396 assert_equal s3, s2
396 assert_equal s3, s2
397 elsif RUBY_PLATFORM == 'java'
397 elsif RUBY_PLATFORM == 'java'
398 assert_equal "??", s2
398 assert_equal "??", s2
399 else
399 else
400 assert_equal "\xa5H???", s2
400 assert_equal "\xa5H???", s2
401 end
401 end
402 end
402 end
403 end
403 end
404
404
405 def test_index_csv_tw
405 def test_index_csv_tw
406 with_settings :default_language => "zh-TW" do
406 with_settings :default_language => "zh-TW" do
407 str1 = "test_index_csv_tw"
407 str1 = "test_index_csv_tw"
408 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
408 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
409 :status_id => 1, :priority => IssuePriority.all.first,
409 :status_id => 1, :priority => IssuePriority.all.first,
410 :subject => str1, :estimated_hours => '1234.5')
410 :subject => str1, :estimated_hours => '1234.5')
411 assert issue.save
411 assert issue.save
412 assert_equal 1234.5, issue.estimated_hours
412 assert_equal 1234.5, issue.estimated_hours
413
413
414 get :index, :project_id => 1,
414 get :index, :project_id => 1,
415 :f => ['subject'],
415 :f => ['subject'],
416 :op => '=', :values => [str1],
416 :op => '=', :values => [str1],
417 :c => ['estimated_hours', 'subject'],
417 :c => ['estimated_hours', 'subject'],
418 :format => 'csv',
418 :format => 'csv',
419 :set_filter => 1
419 :set_filter => 1
420 assert_equal 'text/csv', @response.content_type
420 assert_equal 'text/csv', @response.content_type
421 lines = @response.body.chomp.split("\n")
421 lines = @response.body.chomp.split("\n")
422 assert_equal "#{issue.id},1234.5,#{str1}", lines[1]
422 assert_equal "#{issue.id},1234.5,#{str1}", lines[1]
423
423
424 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)"
424 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)"
425 if str_tw.respond_to?(:force_encoding)
425 if str_tw.respond_to?(:force_encoding)
426 str_tw.force_encoding('UTF-8')
426 str_tw.force_encoding('UTF-8')
427 end
427 end
428 assert_equal str_tw, l(:general_lang_name)
428 assert_equal str_tw, l(:general_lang_name)
429 assert_equal ',', l(:general_csv_separator)
429 assert_equal ',', l(:general_csv_separator)
430 assert_equal '.', l(:general_csv_decimal_separator)
430 assert_equal '.', l(:general_csv_decimal_separator)
431 end
431 end
432 end
432 end
433
433
434 def test_index_csv_fr
434 def test_index_csv_fr
435 with_settings :default_language => "fr" do
435 with_settings :default_language => "fr" do
436 str1 = "test_index_csv_fr"
436 str1 = "test_index_csv_fr"
437 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
437 issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3,
438 :status_id => 1, :priority => IssuePriority.all.first,
438 :status_id => 1, :priority => IssuePriority.all.first,
439 :subject => str1, :estimated_hours => '1234.5')
439 :subject => str1, :estimated_hours => '1234.5')
440 assert issue.save
440 assert issue.save
441 assert_equal 1234.5, issue.estimated_hours
441 assert_equal 1234.5, issue.estimated_hours
442
442
443 get :index, :project_id => 1,
443 get :index, :project_id => 1,
444 :f => ['subject'],
444 :f => ['subject'],
445 :op => '=', :values => [str1],
445 :op => '=', :values => [str1],
446 :c => ['estimated_hours', 'subject'],
446 :c => ['estimated_hours', 'subject'],
447 :format => 'csv',
447 :format => 'csv',
448 :set_filter => 1
448 :set_filter => 1
449 assert_equal 'text/csv', @response.content_type
449 assert_equal 'text/csv', @response.content_type
450 lines = @response.body.chomp.split("\n")
450 lines = @response.body.chomp.split("\n")
451 assert_equal "#{issue.id};1234,5;#{str1}", lines[1]
451 assert_equal "#{issue.id};1234,5;#{str1}", lines[1]
452
452
453 str_fr = "Fran\xc3\xa7ais"
453 str_fr = "Fran\xc3\xa7ais"
454 if str_fr.respond_to?(:force_encoding)
454 if str_fr.respond_to?(:force_encoding)
455 str_fr.force_encoding('UTF-8')
455 str_fr.force_encoding('UTF-8')
456 end
456 end
457 assert_equal str_fr, l(:general_lang_name)
457 assert_equal str_fr, l(:general_lang_name)
458 assert_equal ';', l(:general_csv_separator)
458 assert_equal ';', l(:general_csv_separator)
459 assert_equal ',', l(:general_csv_decimal_separator)
459 assert_equal ',', l(:general_csv_decimal_separator)
460 end
460 end
461 end
461 end
462
462
463 def test_index_pdf
463 def test_index_pdf
464 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
464 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
465 with_settings :default_language => lang do
465 with_settings :default_language => lang do
466
466
467 get :index
467 get :index
468 assert_response :success
468 assert_response :success
469 assert_template 'index'
469 assert_template 'index'
470
470
471 if lang == "ja"
471 if lang == "ja"
472 if RUBY_PLATFORM != 'java'
472 if RUBY_PLATFORM != 'java'
473 assert_equal "CP932", l(:general_pdf_encoding)
473 assert_equal "CP932", l(:general_pdf_encoding)
474 end
474 end
475 if RUBY_PLATFORM == 'java' && l(:general_pdf_encoding) == "CP932"
475 if RUBY_PLATFORM == 'java' && l(:general_pdf_encoding) == "CP932"
476 next
476 next
477 end
477 end
478 end
478 end
479
479
480 get :index, :format => 'pdf'
480 get :index, :format => 'pdf'
481 assert_response :success
481 assert_response :success
482 assert_not_nil assigns(:issues)
482 assert_not_nil assigns(:issues)
483 assert_equal 'application/pdf', @response.content_type
483 assert_equal 'application/pdf', @response.content_type
484
484
485 get :index, :project_id => 1, :format => 'pdf'
485 get :index, :project_id => 1, :format => 'pdf'
486 assert_response :success
486 assert_response :success
487 assert_not_nil assigns(:issues)
487 assert_not_nil assigns(:issues)
488 assert_equal 'application/pdf', @response.content_type
488 assert_equal 'application/pdf', @response.content_type
489
489
490 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
490 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
491 assert_response :success
491 assert_response :success
492 assert_not_nil assigns(:issues)
492 assert_not_nil assigns(:issues)
493 assert_equal 'application/pdf', @response.content_type
493 assert_equal 'application/pdf', @response.content_type
494 end
494 end
495 end
495 end
496 end
496 end
497
497
498 def test_index_pdf_with_query_grouped_by_list_custom_field
498 def test_index_pdf_with_query_grouped_by_list_custom_field
499 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
499 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
500 assert_response :success
500 assert_response :success
501 assert_not_nil assigns(:issues)
501 assert_not_nil assigns(:issues)
502 assert_not_nil assigns(:issue_count_by_group)
502 assert_not_nil assigns(:issue_count_by_group)
503 assert_equal 'application/pdf', @response.content_type
503 assert_equal 'application/pdf', @response.content_type
504 end
504 end
505
505
506 def test_index_sort
506 def test_index_sort
507 get :index, :sort => 'tracker,id:desc'
507 get :index, :sort => 'tracker,id:desc'
508 assert_response :success
508 assert_response :success
509
509
510 sort_params = @request.session['issues_index_sort']
510 sort_params = @request.session['issues_index_sort']
511 assert sort_params.is_a?(String)
511 assert sort_params.is_a?(String)
512 assert_equal 'tracker,id:desc', sort_params
512 assert_equal 'tracker,id:desc', sort_params
513
513
514 issues = assigns(:issues)
514 issues = assigns(:issues)
515 assert_not_nil issues
515 assert_not_nil issues
516 assert !issues.empty?
516 assert !issues.empty?
517 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
517 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
518 end
518 end
519
519
520 def test_index_sort_by_field_not_included_in_columns
520 def test_index_sort_by_field_not_included_in_columns
521 Setting.issue_list_default_columns = %w(subject author)
521 Setting.issue_list_default_columns = %w(subject author)
522 get :index, :sort => 'tracker'
522 get :index, :sort => 'tracker'
523 end
523 end
524
524
525 def test_index_sort_by_assigned_to
525 def test_index_sort_by_assigned_to
526 get :index, :sort => 'assigned_to'
526 get :index, :sort => 'assigned_to'
527 assert_response :success
527 assert_response :success
528 assignees = assigns(:issues).collect(&:assigned_to).compact
528 assignees = assigns(:issues).collect(&:assigned_to).compact
529 assert_equal assignees.sort, assignees
529 assert_equal assignees.sort, assignees
530 end
530 end
531
531
532 def test_index_sort_by_assigned_to_desc
532 def test_index_sort_by_assigned_to_desc
533 get :index, :sort => 'assigned_to:desc'
533 get :index, :sort => 'assigned_to:desc'
534 assert_response :success
534 assert_response :success
535 assignees = assigns(:issues).collect(&:assigned_to).compact
535 assignees = assigns(:issues).collect(&:assigned_to).compact
536 assert_equal assignees.sort.reverse, assignees
536 assert_equal assignees.sort.reverse, assignees
537 end
537 end
538
538
539 def test_index_group_by_assigned_to
539 def test_index_group_by_assigned_to
540 get :index, :group_by => 'assigned_to', :sort => 'priority'
540 get :index, :group_by => 'assigned_to', :sort => 'priority'
541 assert_response :success
541 assert_response :success
542 end
542 end
543
543
544 def test_index_sort_by_author
544 def test_index_sort_by_author
545 get :index, :sort => 'author'
545 get :index, :sort => 'author'
546 assert_response :success
546 assert_response :success
547 authors = assigns(:issues).collect(&:author)
547 authors = assigns(:issues).collect(&:author)
548 assert_equal authors.sort, authors
548 assert_equal authors.sort, authors
549 end
549 end
550
550
551 def test_index_sort_by_author_desc
551 def test_index_sort_by_author_desc
552 get :index, :sort => 'author:desc'
552 get :index, :sort => 'author:desc'
553 assert_response :success
553 assert_response :success
554 authors = assigns(:issues).collect(&:author)
554 authors = assigns(:issues).collect(&:author)
555 assert_equal authors.sort.reverse, authors
555 assert_equal authors.sort.reverse, authors
556 end
556 end
557
557
558 def test_index_group_by_author
558 def test_index_group_by_author
559 get :index, :group_by => 'author', :sort => 'priority'
559 get :index, :group_by => 'author', :sort => 'priority'
560 assert_response :success
560 assert_response :success
561 end
561 end
562
562
563 def test_index_sort_by_spent_hours
563 def test_index_sort_by_spent_hours
564 get :index, :sort => 'spent_hours:desc'
564 get :index, :sort => 'spent_hours:desc'
565 assert_response :success
565 assert_response :success
566 hours = assigns(:issues).collect(&:spent_hours)
566 hours = assigns(:issues).collect(&:spent_hours)
567 assert_equal hours.sort.reverse, hours
567 assert_equal hours.sort.reverse, hours
568 end
568 end
569
569
570 def test_index_with_columns
570 def test_index_with_columns
571 columns = ['tracker', 'subject', 'assigned_to']
571 columns = ['tracker', 'subject', 'assigned_to']
572 get :index, :set_filter => 1, :c => columns
572 get :index, :set_filter => 1, :c => columns
573 assert_response :success
573 assert_response :success
574
574
575 # query should use specified columns
575 # query should use specified columns
576 query = assigns(:query)
576 query = assigns(:query)
577 assert_kind_of Query, query
577 assert_kind_of Query, query
578 assert_equal columns, query.column_names.map(&:to_s)
578 assert_equal columns, query.column_names.map(&:to_s)
579
579
580 # columns should be stored in session
580 # columns should be stored in session
581 assert_kind_of Hash, session[:query]
581 assert_kind_of Hash, session[:query]
582 assert_kind_of Array, session[:query][:column_names]
582 assert_kind_of Array, session[:query][:column_names]
583 assert_equal columns, session[:query][:column_names].map(&:to_s)
583 assert_equal columns, session[:query][:column_names].map(&:to_s)
584
584
585 # ensure only these columns are kept in the selected columns list
585 # ensure only these columns are kept in the selected columns list
586 assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
586 assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
587 :children => { :count => 3 }
587 :children => { :count => 3 }
588 assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
588 assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
589 :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
589 :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
590 end
590 end
591
591
592 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
592 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
593 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
593 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
594 get :index, :set_filter => 1
594 get :index, :set_filter => 1
595
595
596 # query should use specified columns
596 # query should use specified columns
597 query = assigns(:query)
597 query = assigns(:query)
598 assert_kind_of Query, query
598 assert_kind_of Query, query
599 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
599 assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
600 end
600 end
601
601
602 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
602 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
603 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
603 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
604 columns = ['tracker', 'subject', 'assigned_to']
604 columns = ['tracker', 'subject', 'assigned_to']
605 get :index, :set_filter => 1, :c => columns
605 get :index, :set_filter => 1, :c => columns
606
606
607 # query should use specified columns
607 # query should use specified columns
608 query = assigns(:query)
608 query = assigns(:query)
609 assert_kind_of Query, query
609 assert_kind_of Query, query
610 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
610 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
611 end
611 end
612
612
613 def test_index_with_custom_field_column
613 def test_index_with_custom_field_column
614 columns = %w(tracker subject cf_2)
614 columns = %w(tracker subject cf_2)
615 get :index, :set_filter => 1, :c => columns
615 get :index, :set_filter => 1, :c => columns
616 assert_response :success
616 assert_response :success
617
617
618 # query should use specified columns
618 # query should use specified columns
619 query = assigns(:query)
619 query = assigns(:query)
620 assert_kind_of Query, query
620 assert_kind_of Query, query
621 assert_equal columns, query.column_names.map(&:to_s)
621 assert_equal columns, query.column_names.map(&:to_s)
622
622
623 assert_tag :td,
623 assert_tag :td,
624 :attributes => {:class => 'cf_2 string'},
624 :attributes => {:class => 'cf_2 string'},
625 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
625 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
626 end
626 end
627
627
628 def test_index_with_date_column
628 def test_index_with_date_column
629 Issue.find(1).update_attribute :start_date, '1987-08-24'
629 Issue.find(1).update_attribute :start_date, '1987-08-24'
630
630
631 with_settings :date_format => '%d/%m/%Y' do
631 with_settings :date_format => '%d/%m/%Y' do
632 get :index, :set_filter => 1, :c => %w(start_date)
632 get :index, :set_filter => 1, :c => %w(start_date)
633 assert_tag 'td', :attributes => {:class => /start_date/}, :content => '24/08/1987'
633 assert_tag 'td', :attributes => {:class => /start_date/}, :content => '24/08/1987'
634 end
634 end
635 end
635 end
636
636
637 def test_index_with_done_ratio
637 def test_index_with_done_ratio
638 Issue.find(1).update_attribute :done_ratio, 40
638 Issue.find(1).update_attribute :done_ratio, 40
639
639
640 get :index, :set_filter => 1, :c => %w(done_ratio)
640 get :index, :set_filter => 1, :c => %w(done_ratio)
641 assert_tag 'td', :attributes => {:class => /done_ratio/},
641 assert_tag 'td', :attributes => {:class => /done_ratio/},
642 :child => {:tag => 'table', :attributes => {:class => 'progress'},
642 :child => {:tag => 'table', :attributes => {:class => 'progress'},
643 :descendant => {:tag => 'td', :attributes => {:class => 'closed', :style => 'width: 40%;'}}
643 :descendant => {:tag => 'td', :attributes => {:class => 'closed', :style => 'width: 40%;'}}
644 }
644 }
645 end
645 end
646
646
647 def test_index_with_spent_hours_column
647 def test_index_with_spent_hours_column
648 get :index, :set_filter => 1, :c => %w(subject spent_hours)
648 get :index, :set_filter => 1, :c => %w(subject spent_hours)
649
649
650 assert_tag 'tr', :attributes => {:id => 'issue-3'},
650 assert_tag 'tr', :attributes => {:id => 'issue-3'},
651 :child => {
651 :child => {
652 :tag => 'td', :attributes => {:class => /spent_hours/}, :content => '1.00'
652 :tag => 'td', :attributes => {:class => /spent_hours/}, :content => '1.00'
653 }
653 }
654 end
654 end
655
655
656 def test_index_should_not_show_spent_hours_column_without_permission
656 def test_index_should_not_show_spent_hours_column_without_permission
657 Role.anonymous.remove_permission! :view_time_entries
657 Role.anonymous.remove_permission! :view_time_entries
658 get :index, :set_filter => 1, :c => %w(subject spent_hours)
658 get :index, :set_filter => 1, :c => %w(subject spent_hours)
659
659
660 assert_no_tag 'td', :attributes => {:class => /spent_hours/}
660 assert_no_tag 'td', :attributes => {:class => /spent_hours/}
661 end
661 end
662
662
663 def test_index_with_fixed_version
663 def test_index_with_fixed_version
664 get :index, :set_filter => 1, :c => %w(fixed_version)
664 get :index, :set_filter => 1, :c => %w(fixed_version)
665 assert_tag 'td', :attributes => {:class => /fixed_version/},
665 assert_tag 'td', :attributes => {:class => /fixed_version/},
666 :child => {:tag => 'a', :content => '1.0', :attributes => {:href => '/versions/2'}}
666 :child => {:tag => 'a', :content => '1.0', :attributes => {:href => '/versions/2'}}
667 end
667 end
668
668
669 def test_index_send_html_if_query_is_invalid
669 def test_index_send_html_if_query_is_invalid
670 get :index, :f => ['start_date'], :op => {:start_date => '='}
670 get :index, :f => ['start_date'], :op => {:start_date => '='}
671 assert_equal 'text/html', @response.content_type
671 assert_equal 'text/html', @response.content_type
672 assert_template 'index'
672 assert_template 'index'
673 end
673 end
674
674
675 def test_index_send_nothing_if_query_is_invalid
675 def test_index_send_nothing_if_query_is_invalid
676 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
676 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
677 assert_equal 'text/csv', @response.content_type
677 assert_equal 'text/csv', @response.content_type
678 assert @response.body.blank?
678 assert @response.body.blank?
679 end
679 end
680
680
681 def test_show_by_anonymous
681 def test_show_by_anonymous
682 get :show, :id => 1
682 get :show, :id => 1
683 assert_response :success
683 assert_response :success
684 assert_template 'show'
684 assert_template 'show'
685 assert_not_nil assigns(:issue)
685 assert_not_nil assigns(:issue)
686 assert_equal Issue.find(1), assigns(:issue)
686 assert_equal Issue.find(1), assigns(:issue)
687
687
688 # anonymous role is allowed to add a note
688 # anonymous role is allowed to add a note
689 assert_tag :tag => 'form',
689 assert_tag :tag => 'form',
690 :descendant => { :tag => 'fieldset',
690 :descendant => { :tag => 'fieldset',
691 :child => { :tag => 'legend',
691 :child => { :tag => 'legend',
692 :content => /Notes/ } }
692 :content => /Notes/ } }
693 assert_tag :tag => 'title',
693 assert_tag :tag => 'title',
694 :content => "Bug #1: Can't print recipes - eCookbook - Redmine"
694 :content => "Bug #1: Can't print recipes - eCookbook - Redmine"
695 end
695 end
696
696
697 def test_show_by_manager
697 def test_show_by_manager
698 @request.session[:user_id] = 2
698 @request.session[:user_id] = 2
699 get :show, :id => 1
699 get :show, :id => 1
700 assert_response :success
700 assert_response :success
701
701
702 assert_tag :tag => 'a',
702 assert_tag :tag => 'a',
703 :content => /Quote/
703 :content => /Quote/
704
704
705 assert_tag :tag => 'form',
705 assert_tag :tag => 'form',
706 :descendant => { :tag => 'fieldset',
706 :descendant => { :tag => 'fieldset',
707 :child => { :tag => 'legend',
707 :child => { :tag => 'legend',
708 :content => /Change properties/ } },
708 :content => /Change properties/ } },
709 :descendant => { :tag => 'fieldset',
709 :descendant => { :tag => 'fieldset',
710 :child => { :tag => 'legend',
710 :child => { :tag => 'legend',
711 :content => /Log time/ } },
711 :content => /Log time/ } },
712 :descendant => { :tag => 'fieldset',
712 :descendant => { :tag => 'fieldset',
713 :child => { :tag => 'legend',
713 :child => { :tag => 'legend',
714 :content => /Notes/ } }
714 :content => /Notes/ } }
715 end
715 end
716
716
717 def test_update_form_should_not_display_inactive_enumerations
717 def test_update_form_should_not_display_inactive_enumerations
718 @request.session[:user_id] = 2
718 @request.session[:user_id] = 2
719 get :show, :id => 1
719 get :show, :id => 1
720 assert_response :success
720 assert_response :success
721
721
722 assert ! IssuePriority.find(15).active?
722 assert ! IssuePriority.find(15).active?
723 assert_no_tag :option, :attributes => {:value => '15'},
723 assert_no_tag :option, :attributes => {:value => '15'},
724 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
724 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
725 end
725 end
726
726
727 def test_update_form_should_allow_attachment_upload
727 def test_update_form_should_allow_attachment_upload
728 @request.session[:user_id] = 2
728 @request.session[:user_id] = 2
729 get :show, :id => 1
729 get :show, :id => 1
730
730
731 assert_tag :tag => 'form',
731 assert_tag :tag => 'form',
732 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
732 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
733 :descendant => {
733 :descendant => {
734 :tag => 'input',
734 :tag => 'input',
735 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
735 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
736 }
736 }
737 end
737 end
738
738
739 def test_show_should_deny_anonymous_access_without_permission
739 def test_show_should_deny_anonymous_access_without_permission
740 Role.anonymous.remove_permission!(:view_issues)
740 Role.anonymous.remove_permission!(:view_issues)
741 get :show, :id => 1
741 get :show, :id => 1
742 assert_response :redirect
742 assert_response :redirect
743 end
743 end
744
744
745 def test_show_should_deny_anonymous_access_to_private_issue
745 def test_show_should_deny_anonymous_access_to_private_issue
746 Issue.update_all(["is_private = ?", true], "id = 1")
746 Issue.update_all(["is_private = ?", true], "id = 1")
747 get :show, :id => 1
747 get :show, :id => 1
748 assert_response :redirect
748 assert_response :redirect
749 end
749 end
750
750
751 def test_show_should_deny_non_member_access_without_permission
751 def test_show_should_deny_non_member_access_without_permission
752 Role.non_member.remove_permission!(:view_issues)
752 Role.non_member.remove_permission!(:view_issues)
753 @request.session[:user_id] = 9
753 @request.session[:user_id] = 9
754 get :show, :id => 1
754 get :show, :id => 1
755 assert_response 403
755 assert_response 403
756 end
756 end
757
757
758 def test_show_should_deny_non_member_access_to_private_issue
758 def test_show_should_deny_non_member_access_to_private_issue
759 Issue.update_all(["is_private = ?", true], "id = 1")
759 Issue.update_all(["is_private = ?", true], "id = 1")
760 @request.session[:user_id] = 9
760 @request.session[:user_id] = 9
761 get :show, :id => 1
761 get :show, :id => 1
762 assert_response 403
762 assert_response 403
763 end
763 end
764
764
765 def test_show_should_deny_member_access_without_permission
765 def test_show_should_deny_member_access_without_permission
766 Role.find(1).remove_permission!(:view_issues)
766 Role.find(1).remove_permission!(:view_issues)
767 @request.session[:user_id] = 2
767 @request.session[:user_id] = 2
768 get :show, :id => 1
768 get :show, :id => 1
769 assert_response 403
769 assert_response 403
770 end
770 end
771
771
772 def test_show_should_deny_member_access_to_private_issue_without_permission
772 def test_show_should_deny_member_access_to_private_issue_without_permission
773 Issue.update_all(["is_private = ?", true], "id = 1")
773 Issue.update_all(["is_private = ?", true], "id = 1")
774 @request.session[:user_id] = 3
774 @request.session[:user_id] = 3
775 get :show, :id => 1
775 get :show, :id => 1
776 assert_response 403
776 assert_response 403
777 end
777 end
778
778
779 def test_show_should_allow_author_access_to_private_issue
779 def test_show_should_allow_author_access_to_private_issue
780 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
780 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
781 @request.session[:user_id] = 3
781 @request.session[:user_id] = 3
782 get :show, :id => 1
782 get :show, :id => 1
783 assert_response :success
783 assert_response :success
784 end
784 end
785
785
786 def test_show_should_allow_assignee_access_to_private_issue
786 def test_show_should_allow_assignee_access_to_private_issue
787 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
787 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
788 @request.session[:user_id] = 3
788 @request.session[:user_id] = 3
789 get :show, :id => 1
789 get :show, :id => 1
790 assert_response :success
790 assert_response :success
791 end
791 end
792
792
793 def test_show_should_allow_member_access_to_private_issue_with_permission
793 def test_show_should_allow_member_access_to_private_issue_with_permission
794 Issue.update_all(["is_private = ?", true], "id = 1")
794 Issue.update_all(["is_private = ?", true], "id = 1")
795 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
795 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
796 @request.session[:user_id] = 3
796 @request.session[:user_id] = 3
797 get :show, :id => 1
797 get :show, :id => 1
798 assert_response :success
798 assert_response :success
799 end
799 end
800
800
801 def test_show_should_not_disclose_relations_to_invisible_issues
801 def test_show_should_not_disclose_relations_to_invisible_issues
802 Setting.cross_project_issue_relations = '1'
802 Setting.cross_project_issue_relations = '1'
803 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
803 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
804 # Relation to a private project issue
804 # Relation to a private project issue
805 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
805 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
806
806
807 get :show, :id => 1
807 get :show, :id => 1
808 assert_response :success
808 assert_response :success
809
809
810 assert_tag :div, :attributes => { :id => 'relations' },
810 assert_tag :div, :attributes => { :id => 'relations' },
811 :descendant => { :tag => 'a', :content => /#2$/ }
811 :descendant => { :tag => 'a', :content => /#2$/ }
812 assert_no_tag :div, :attributes => { :id => 'relations' },
812 assert_no_tag :div, :attributes => { :id => 'relations' },
813 :descendant => { :tag => 'a', :content => /#4$/ }
813 :descendant => { :tag => 'a', :content => /#4$/ }
814 end
814 end
815
815
816 def test_show_should_list_subtasks
816 def test_show_should_list_subtasks
817 Issue.generate!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
817 Issue.generate!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
818
818
819 get :show, :id => 1
819 get :show, :id => 1
820 assert_response :success
820 assert_response :success
821 assert_tag 'div', :attributes => {:id => 'issue_tree'},
821 assert_tag 'div', :attributes => {:id => 'issue_tree'},
822 :descendant => {:tag => 'td', :content => /Child Issue/, :attributes => {:class => /subject/}}
822 :descendant => {:tag => 'td', :content => /Child Issue/, :attributes => {:class => /subject/}}
823 end
823 end
824
824
825 def test_show_should_list_parents
825 def test_show_should_list_parents
826 issue = Issue.generate!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
826 issue = Issue.generate!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
827
827
828 get :show, :id => issue.id
828 get :show, :id => issue.id
829 assert_response :success
829 assert_response :success
830 assert_tag 'div', :attributes => {:class => 'subject'},
830 assert_tag 'div', :attributes => {:class => 'subject'},
831 :descendant => {:tag => 'h3', :content => 'Child Issue'}
831 :descendant => {:tag => 'h3', :content => 'Child Issue'}
832 assert_tag 'div', :attributes => {:class => 'subject'},
832 assert_tag 'div', :attributes => {:class => 'subject'},
833 :descendant => {:tag => 'a', :attributes => {:href => '/issues/1'}}
833 :descendant => {:tag => 'a', :attributes => {:href => '/issues/1'}}
834 end
834 end
835
835
836 def test_show_atom
836 def test_show_atom
837 get :show, :id => 2, :format => 'atom'
837 get :show, :id => 2, :format => 'atom'
838 assert_response :success
838 assert_response :success
839 assert_template 'journals/index'
839 assert_template 'journals/index'
840 # Inline image
840 # Inline image
841 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
841 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
842 end
842 end
843
843
844 def test_show_export_to_pdf
844 def test_show_export_to_pdf
845 get :show, :id => 3, :format => 'pdf'
845 get :show, :id => 3, :format => 'pdf'
846 assert_response :success
846 assert_response :success
847 assert_equal 'application/pdf', @response.content_type
847 assert_equal 'application/pdf', @response.content_type
848 assert @response.body.starts_with?('%PDF')
848 assert @response.body.starts_with?('%PDF')
849 assert_not_nil assigns(:issue)
849 assert_not_nil assigns(:issue)
850 end
850 end
851
851
852 def test_get_new
852 def test_get_new
853 @request.session[:user_id] = 2
853 @request.session[:user_id] = 2
854 get :new, :project_id => 1, :tracker_id => 1
854 get :new, :project_id => 1, :tracker_id => 1
855 assert_response :success
855 assert_response :success
856 assert_template 'new'
856 assert_template 'new'
857
857
858 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
858 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
859 :value => 'Default string' }
859 :value => 'Default string' }
860
860
861 # Be sure we don't display inactive IssuePriorities
861 # Be sure we don't display inactive IssuePriorities
862 assert ! IssuePriority.find(15).active?
862 assert ! IssuePriority.find(15).active?
863 assert_no_tag :option, :attributes => {:value => '15'},
863 assert_no_tag :option, :attributes => {:value => '15'},
864 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
864 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
865 end
865 end
866
866
867 def test_get_new_without_default_start_date_is_creation_date
867 def test_get_new_without_default_start_date_is_creation_date
868 Setting.default_issue_start_date_to_creation_date = 0
868 Setting.default_issue_start_date_to_creation_date = 0
869
869
870 @request.session[:user_id] = 2
870 @request.session[:user_id] = 2
871 get :new, :project_id => 1, :tracker_id => 1
871 get :new, :project_id => 1, :tracker_id => 1
872 assert_response :success
872 assert_response :success
873 assert_template 'new'
873 assert_template 'new'
874
874
875 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
875 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
876 :value => nil }
876 :value => nil }
877 end
877 end
878
878
879 def test_get_new_with_default_start_date_is_creation_date
879 def test_get_new_with_default_start_date_is_creation_date
880 Setting.default_issue_start_date_to_creation_date = 1
880 Setting.default_issue_start_date_to_creation_date = 1
881
881
882 @request.session[:user_id] = 2
882 @request.session[:user_id] = 2
883 get :new, :project_id => 1, :tracker_id => 1
883 get :new, :project_id => 1, :tracker_id => 1
884 assert_response :success
884 assert_response :success
885 assert_template 'new'
885 assert_template 'new'
886
886
887 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
887 assert_tag :tag => 'input', :attributes => { :name => 'issue[start_date]',
888 :value => Date.today.to_s }
888 :value => Date.today.to_s }
889 end
889 end
890
890
891 def test_get_new_form_should_allow_attachment_upload
891 def test_get_new_form_should_allow_attachment_upload
892 @request.session[:user_id] = 2
892 @request.session[:user_id] = 2
893 get :new, :project_id => 1, :tracker_id => 1
893 get :new, :project_id => 1, :tracker_id => 1
894
894
895 assert_tag :tag => 'form',
895 assert_tag :tag => 'form',
896 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
896 :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
897 :descendant => {
897 :descendant => {
898 :tag => 'input',
898 :tag => 'input',
899 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
899 :attributes => {:type => 'file', :name => 'attachments[1][file]'}
900 }
900 }
901 end
901 end
902
902
903 def test_get_new_without_tracker_id
903 def test_get_new_without_tracker_id
904 @request.session[:user_id] = 2
904 @request.session[:user_id] = 2
905 get :new, :project_id => 1
905 get :new, :project_id => 1
906 assert_response :success
906 assert_response :success
907 assert_template 'new'
907 assert_template 'new'
908
908
909 issue = assigns(:issue)
909 issue = assigns(:issue)
910 assert_not_nil issue
910 assert_not_nil issue
911 assert_equal Project.find(1).trackers.first, issue.tracker
911 assert_equal Project.find(1).trackers.first, issue.tracker
912 end
912 end
913
913
914 def test_get_new_with_no_default_status_should_display_an_error
914 def test_get_new_with_no_default_status_should_display_an_error
915 @request.session[:user_id] = 2
915 @request.session[:user_id] = 2
916 IssueStatus.delete_all
916 IssueStatus.delete_all
917
917
918 get :new, :project_id => 1
918 get :new, :project_id => 1
919 assert_response 500
919 assert_response 500
920 assert_error_tag :content => /No default issue/
920 assert_error_tag :content => /No default issue/
921 end
921 end
922
922
923 def test_get_new_with_no_tracker_should_display_an_error
923 def test_get_new_with_no_tracker_should_display_an_error
924 @request.session[:user_id] = 2
924 @request.session[:user_id] = 2
925 Tracker.delete_all
925 Tracker.delete_all
926
926
927 get :new, :project_id => 1
927 get :new, :project_id => 1
928 assert_response 500
928 assert_response 500
929 assert_error_tag :content => /No tracker/
929 assert_error_tag :content => /No tracker/
930 end
930 end
931
931
932 def test_update_new_form
932 def test_update_new_form
933 @request.session[:user_id] = 2
933 @request.session[:user_id] = 2
934 xhr :post, :new, :project_id => 1,
934 xhr :post, :new, :project_id => 1,
935 :issue => {:tracker_id => 2,
935 :issue => {:tracker_id => 2,
936 :subject => 'This is the test_new issue',
936 :subject => 'This is the test_new issue',
937 :description => 'This is the description',
937 :description => 'This is the description',
938 :priority_id => 5}
938 :priority_id => 5}
939 assert_response :success
939 assert_response :success
940 assert_template 'attributes'
940 assert_template 'attributes'
941
941
942 issue = assigns(:issue)
942 issue = assigns(:issue)
943 assert_kind_of Issue, issue
943 assert_kind_of Issue, issue
944 assert_equal 1, issue.project_id
944 assert_equal 1, issue.project_id
945 assert_equal 2, issue.tracker_id
945 assert_equal 2, issue.tracker_id
946 assert_equal 'This is the test_new issue', issue.subject
946 assert_equal 'This is the test_new issue', issue.subject
947 end
947 end
948
948
949 def test_post_create
949 def test_post_create
950 @request.session[:user_id] = 2
950 @request.session[:user_id] = 2
951 assert_difference 'Issue.count' do
951 assert_difference 'Issue.count' do
952 post :create, :project_id => 1,
952 post :create, :project_id => 1,
953 :issue => {:tracker_id => 3,
953 :issue => {:tracker_id => 3,
954 :status_id => 2,
954 :status_id => 2,
955 :subject => 'This is the test_new issue',
955 :subject => 'This is the test_new issue',
956 :description => 'This is the description',
956 :description => 'This is the description',
957 :priority_id => 5,
957 :priority_id => 5,
958 :start_date => '2010-11-07',
958 :start_date => '2010-11-07',
959 :estimated_hours => '',
959 :estimated_hours => '',
960 :custom_field_values => {'2' => 'Value for field 2'}}
960 :custom_field_values => {'2' => 'Value for field 2'}}
961 end
961 end
962 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
962 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
963
963
964 issue = Issue.find_by_subject('This is the test_new issue')
964 issue = Issue.find_by_subject('This is the test_new issue')
965 assert_not_nil issue
965 assert_not_nil issue
966 assert_equal 2, issue.author_id
966 assert_equal 2, issue.author_id
967 assert_equal 3, issue.tracker_id
967 assert_equal 3, issue.tracker_id
968 assert_equal 2, issue.status_id
968 assert_equal 2, issue.status_id
969 assert_equal Date.parse('2010-11-07'), issue.start_date
969 assert_equal Date.parse('2010-11-07'), issue.start_date
970 assert_nil issue.estimated_hours
970 assert_nil issue.estimated_hours
971 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
971 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
972 assert_not_nil v
972 assert_not_nil v
973 assert_equal 'Value for field 2', v.value
973 assert_equal 'Value for field 2', v.value
974 end
974 end
975
975
976 def test_post_new_with_group_assignment
976 def test_post_new_with_group_assignment
977 group = Group.find(11)
977 group = Group.find(11)
978 project = Project.find(1)
978 project = Project.find(1)
979 project.members << Member.new(:principal => group, :roles => [Role.first])
979 project.members << Member.new(:principal => group, :roles => [Role.first])
980
980
981 with_settings :issue_group_assignment => '1' do
981 with_settings :issue_group_assignment => '1' do
982 @request.session[:user_id] = 2
982 @request.session[:user_id] = 2
983 assert_difference 'Issue.count' do
983 assert_difference 'Issue.count' do
984 post :create, :project_id => project.id,
984 post :create, :project_id => project.id,
985 :issue => {:tracker_id => 3,
985 :issue => {:tracker_id => 3,
986 :status_id => 1,
986 :status_id => 1,
987 :subject => 'This is the test_new_with_group_assignment issue',
987 :subject => 'This is the test_new_with_group_assignment issue',
988 :assigned_to_id => group.id}
988 :assigned_to_id => group.id}
989 end
989 end
990 end
990 end
991 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
991 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
992
992
993 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
993 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
994 assert_not_nil issue
994 assert_not_nil issue
995 assert_equal group, issue.assigned_to
995 assert_equal group, issue.assigned_to
996 end
996 end
997
997
998 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
998 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
999 Setting.default_issue_start_date_to_creation_date = 0
999 Setting.default_issue_start_date_to_creation_date = 0
1000
1000
1001 @request.session[:user_id] = 2
1001 @request.session[:user_id] = 2
1002 assert_difference 'Issue.count' do
1002 assert_difference 'Issue.count' do
1003 post :create, :project_id => 1,
1003 post :create, :project_id => 1,
1004 :issue => {:tracker_id => 3,
1004 :issue => {:tracker_id => 3,
1005 :status_id => 2,
1005 :status_id => 2,
1006 :subject => 'This is the test_new issue',
1006 :subject => 'This is the test_new issue',
1007 :description => 'This is the description',
1007 :description => 'This is the description',
1008 :priority_id => 5,
1008 :priority_id => 5,
1009 :estimated_hours => '',
1009 :estimated_hours => '',
1010 :custom_field_values => {'2' => 'Value for field 2'}}
1010 :custom_field_values => {'2' => 'Value for field 2'}}
1011 end
1011 end
1012 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1012 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1013
1013
1014 issue = Issue.find_by_subject('This is the test_new issue')
1014 issue = Issue.find_by_subject('This is the test_new issue')
1015 assert_not_nil issue
1015 assert_not_nil issue
1016 assert_nil issue.start_date
1016 assert_nil issue.start_date
1017 end
1017 end
1018
1018
1019 def test_post_create_without_start_date_and_default_start_date_is_creation_date
1019 def test_post_create_without_start_date_and_default_start_date_is_creation_date
1020 Setting.default_issue_start_date_to_creation_date = 1
1020 Setting.default_issue_start_date_to_creation_date = 1
1021
1021
1022 @request.session[:user_id] = 2
1022 @request.session[:user_id] = 2
1023 assert_difference 'Issue.count' do
1023 assert_difference 'Issue.count' do
1024 post :create, :project_id => 1,
1024 post :create, :project_id => 1,
1025 :issue => {:tracker_id => 3,
1025 :issue => {:tracker_id => 3,
1026 :status_id => 2,
1026 :status_id => 2,
1027 :subject => 'This is the test_new issue',
1027 :subject => 'This is the test_new issue',
1028 :description => 'This is the description',
1028 :description => 'This is the description',
1029 :priority_id => 5,
1029 :priority_id => 5,
1030 :estimated_hours => '',
1030 :estimated_hours => '',
1031 :custom_field_values => {'2' => 'Value for field 2'}}
1031 :custom_field_values => {'2' => 'Value for field 2'}}
1032 end
1032 end
1033 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1033 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1034
1034
1035 issue = Issue.find_by_subject('This is the test_new issue')
1035 issue = Issue.find_by_subject('This is the test_new issue')
1036 assert_not_nil issue
1036 assert_not_nil issue
1037 assert_equal Date.today, issue.start_date
1037 assert_equal Date.today, issue.start_date
1038 end
1038 end
1039
1039
1040 def test_post_create_and_continue
1040 def test_post_create_and_continue
1041 @request.session[:user_id] = 2
1041 @request.session[:user_id] = 2
1042 assert_difference 'Issue.count' do
1042 assert_difference 'Issue.count' do
1043 post :create, :project_id => 1,
1043 post :create, :project_id => 1,
1044 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
1044 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
1045 :continue => ''
1045 :continue => ''
1046 end
1046 end
1047
1047
1048 issue = Issue.first(:order => 'id DESC')
1048 issue = Issue.first(:order => 'id DESC')
1049 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
1049 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
1050 assert_not_nil flash[:notice], "flash was not set"
1050 assert_not_nil flash[:notice], "flash was not set"
1051 assert flash[:notice].include?("<a href='/issues/#{issue.id}'>##{issue.id}</a>"), "issue link not found in flash: #{flash[:notice]}"
1051 assert flash[:notice].include?("<a href='/issues/#{issue.id}'>##{issue.id}</a>"), "issue link not found in flash: #{flash[:notice]}"
1052 end
1052 end
1053
1053
1054 def test_post_create_without_custom_fields_param
1054 def test_post_create_without_custom_fields_param
1055 @request.session[:user_id] = 2
1055 @request.session[:user_id] = 2
1056 assert_difference 'Issue.count' do
1056 assert_difference 'Issue.count' do
1057 post :create, :project_id => 1,
1057 post :create, :project_id => 1,
1058 :issue => {:tracker_id => 1,
1058 :issue => {:tracker_id => 1,
1059 :subject => 'This is the test_new issue',
1059 :subject => 'This is the test_new issue',
1060 :description => 'This is the description',
1060 :description => 'This is the description',
1061 :priority_id => 5}
1061 :priority_id => 5}
1062 end
1062 end
1063 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1063 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1064 end
1064 end
1065
1065
1066 def test_post_create_with_required_custom_field_and_without_custom_fields_param
1066 def test_post_create_with_required_custom_field_and_without_custom_fields_param
1067 field = IssueCustomField.find_by_name('Database')
1067 field = IssueCustomField.find_by_name('Database')
1068 field.update_attribute(:is_required, true)
1068 field.update_attribute(:is_required, true)
1069
1069
1070 @request.session[:user_id] = 2
1070 @request.session[:user_id] = 2
1071 post :create, :project_id => 1,
1071 post :create, :project_id => 1,
1072 :issue => {:tracker_id => 1,
1072 :issue => {:tracker_id => 1,
1073 :subject => 'This is the test_new issue',
1073 :subject => 'This is the test_new issue',
1074 :description => 'This is the description',
1074 :description => 'This is the description',
1075 :priority_id => 5}
1075 :priority_id => 5}
1076 assert_response :success
1076 assert_response :success
1077 assert_template 'new'
1077 assert_template 'new'
1078 issue = assigns(:issue)
1078 issue = assigns(:issue)
1079 assert_not_nil issue
1079 assert_not_nil issue
1080 assert_equal I18n.translate('activerecord.errors.messages.invalid'),
1080 assert_equal I18n.translate('activerecord.errors.messages.invalid'),
1081 issue.errors[:custom_values].to_s
1081 issue.errors[:custom_values].to_s
1082 end
1082 end
1083
1083
1084 def test_post_create_with_watchers
1084 def test_post_create_with_watchers
1085 @request.session[:user_id] = 2
1085 @request.session[:user_id] = 2
1086 ActionMailer::Base.deliveries.clear
1086 ActionMailer::Base.deliveries.clear
1087
1087
1088 assert_difference 'Watcher.count', 2 do
1088 assert_difference 'Watcher.count', 2 do
1089 post :create, :project_id => 1,
1089 post :create, :project_id => 1,
1090 :issue => {:tracker_id => 1,
1090 :issue => {:tracker_id => 1,
1091 :subject => 'This is a new issue with watchers',
1091 :subject => 'This is a new issue with watchers',
1092 :description => 'This is the description',
1092 :description => 'This is the description',
1093 :priority_id => 5,
1093 :priority_id => 5,
1094 :watcher_user_ids => ['2', '3']}
1094 :watcher_user_ids => ['2', '3']}
1095 end
1095 end
1096 issue = Issue.find_by_subject('This is a new issue with watchers')
1096 issue = Issue.find_by_subject('This is a new issue with watchers')
1097 assert_not_nil issue
1097 assert_not_nil issue
1098 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
1098 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
1099
1099
1100 # Watchers added
1100 # Watchers added
1101 assert_equal [2, 3], issue.watcher_user_ids.sort
1101 assert_equal [2, 3], issue.watcher_user_ids.sort
1102 assert issue.watched_by?(User.find(3))
1102 assert issue.watched_by?(User.find(3))
1103 # Watchers notified
1103 # Watchers notified
1104 mail = ActionMailer::Base.deliveries.last
1104 mail = ActionMailer::Base.deliveries.last
1105 assert_kind_of TMail::Mail, mail
1105 assert_kind_of TMail::Mail, mail
1106 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
1106 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
1107 end
1107 end
1108
1108
1109 def test_post_create_subissue
1109 def test_post_create_subissue
1110 @request.session[:user_id] = 2
1110 @request.session[:user_id] = 2
1111
1111
1112 assert_difference 'Issue.count' do
1112 assert_difference 'Issue.count' do
1113 post :create, :project_id => 1,
1113 post :create, :project_id => 1,
1114 :issue => {:tracker_id => 1,
1114 :issue => {:tracker_id => 1,
1115 :subject => 'This is a child issue',
1115 :subject => 'This is a child issue',
1116 :parent_issue_id => 2}
1116 :parent_issue_id => 2}
1117 end
1117 end
1118 issue = Issue.find_by_subject('This is a child issue')
1118 issue = Issue.find_by_subject('This is a child issue')
1119 assert_not_nil issue
1119 assert_not_nil issue
1120 assert_equal Issue.find(2), issue.parent
1120 assert_equal Issue.find(2), issue.parent
1121 end
1121 end
1122
1122
1123 def test_post_create_subissue_with_non_numeric_parent_id
1123 def test_post_create_subissue_with_non_numeric_parent_id
1124 @request.session[:user_id] = 2
1124 @request.session[:user_id] = 2
1125
1125
1126 assert_difference 'Issue.count' do
1126 assert_difference 'Issue.count' do
1127 post :create, :project_id => 1,
1127 post :create, :project_id => 1,
1128 :issue => {:tracker_id => 1,
1128 :issue => {:tracker_id => 1,
1129 :subject => 'This is a child issue',
1129 :subject => 'This is a child issue',
1130 :parent_issue_id => 'ABC'}
1130 :parent_issue_id => 'ABC'}
1131 end
1131 end
1132 issue = Issue.find_by_subject('This is a child issue')
1132 issue = Issue.find_by_subject('This is a child issue')
1133 assert_not_nil issue
1133 assert_not_nil issue
1134 assert_nil issue.parent
1134 assert_nil issue.parent
1135 end
1135 end
1136
1136
1137 def test_post_create_private
1137 def test_post_create_private
1138 @request.session[:user_id] = 2
1138 @request.session[:user_id] = 2
1139
1139
1140 assert_difference 'Issue.count' do
1140 assert_difference 'Issue.count' do
1141 post :create, :project_id => 1,
1141 post :create, :project_id => 1,
1142 :issue => {:tracker_id => 1,
1142 :issue => {:tracker_id => 1,
1143 :subject => 'This is a private issue',
1143 :subject => 'This is a private issue',
1144 :is_private => '1'}
1144 :is_private => '1'}
1145 end
1145 end
1146 issue = Issue.first(:order => 'id DESC')
1146 issue = Issue.first(:order => 'id DESC')
1147 assert issue.is_private?
1147 assert issue.is_private?
1148 end
1148 end
1149
1149
1150 def test_post_create_private_with_set_own_issues_private_permission
1150 def test_post_create_private_with_set_own_issues_private_permission
1151 role = Role.find(1)
1151 role = Role.find(1)
1152 role.remove_permission! :set_issues_private
1152 role.remove_permission! :set_issues_private
1153 role.add_permission! :set_own_issues_private
1153 role.add_permission! :set_own_issues_private
1154
1154
1155 @request.session[:user_id] = 2
1155 @request.session[:user_id] = 2
1156
1156
1157 assert_difference 'Issue.count' do
1157 assert_difference 'Issue.count' do
1158 post :create, :project_id => 1,
1158 post :create, :project_id => 1,
1159 :issue => {:tracker_id => 1,
1159 :issue => {:tracker_id => 1,
1160 :subject => 'This is a private issue',
1160 :subject => 'This is a private issue',
1161 :is_private => '1'}
1161 :is_private => '1'}
1162 end
1162 end
1163 issue = Issue.first(:order => 'id DESC')
1163 issue = Issue.first(:order => 'id DESC')
1164 assert issue.is_private?
1164 assert issue.is_private?
1165 end
1165 end
1166
1166
1167 def test_post_create_should_send_a_notification
1167 def test_post_create_should_send_a_notification
1168 ActionMailer::Base.deliveries.clear
1168 ActionMailer::Base.deliveries.clear
1169 @request.session[:user_id] = 2
1169 @request.session[:user_id] = 2
1170 assert_difference 'Issue.count' do
1170 assert_difference 'Issue.count' do
1171 post :create, :project_id => 1,
1171 post :create, :project_id => 1,
1172 :issue => {:tracker_id => 3,
1172 :issue => {:tracker_id => 3,
1173 :subject => 'This is the test_new issue',
1173 :subject => 'This is the test_new issue',
1174 :description => 'This is the description',
1174 :description => 'This is the description',
1175 :priority_id => 5,
1175 :priority_id => 5,
1176 :estimated_hours => '',
1176 :estimated_hours => '',
1177 :custom_field_values => {'2' => 'Value for field 2'}}
1177 :custom_field_values => {'2' => 'Value for field 2'}}
1178 end
1178 end
1179 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1179 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
1180
1180
1181 assert_equal 1, ActionMailer::Base.deliveries.size
1181 assert_equal 1, ActionMailer::Base.deliveries.size
1182 end
1182 end
1183
1183
1184 def test_post_create_should_preserve_fields_values_on_validation_failure
1184 def test_post_create_should_preserve_fields_values_on_validation_failure
1185 @request.session[:user_id] = 2
1185 @request.session[:user_id] = 2
1186 post :create, :project_id => 1,
1186 post :create, :project_id => 1,
1187 :issue => {:tracker_id => 1,
1187 :issue => {:tracker_id => 1,
1188 # empty subject
1188 # empty subject
1189 :subject => '',
1189 :subject => '',
1190 :description => 'This is a description',
1190 :description => 'This is a description',
1191 :priority_id => 6,
1191 :priority_id => 6,
1192 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
1192 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
1193 assert_response :success
1193 assert_response :success
1194 assert_template 'new'
1194 assert_template 'new'
1195
1195
1196 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
1196 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
1197 :content => 'This is a description'
1197 :content => 'This is a description'
1198 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1198 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1199 :child => { :tag => 'option', :attributes => { :selected => 'selected',
1199 :child => { :tag => 'option', :attributes => { :selected => 'selected',
1200 :value => '6' },
1200 :value => '6' },
1201 :content => 'High' }
1201 :content => 'High' }
1202 # Custom fields
1202 # Custom fields
1203 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
1203 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
1204 :child => { :tag => 'option', :attributes => { :selected => 'selected',
1204 :child => { :tag => 'option', :attributes => { :selected => 'selected',
1205 :value => 'Oracle' },
1205 :value => 'Oracle' },
1206 :content => 'Oracle' }
1206 :content => 'Oracle' }
1207 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
1207 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
1208 :value => 'Value for field 2'}
1208 :value => 'Value for field 2'}
1209 end
1209 end
1210
1210
1211 def test_post_create_should_ignore_non_safe_attributes
1211 def test_post_create_should_ignore_non_safe_attributes
1212 @request.session[:user_id] = 2
1212 @request.session[:user_id] = 2
1213 assert_nothing_raised do
1213 assert_nothing_raised do
1214 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
1214 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
1215 end
1215 end
1216 end
1216 end
1217
1217
1218 def test_post_create_with_attachment
1218 def test_post_create_with_attachment
1219 set_tmp_attachments_directory
1219 set_tmp_attachments_directory
1220 @request.session[:user_id] = 2
1220 @request.session[:user_id] = 2
1221
1221
1222 assert_difference 'Issue.count' do
1222 assert_difference 'Issue.count' do
1223 assert_difference 'Attachment.count' do
1223 assert_difference 'Attachment.count' do
1224 post :create, :project_id => 1,
1224 post :create, :project_id => 1,
1225 :issue => { :tracker_id => '1', :subject => 'With attachment' },
1225 :issue => { :tracker_id => '1', :subject => 'With attachment' },
1226 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1226 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1227 end
1227 end
1228 end
1228 end
1229
1229
1230 issue = Issue.first(:order => 'id DESC')
1230 issue = Issue.first(:order => 'id DESC')
1231 attachment = Attachment.first(:order => 'id DESC')
1231 attachment = Attachment.first(:order => 'id DESC')
1232
1232
1233 assert_equal issue, attachment.container
1233 assert_equal issue, attachment.container
1234 assert_equal 2, attachment.author_id
1234 assert_equal 2, attachment.author_id
1235 assert_equal 'testfile.txt', attachment.filename
1235 assert_equal 'testfile.txt', attachment.filename
1236 assert_equal 'text/plain', attachment.content_type
1236 assert_equal 'text/plain', attachment.content_type
1237 assert_equal 'test file', attachment.description
1237 assert_equal 'test file', attachment.description
1238 assert_equal 59, attachment.filesize
1238 assert_equal 59, attachment.filesize
1239 assert File.exists?(attachment.diskfile)
1239 assert File.exists?(attachment.diskfile)
1240 assert_equal 59, File.size(attachment.diskfile)
1240 assert_equal 59, File.size(attachment.diskfile)
1241 end
1241 end
1242
1242
1243 context "without workflow privilege" do
1243 context "without workflow privilege" do
1244 setup do
1244 setup do
1245 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1245 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1246 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1246 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1247 end
1247 end
1248
1248
1249 context "#new" do
1249 context "#new" do
1250 should "propose default status only" do
1250 should "propose default status only" do
1251 get :new, :project_id => 1
1251 get :new, :project_id => 1
1252 assert_response :success
1252 assert_response :success
1253 assert_template 'new'
1253 assert_template 'new'
1254 assert_tag :tag => 'select',
1254 assert_tag :tag => 'select',
1255 :attributes => {:name => 'issue[status_id]'},
1255 :attributes => {:name => 'issue[status_id]'},
1256 :children => {:count => 1},
1256 :children => {:count => 1},
1257 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
1257 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
1258 end
1258 end
1259
1259
1260 should "accept default status" do
1260 should "accept default status" do
1261 assert_difference 'Issue.count' do
1261 assert_difference 'Issue.count' do
1262 post :create, :project_id => 1,
1262 post :create, :project_id => 1,
1263 :issue => {:tracker_id => 1,
1263 :issue => {:tracker_id => 1,
1264 :subject => 'This is an issue',
1264 :subject => 'This is an issue',
1265 :status_id => 1}
1265 :status_id => 1}
1266 end
1266 end
1267 issue = Issue.last(:order => 'id')
1267 issue = Issue.last(:order => 'id')
1268 assert_equal IssueStatus.default, issue.status
1268 assert_equal IssueStatus.default, issue.status
1269 end
1269 end
1270
1270
1271 should "ignore unauthorized status" do
1271 should "ignore unauthorized status" do
1272 assert_difference 'Issue.count' do
1272 assert_difference 'Issue.count' do
1273 post :create, :project_id => 1,
1273 post :create, :project_id => 1,
1274 :issue => {:tracker_id => 1,
1274 :issue => {:tracker_id => 1,
1275 :subject => 'This is an issue',
1275 :subject => 'This is an issue',
1276 :status_id => 3}
1276 :status_id => 3}
1277 end
1277 end
1278 issue = Issue.last(:order => 'id')
1278 issue = Issue.last(:order => 'id')
1279 assert_equal IssueStatus.default, issue.status
1279 assert_equal IssueStatus.default, issue.status
1280 end
1280 end
1281 end
1281 end
1282
1282
1283 context "#update" do
1283 context "#update" do
1284 should "ignore status change" do
1284 should "ignore status change" do
1285 assert_difference 'Journal.count' do
1285 assert_difference 'Journal.count' do
1286 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1286 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1287 end
1287 end
1288 assert_equal 1, Issue.find(1).status_id
1288 assert_equal 1, Issue.find(1).status_id
1289 end
1289 end
1290
1290
1291 should "ignore attributes changes" do
1291 should "ignore attributes changes" do
1292 assert_difference 'Journal.count' do
1292 assert_difference 'Journal.count' do
1293 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1293 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1294 end
1294 end
1295 issue = Issue.find(1)
1295 issue = Issue.find(1)
1296 assert_equal "Can't print recipes", issue.subject
1296 assert_equal "Can't print recipes", issue.subject
1297 assert_nil issue.assigned_to
1297 assert_nil issue.assigned_to
1298 end
1298 end
1299 end
1299 end
1300 end
1300 end
1301
1301
1302 context "with workflow privilege" do
1302 context "with workflow privilege" do
1303 setup do
1303 setup do
1304 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1304 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
1305 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
1305 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
1306 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
1306 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
1307 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1307 Role.anonymous.add_permission! :add_issues, :add_issue_notes
1308 end
1308 end
1309
1309
1310 context "#update" do
1310 context "#update" do
1311 should "accept authorized status" do
1311 should "accept authorized status" do
1312 assert_difference 'Journal.count' do
1312 assert_difference 'Journal.count' do
1313 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1313 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1314 end
1314 end
1315 assert_equal 3, Issue.find(1).status_id
1315 assert_equal 3, Issue.find(1).status_id
1316 end
1316 end
1317
1317
1318 should "ignore unauthorized status" do
1318 should "ignore unauthorized status" do
1319 assert_difference 'Journal.count' do
1319 assert_difference 'Journal.count' do
1320 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1320 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1321 end
1321 end
1322 assert_equal 1, Issue.find(1).status_id
1322 assert_equal 1, Issue.find(1).status_id
1323 end
1323 end
1324
1324
1325 should "accept authorized attributes changes" do
1325 should "accept authorized attributes changes" do
1326 assert_difference 'Journal.count' do
1326 assert_difference 'Journal.count' do
1327 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
1327 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
1328 end
1328 end
1329 issue = Issue.find(1)
1329 issue = Issue.find(1)
1330 assert_equal 2, issue.assigned_to_id
1330 assert_equal 2, issue.assigned_to_id
1331 end
1331 end
1332
1332
1333 should "ignore unauthorized attributes changes" do
1333 should "ignore unauthorized attributes changes" do
1334 assert_difference 'Journal.count' do
1334 assert_difference 'Journal.count' do
1335 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
1335 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
1336 end
1336 end
1337 issue = Issue.find(1)
1337 issue = Issue.find(1)
1338 assert_equal "Can't print recipes", issue.subject
1338 assert_equal "Can't print recipes", issue.subject
1339 end
1339 end
1340 end
1340 end
1341
1341
1342 context "and :edit_issues permission" do
1342 context "and :edit_issues permission" do
1343 setup do
1343 setup do
1344 Role.anonymous.add_permission! :add_issues, :edit_issues
1344 Role.anonymous.add_permission! :add_issues, :edit_issues
1345 end
1345 end
1346
1346
1347 should "accept authorized status" do
1347 should "accept authorized status" do
1348 assert_difference 'Journal.count' do
1348 assert_difference 'Journal.count' do
1349 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1349 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
1350 end
1350 end
1351 assert_equal 3, Issue.find(1).status_id
1351 assert_equal 3, Issue.find(1).status_id
1352 end
1352 end
1353
1353
1354 should "ignore unauthorized status" do
1354 should "ignore unauthorized status" do
1355 assert_difference 'Journal.count' do
1355 assert_difference 'Journal.count' do
1356 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1356 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
1357 end
1357 end
1358 assert_equal 1, Issue.find(1).status_id
1358 assert_equal 1, Issue.find(1).status_id
1359 end
1359 end
1360
1360
1361 should "accept authorized attributes changes" do
1361 should "accept authorized attributes changes" do
1362 assert_difference 'Journal.count' do
1362 assert_difference 'Journal.count' do
1363 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1363 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
1364 end
1364 end
1365 issue = Issue.find(1)
1365 issue = Issue.find(1)
1366 assert_equal "changed", issue.subject
1366 assert_equal "changed", issue.subject
1367 assert_equal 2, issue.assigned_to_id
1367 assert_equal 2, issue.assigned_to_id
1368 end
1368 end
1369 end
1369 end
1370 end
1370 end
1371
1371
1372 def test_copy_issue
1372 def test_copy_issue
1373 @request.session[:user_id] = 2
1373 @request.session[:user_id] = 2
1374 get :new, :project_id => 1, :copy_from => 1
1374 get :new, :project_id => 1, :copy_from => 1
1375 assert_template 'new'
1375 assert_template 'new'
1376 assert_not_nil assigns(:issue)
1376 assert_not_nil assigns(:issue)
1377 orig = Issue.find(1)
1377 orig = Issue.find(1)
1378 assert_equal orig.subject, assigns(:issue).subject
1378 assert_equal orig.subject, assigns(:issue).subject
1379 end
1379 end
1380
1380
1381 def test_get_edit
1381 def test_get_edit
1382 @request.session[:user_id] = 2
1382 @request.session[:user_id] = 2
1383 get :edit, :id => 1
1383 get :edit, :id => 1
1384 assert_response :success
1384 assert_response :success
1385 assert_template 'edit'
1385 assert_template 'edit'
1386 assert_not_nil assigns(:issue)
1386 assert_not_nil assigns(:issue)
1387 assert_equal Issue.find(1), assigns(:issue)
1387 assert_equal Issue.find(1), assigns(:issue)
1388
1388
1389 # Be sure we don't display inactive IssuePriorities
1389 # Be sure we don't display inactive IssuePriorities
1390 assert ! IssuePriority.find(15).active?
1390 assert ! IssuePriority.find(15).active?
1391 assert_no_tag :option, :attributes => {:value => '15'},
1391 assert_no_tag :option, :attributes => {:value => '15'},
1392 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1392 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1393 end
1393 end
1394
1394
1395 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
1395 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
1396 @request.session[:user_id] = 2
1396 @request.session[:user_id] = 2
1397 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
1397 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
1398
1398
1399 get :edit, :id => 1
1399 get :edit, :id => 1
1400 assert_tag 'input', :attributes => {:name => 'time_entry[hours]'}
1400 assert_tag 'input', :attributes => {:name => 'time_entry[hours]'}
1401 end
1401 end
1402
1402
1403 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
1403 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
1404 @request.session[:user_id] = 2
1404 @request.session[:user_id] = 2
1405 Role.find_by_name('Manager').remove_permission! :log_time
1405 Role.find_by_name('Manager').remove_permission! :log_time
1406
1406
1407 get :edit, :id => 1
1407 get :edit, :id => 1
1408 assert_no_tag 'input', :attributes => {:name => 'time_entry[hours]'}
1408 assert_no_tag 'input', :attributes => {:name => 'time_entry[hours]'}
1409 end
1409 end
1410
1410
1411 def test_get_edit_with_params
1411 def test_get_edit_with_params
1412 @request.session[:user_id] = 2
1412 @request.session[:user_id] = 2
1413 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
1413 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
1414 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
1414 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
1415 assert_response :success
1415 assert_response :success
1416 assert_template 'edit'
1416 assert_template 'edit'
1417
1417
1418 issue = assigns(:issue)
1418 issue = assigns(:issue)
1419 assert_not_nil issue
1419 assert_not_nil issue
1420
1420
1421 assert_equal 5, issue.status_id
1421 assert_equal 5, issue.status_id
1422 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
1422 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
1423 :child => { :tag => 'option',
1423 :child => { :tag => 'option',
1424 :content => 'Closed',
1424 :content => 'Closed',
1425 :attributes => { :selected => 'selected' } }
1425 :attributes => { :selected => 'selected' } }
1426
1426
1427 assert_equal 7, issue.priority_id
1427 assert_equal 7, issue.priority_id
1428 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1428 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
1429 :child => { :tag => 'option',
1429 :child => { :tag => 'option',
1430 :content => 'Urgent',
1430 :content => 'Urgent',
1431 :attributes => { :selected => 'selected' } }
1431 :attributes => { :selected => 'selected' } }
1432
1432
1433 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
1433 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
1434 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
1434 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
1435 :child => { :tag => 'option',
1435 :child => { :tag => 'option',
1436 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
1436 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
1437 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
1437 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
1438 end
1438 end
1439
1439
1440 def test_update_edit_form
1440 def test_update_edit_form
1441 @request.session[:user_id] = 2
1441 @request.session[:user_id] = 2
1442 xhr :post, :new, :project_id => 1,
1442 xhr :post, :new, :project_id => 1,
1443 :id => 1,
1443 :id => 1,
1444 :issue => {:tracker_id => 2,
1444 :issue => {:tracker_id => 2,
1445 :subject => 'This is the test_new issue',
1445 :subject => 'This is the test_new issue',
1446 :description => 'This is the description',
1446 :description => 'This is the description',
1447 :priority_id => 5}
1447 :priority_id => 5}
1448 assert_response :success
1448 assert_response :success
1449 assert_template 'attributes'
1449 assert_template 'attributes'
1450
1450
1451 issue = assigns(:issue)
1451 issue = assigns(:issue)
1452 assert_kind_of Issue, issue
1452 assert_kind_of Issue, issue
1453 assert_equal 1, issue.id
1453 assert_equal 1, issue.id
1454 assert_equal 1, issue.project_id
1454 assert_equal 1, issue.project_id
1455 assert_equal 2, issue.tracker_id
1455 assert_equal 2, issue.tracker_id
1456 assert_equal 'This is the test_new issue', issue.subject
1456 assert_equal 'This is the test_new issue', issue.subject
1457 end
1457 end
1458
1458
1459 def test_update_using_invalid_http_verbs
1459 def test_update_using_invalid_http_verbs
1460 @request.session[:user_id] = 2
1460 @request.session[:user_id] = 2
1461 subject = 'Updated by an invalid http verb'
1461 subject = 'Updated by an invalid http verb'
1462
1462
1463 get :update, :id => 1, :issue => {:subject => subject}
1463 get :update, :id => 1, :issue => {:subject => subject}
1464 assert_not_equal subject, Issue.find(1).subject
1464 assert_not_equal subject, Issue.find(1).subject
1465
1465
1466 post :update, :id => 1, :issue => {:subject => subject}
1466 post :update, :id => 1, :issue => {:subject => subject}
1467 assert_not_equal subject, Issue.find(1).subject
1467 assert_not_equal subject, Issue.find(1).subject
1468
1468
1469 delete :update, :id => 1, :issue => {:subject => subject}
1469 delete :update, :id => 1, :issue => {:subject => subject}
1470 assert_not_equal subject, Issue.find(1).subject
1470 assert_not_equal subject, Issue.find(1).subject
1471 end
1471 end
1472
1472
1473 def test_put_update_without_custom_fields_param
1473 def test_put_update_without_custom_fields_param
1474 @request.session[:user_id] = 2
1474 @request.session[:user_id] = 2
1475 ActionMailer::Base.deliveries.clear
1475 ActionMailer::Base.deliveries.clear
1476
1476
1477 issue = Issue.find(1)
1477 issue = Issue.find(1)
1478 assert_equal '125', issue.custom_value_for(2).value
1478 assert_equal '125', issue.custom_value_for(2).value
1479 old_subject = issue.subject
1479 old_subject = issue.subject
1480 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1480 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1481
1481
1482 assert_difference('Journal.count') do
1482 assert_difference('Journal.count') do
1483 assert_difference('JournalDetail.count', 2) do
1483 assert_difference('JournalDetail.count', 2) do
1484 put :update, :id => 1, :issue => {:subject => new_subject,
1484 put :update, :id => 1, :issue => {:subject => new_subject,
1485 :priority_id => '6',
1485 :priority_id => '6',
1486 :category_id => '1' # no change
1486 :category_id => '1' # no change
1487 }
1487 }
1488 end
1488 end
1489 end
1489 end
1490 assert_redirected_to :action => 'show', :id => '1'
1490 assert_redirected_to :action => 'show', :id => '1'
1491 issue.reload
1491 issue.reload
1492 assert_equal new_subject, issue.subject
1492 assert_equal new_subject, issue.subject
1493 # Make sure custom fields were not cleared
1493 # Make sure custom fields were not cleared
1494 assert_equal '125', issue.custom_value_for(2).value
1494 assert_equal '125', issue.custom_value_for(2).value
1495
1495
1496 mail = ActionMailer::Base.deliveries.last
1496 mail = ActionMailer::Base.deliveries.last
1497 assert_kind_of TMail::Mail, mail
1497 assert_kind_of TMail::Mail, mail
1498 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1498 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
1499 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
1499 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
1500 end
1500 end
1501
1501
1502 def test_put_update_with_custom_field_change
1502 def test_put_update_with_custom_field_change
1503 @request.session[:user_id] = 2
1503 @request.session[:user_id] = 2
1504 issue = Issue.find(1)
1504 issue = Issue.find(1)
1505 assert_equal '125', issue.custom_value_for(2).value
1505 assert_equal '125', issue.custom_value_for(2).value
1506
1506
1507 assert_difference('Journal.count') do
1507 assert_difference('Journal.count') do
1508 assert_difference('JournalDetail.count', 3) do
1508 assert_difference('JournalDetail.count', 3) do
1509 put :update, :id => 1, :issue => {:subject => 'Custom field change',
1509 put :update, :id => 1, :issue => {:subject => 'Custom field change',
1510 :priority_id => '6',
1510 :priority_id => '6',
1511 :category_id => '1', # no change
1511 :category_id => '1', # no change
1512 :custom_field_values => { '2' => 'New custom value' }
1512 :custom_field_values => { '2' => 'New custom value' }
1513 }
1513 }
1514 end
1514 end
1515 end
1515 end
1516 assert_redirected_to :action => 'show', :id => '1'
1516 assert_redirected_to :action => 'show', :id => '1'
1517 issue.reload
1517 issue.reload
1518 assert_equal 'New custom value', issue.custom_value_for(2).value
1518 assert_equal 'New custom value', issue.custom_value_for(2).value
1519
1519
1520 mail = ActionMailer::Base.deliveries.last
1520 mail = ActionMailer::Base.deliveries.last
1521 assert_kind_of TMail::Mail, mail
1521 assert_kind_of TMail::Mail, mail
1522 assert mail.body.include?("Searchable field changed from 125 to New custom value")
1522 assert mail.body.include?("Searchable field changed from 125 to New custom value")
1523 end
1523 end
1524
1524
1525 def test_put_update_with_status_and_assignee_change
1525 def test_put_update_with_status_and_assignee_change
1526 issue = Issue.find(1)
1526 issue = Issue.find(1)
1527 assert_equal 1, issue.status_id
1527 assert_equal 1, issue.status_id
1528 @request.session[:user_id] = 2
1528 @request.session[:user_id] = 2
1529 assert_difference('TimeEntry.count', 0) do
1529 assert_difference('TimeEntry.count', 0) do
1530 put :update,
1530 put :update,
1531 :id => 1,
1531 :id => 1,
1532 :issue => { :status_id => 2, :assigned_to_id => 3 },
1532 :issue => { :status_id => 2, :assigned_to_id => 3 },
1533 :notes => 'Assigned to dlopper',
1533 :notes => 'Assigned to dlopper',
1534 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
1534 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
1535 end
1535 end
1536 assert_redirected_to :action => 'show', :id => '1'
1536 assert_redirected_to :action => 'show', :id => '1'
1537 issue.reload
1537 issue.reload
1538 assert_equal 2, issue.status_id
1538 assert_equal 2, issue.status_id
1539 j = Journal.find(:first, :order => 'id DESC')
1539 j = Journal.find(:first, :order => 'id DESC')
1540 assert_equal 'Assigned to dlopper', j.notes
1540 assert_equal 'Assigned to dlopper', j.notes
1541 assert_equal 2, j.details.size
1541 assert_equal 2, j.details.size
1542
1542
1543 mail = ActionMailer::Base.deliveries.last
1543 mail = ActionMailer::Base.deliveries.last
1544 assert mail.body.include?("Status changed from New to Assigned")
1544 assert mail.body.include?("Status changed from New to Assigned")
1545 # subject should contain the new status
1545 # subject should contain the new status
1546 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
1546 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
1547 end
1547 end
1548
1548
1549 def test_put_update_with_note_only
1549 def test_put_update_with_note_only
1550 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
1550 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
1551 # anonymous user
1551 # anonymous user
1552 put :update,
1552 put :update,
1553 :id => 1,
1553 :id => 1,
1554 :notes => notes
1554 :notes => notes
1555 assert_redirected_to :action => 'show', :id => '1'
1555 assert_redirected_to :action => 'show', :id => '1'
1556 j = Journal.find(:first, :order => 'id DESC')
1556 j = Journal.find(:first, :order => 'id DESC')
1557 assert_equal notes, j.notes
1557 assert_equal notes, j.notes
1558 assert_equal 0, j.details.size
1558 assert_equal 0, j.details.size
1559 assert_equal User.anonymous, j.user
1559 assert_equal User.anonymous, j.user
1560
1560
1561 mail = ActionMailer::Base.deliveries.last
1561 mail = ActionMailer::Base.deliveries.last
1562 assert mail.body.include?(notes)
1562 assert mail.body.include?(notes)
1563 end
1563 end
1564
1564
1565 def test_put_update_with_note_and_spent_time
1565 def test_put_update_with_note_and_spent_time
1566 @request.session[:user_id] = 2
1566 @request.session[:user_id] = 2
1567 spent_hours_before = Issue.find(1).spent_hours
1567 spent_hours_before = Issue.find(1).spent_hours
1568 assert_difference('TimeEntry.count') do
1568 assert_difference('TimeEntry.count') do
1569 put :update,
1569 put :update,
1570 :id => 1,
1570 :id => 1,
1571 :notes => '2.5 hours added',
1571 :notes => '2.5 hours added',
1572 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
1572 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
1573 end
1573 end
1574 assert_redirected_to :action => 'show', :id => '1'
1574 assert_redirected_to :action => 'show', :id => '1'
1575
1575
1576 issue = Issue.find(1)
1576 issue = Issue.find(1)
1577
1577
1578 j = Journal.find(:first, :order => 'id DESC')
1578 j = Journal.find(:first, :order => 'id DESC')
1579 assert_equal '2.5 hours added', j.notes
1579 assert_equal '2.5 hours added', j.notes
1580 assert_equal 0, j.details.size
1580 assert_equal 0, j.details.size
1581
1581
1582 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
1582 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
1583 assert_not_nil t
1583 assert_not_nil t
1584 assert_equal 2.5, t.hours
1584 assert_equal 2.5, t.hours
1585 assert_equal spent_hours_before + 2.5, issue.spent_hours
1585 assert_equal spent_hours_before + 2.5, issue.spent_hours
1586 end
1586 end
1587
1587
1588 def test_put_update_with_attachment_only
1588 def test_put_update_with_attachment_only
1589 set_tmp_attachments_directory
1589 set_tmp_attachments_directory
1590
1590
1591 # Delete all fixtured journals, a race condition can occur causing the wrong
1591 # Delete all fixtured journals, a race condition can occur causing the wrong
1592 # journal to get fetched in the next find.
1592 # journal to get fetched in the next find.
1593 Journal.delete_all
1593 Journal.delete_all
1594
1594
1595 # anonymous user
1595 # anonymous user
1596 assert_difference 'Attachment.count' do
1596 assert_difference 'Attachment.count' do
1597 put :update, :id => 1,
1597 put :update, :id => 1,
1598 :notes => '',
1598 :notes => '',
1599 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1599 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
1600 end
1600 end
1601
1601
1602 assert_redirected_to :action => 'show', :id => '1'
1602 assert_redirected_to :action => 'show', :id => '1'
1603 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
1603 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
1604 assert j.notes.blank?
1604 assert j.notes.blank?
1605 assert_equal 1, j.details.size
1605 assert_equal 1, j.details.size
1606 assert_equal 'testfile.txt', j.details.first.value
1606 assert_equal 'testfile.txt', j.details.first.value
1607 assert_equal User.anonymous, j.user
1607 assert_equal User.anonymous, j.user
1608
1608
1609 attachment = Attachment.first(:order => 'id DESC')
1609 attachment = Attachment.first(:order => 'id DESC')
1610 assert_equal Issue.find(1), attachment.container
1610 assert_equal Issue.find(1), attachment.container
1611 assert_equal User.anonymous, attachment.author
1611 assert_equal User.anonymous, attachment.author
1612 assert_equal 'testfile.txt', attachment.filename
1612 assert_equal 'testfile.txt', attachment.filename
1613 assert_equal 'text/plain', attachment.content_type
1613 assert_equal 'text/plain', attachment.content_type
1614 assert_equal 'test file', attachment.description
1614 assert_equal 'test file', attachment.description
1615 assert_equal 59, attachment.filesize
1615 assert_equal 59, attachment.filesize
1616 assert File.exists?(attachment.diskfile)
1616 assert File.exists?(attachment.diskfile)
1617 assert_equal 59, File.size(attachment.diskfile)
1617 assert_equal 59, File.size(attachment.diskfile)
1618
1618
1619 mail = ActionMailer::Base.deliveries.last
1619 mail = ActionMailer::Base.deliveries.last
1620 assert mail.body.include?('testfile.txt')
1620 assert mail.body.include?('testfile.txt')
1621 end
1621 end
1622
1622
1623 def test_put_update_with_attachment_that_fails_to_save
1623 def test_put_update_with_attachment_that_fails_to_save
1624 set_tmp_attachments_directory
1624 set_tmp_attachments_directory
1625
1625
1626 # Delete all fixtured journals, a race condition can occur causing the wrong
1626 # Delete all fixtured journals, a race condition can occur causing the wrong
1627 # journal to get fetched in the next find.
1627 # journal to get fetched in the next find.
1628 Journal.delete_all
1628 Journal.delete_all
1629
1629
1630 # Mock out the unsaved attachment
1630 # Mock out the unsaved attachment
1631 Attachment.any_instance.stubs(:create).returns(Attachment.new)
1631 Attachment.any_instance.stubs(:create).returns(Attachment.new)
1632
1632
1633 # anonymous user
1633 # anonymous user
1634 put :update,
1634 put :update,
1635 :id => 1,
1635 :id => 1,
1636 :notes => '',
1636 :notes => '',
1637 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1637 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
1638 assert_redirected_to :action => 'show', :id => '1'
1638 assert_redirected_to :action => 'show', :id => '1'
1639 assert_equal '1 file(s) could not be saved.', flash[:warning]
1639 assert_equal '1 file(s) could not be saved.', flash[:warning]
1640
1640
1641 end if Object.const_defined?(:Mocha)
1641 end if Object.const_defined?(:Mocha)
1642
1642
1643 def test_put_update_with_no_change
1643 def test_put_update_with_no_change
1644 issue = Issue.find(1)
1644 issue = Issue.find(1)
1645 issue.journals.clear
1645 issue.journals.clear
1646 ActionMailer::Base.deliveries.clear
1646 ActionMailer::Base.deliveries.clear
1647
1647
1648 put :update,
1648 put :update,
1649 :id => 1,
1649 :id => 1,
1650 :notes => ''
1650 :notes => ''
1651 assert_redirected_to :action => 'show', :id => '1'
1651 assert_redirected_to :action => 'show', :id => '1'
1652
1652
1653 issue.reload
1653 issue.reload
1654 assert issue.journals.empty?
1654 assert issue.journals.empty?
1655 # No email should be sent
1655 # No email should be sent
1656 assert ActionMailer::Base.deliveries.empty?
1656 assert ActionMailer::Base.deliveries.empty?
1657 end
1657 end
1658
1658
1659 def test_put_update_should_send_a_notification
1659 def test_put_update_should_send_a_notification
1660 @request.session[:user_id] = 2
1660 @request.session[:user_id] = 2
1661 ActionMailer::Base.deliveries.clear
1661 ActionMailer::Base.deliveries.clear
1662 issue = Issue.find(1)
1662 issue = Issue.find(1)
1663 old_subject = issue.subject
1663 old_subject = issue.subject
1664 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1664 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1665
1665
1666 put :update, :id => 1, :issue => {:subject => new_subject,
1666 put :update, :id => 1, :issue => {:subject => new_subject,
1667 :priority_id => '6',
1667 :priority_id => '6',
1668 :category_id => '1' # no change
1668 :category_id => '1' # no change
1669 }
1669 }
1670 assert_equal 1, ActionMailer::Base.deliveries.size
1670 assert_equal 1, ActionMailer::Base.deliveries.size
1671 end
1671 end
1672
1672
1673 def test_put_update_with_invalid_spent_time_hours_only
1673 def test_put_update_with_invalid_spent_time_hours_only
1674 @request.session[:user_id] = 2
1674 @request.session[:user_id] = 2
1675 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1675 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1676
1676
1677 assert_no_difference('Journal.count') do
1677 assert_no_difference('Journal.count') do
1678 put :update,
1678 put :update,
1679 :id => 1,
1679 :id => 1,
1680 :notes => notes,
1680 :notes => notes,
1681 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1681 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1682 end
1682 end
1683 assert_response :success
1683 assert_response :success
1684 assert_template 'edit'
1684 assert_template 'edit'
1685
1685
1686 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1686 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1687 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1687 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1688 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1688 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1689 end
1689 end
1690
1690
1691 def test_put_update_with_invalid_spent_time_comments_only
1691 def test_put_update_with_invalid_spent_time_comments_only
1692 @request.session[:user_id] = 2
1692 @request.session[:user_id] = 2
1693 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1693 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1694
1694
1695 assert_no_difference('Journal.count') do
1695 assert_no_difference('Journal.count') do
1696 put :update,
1696 put :update,
1697 :id => 1,
1697 :id => 1,
1698 :notes => notes,
1698 :notes => notes,
1699 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1699 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1700 end
1700 end
1701 assert_response :success
1701 assert_response :success
1702 assert_template 'edit'
1702 assert_template 'edit'
1703
1703
1704 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1704 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1705 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1705 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1706 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1706 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1707 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1707 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1708 end
1708 end
1709
1709
1710 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1710 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1711 issue = Issue.find(2)
1711 issue = Issue.find(2)
1712 @request.session[:user_id] = 2
1712 @request.session[:user_id] = 2
1713
1713
1714 put :update,
1714 put :update,
1715 :id => issue.id,
1715 :id => issue.id,
1716 :issue => {
1716 :issue => {
1717 :fixed_version_id => 4
1717 :fixed_version_id => 4
1718 }
1718 }
1719
1719
1720 assert_response :redirect
1720 assert_response :redirect
1721 issue.reload
1721 issue.reload
1722 assert_equal 4, issue.fixed_version_id
1722 assert_equal 4, issue.fixed_version_id
1723 assert_not_equal issue.project_id, issue.fixed_version.project_id
1723 assert_not_equal issue.project_id, issue.fixed_version.project_id
1724 end
1724 end
1725
1725
1726 def test_put_update_should_redirect_back_using_the_back_url_parameter
1726 def test_put_update_should_redirect_back_using_the_back_url_parameter
1727 issue = Issue.find(2)
1727 issue = Issue.find(2)
1728 @request.session[:user_id] = 2
1728 @request.session[:user_id] = 2
1729
1729
1730 put :update,
1730 put :update,
1731 :id => issue.id,
1731 :id => issue.id,
1732 :issue => {
1732 :issue => {
1733 :fixed_version_id => 4
1733 :fixed_version_id => 4
1734 },
1734 },
1735 :back_url => '/issues'
1735 :back_url => '/issues'
1736
1736
1737 assert_response :redirect
1737 assert_response :redirect
1738 assert_redirected_to '/issues'
1738 assert_redirected_to '/issues'
1739 end
1739 end
1740
1740
1741 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1741 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1742 issue = Issue.find(2)
1742 issue = Issue.find(2)
1743 @request.session[:user_id] = 2
1743 @request.session[:user_id] = 2
1744
1744
1745 put :update,
1745 put :update,
1746 :id => issue.id,
1746 :id => issue.id,
1747 :issue => {
1747 :issue => {
1748 :fixed_version_id => 4
1748 :fixed_version_id => 4
1749 },
1749 },
1750 :back_url => 'http://google.com'
1750 :back_url => 'http://google.com'
1751
1751
1752 assert_response :redirect
1752 assert_response :redirect
1753 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
1753 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
1754 end
1754 end
1755
1755
1756 def test_get_bulk_edit
1756 def test_get_bulk_edit
1757 @request.session[:user_id] = 2
1757 @request.session[:user_id] = 2
1758 get :bulk_edit, :ids => [1, 2]
1758 get :bulk_edit, :ids => [1, 2]
1759 assert_response :success
1759 assert_response :success
1760 assert_template 'bulk_edit'
1760 assert_template 'bulk_edit'
1761
1761
1762 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1762 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1763
1763
1764 # Project specific custom field, date type
1764 # Project specific custom field, date type
1765 field = CustomField.find(9)
1765 field = CustomField.find(9)
1766 assert !field.is_for_all?
1766 assert !field.is_for_all?
1767 assert_equal 'date', field.field_format
1767 assert_equal 'date', field.field_format
1768 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1768 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1769
1769
1770 # System wide custom field
1770 # System wide custom field
1771 assert CustomField.find(1).is_for_all?
1771 assert CustomField.find(1).is_for_all?
1772 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
1772 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
1773
1773
1774 # Be sure we don't display inactive IssuePriorities
1774 # Be sure we don't display inactive IssuePriorities
1775 assert ! IssuePriority.find(15).active?
1775 assert ! IssuePriority.find(15).active?
1776 assert_no_tag :option, :attributes => {:value => '15'},
1776 assert_no_tag :option, :attributes => {:value => '15'},
1777 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1777 :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1778 end
1778 end
1779
1779
1780 def test_get_bulk_edit_on_different_projects
1780 def test_get_bulk_edit_on_different_projects
1781 @request.session[:user_id] = 2
1781 @request.session[:user_id] = 2
1782 get :bulk_edit, :ids => [1, 2, 6]
1782 get :bulk_edit, :ids => [1, 2, 6]
1783 assert_response :success
1783 assert_response :success
1784 assert_template 'bulk_edit'
1784 assert_template 'bulk_edit'
1785
1785
1786 # Can not set issues from different projects as children of an issue
1786 # Can not set issues from different projects as children of an issue
1787 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1787 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1788
1788
1789 # Project specific custom field, date type
1789 # Project specific custom field, date type
1790 field = CustomField.find(9)
1790 field = CustomField.find(9)
1791 assert !field.is_for_all?
1791 assert !field.is_for_all?
1792 assert !field.project_ids.include?(Issue.find(6).project_id)
1792 assert !field.project_ids.include?(Issue.find(6).project_id)
1793 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1793 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1794 end
1794 end
1795
1795
1796 def test_get_bulk_edit_with_user_custom_field
1796 def test_get_bulk_edit_with_user_custom_field
1797 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
1797 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
1798
1798
1799 @request.session[:user_id] = 2
1799 @request.session[:user_id] = 2
1800 get :bulk_edit, :ids => [1, 2]
1800 get :bulk_edit, :ids => [1, 2]
1801 assert_response :success
1801 assert_response :success
1802 assert_template 'bulk_edit'
1802 assert_template 'bulk_edit'
1803
1803
1804 assert_tag :select,
1804 assert_tag :select,
1805 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1805 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1806 :children => {
1806 :children => {
1807 :only => {:tag => 'option'},
1807 :only => {:tag => 'option'},
1808 :count => Project.find(1).users.count + 1
1808 :count => Project.find(1).users.count + 1
1809 }
1809 }
1810 end
1810 end
1811
1811
1812 def test_get_bulk_edit_with_version_custom_field
1812 def test_get_bulk_edit_with_version_custom_field
1813 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
1813 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
1814
1814
1815 @request.session[:user_id] = 2
1815 @request.session[:user_id] = 2
1816 get :bulk_edit, :ids => [1, 2]
1816 get :bulk_edit, :ids => [1, 2]
1817 assert_response :success
1817 assert_response :success
1818 assert_template 'bulk_edit'
1818 assert_template 'bulk_edit'
1819
1819
1820 assert_tag :select,
1820 assert_tag :select,
1821 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1821 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1822 :children => {
1822 :children => {
1823 :only => {:tag => 'option'},
1823 :only => {:tag => 'option'},
1824 :count => Project.find(1).shared_versions.count + 1
1824 :count => Project.find(1).shared_versions.count + 1
1825 }
1825 }
1826 end
1826 end
1827
1827
1828 def test_bulk_update
1828 def test_bulk_update
1829 @request.session[:user_id] = 2
1829 @request.session[:user_id] = 2
1830 # update issues priority
1830 # update issues priority
1831 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1831 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1832 :issue => {:priority_id => 7,
1832 :issue => {:priority_id => 7,
1833 :assigned_to_id => '',
1833 :assigned_to_id => '',
1834 :custom_field_values => {'2' => ''}}
1834 :custom_field_values => {'2' => ''}}
1835
1835
1836 assert_response 302
1836 assert_response 302
1837 # check that the issues were updated
1837 # check that the issues were updated
1838 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
1838 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
1839
1839
1840 issue = Issue.find(1)
1840 issue = Issue.find(1)
1841 journal = issue.journals.find(:first, :order => 'created_on DESC')
1841 journal = issue.journals.find(:first, :order => 'created_on DESC')
1842 assert_equal '125', issue.custom_value_for(2).value
1842 assert_equal '125', issue.custom_value_for(2).value
1843 assert_equal 'Bulk editing', journal.notes
1843 assert_equal 'Bulk editing', journal.notes
1844 assert_equal 1, journal.details.size
1844 assert_equal 1, journal.details.size
1845 end
1845 end
1846
1846
1847 def test_bulk_update_with_group_assignee
1847 def test_bulk_update_with_group_assignee
1848 group = Group.find(11)
1848 group = Group.find(11)
1849 project = Project.find(1)
1849 project = Project.find(1)
1850 project.members << Member.new(:principal => group, :roles => [Role.first])
1850 project.members << Member.new(:principal => group, :roles => [Role.first])
1851
1851
1852 @request.session[:user_id] = 2
1852 @request.session[:user_id] = 2
1853 # update issues assignee
1853 # update issues assignee
1854 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1854 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1855 :issue => {:priority_id => '',
1855 :issue => {:priority_id => '',
1856 :assigned_to_id => group.id,
1856 :assigned_to_id => group.id,
1857 :custom_field_values => {'2' => ''}}
1857 :custom_field_values => {'2' => ''}}
1858
1858
1859 assert_response 302
1859 assert_response 302
1860 assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
1860 assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
1861 end
1861 end
1862
1862
1863 def test_bulk_update_on_different_projects
1863 def test_bulk_update_on_different_projects
1864 @request.session[:user_id] = 2
1864 @request.session[:user_id] = 2
1865 # update issues priority
1865 # update issues priority
1866 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
1866 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
1867 :issue => {:priority_id => 7,
1867 :issue => {:priority_id => 7,
1868 :assigned_to_id => '',
1868 :assigned_to_id => '',
1869 :custom_field_values => {'2' => ''}}
1869 :custom_field_values => {'2' => ''}}
1870
1870
1871 assert_response 302
1871 assert_response 302
1872 # check that the issues were updated
1872 # check that the issues were updated
1873 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
1873 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
1874
1874
1875 issue = Issue.find(1)
1875 issue = Issue.find(1)
1876 journal = issue.journals.find(:first, :order => 'created_on DESC')
1876 journal = issue.journals.find(:first, :order => 'created_on DESC')
1877 assert_equal '125', issue.custom_value_for(2).value
1877 assert_equal '125', issue.custom_value_for(2).value
1878 assert_equal 'Bulk editing', journal.notes
1878 assert_equal 'Bulk editing', journal.notes
1879 assert_equal 1, journal.details.size
1879 assert_equal 1, journal.details.size
1880 end
1880 end
1881
1881
1882 def test_bulk_update_on_different_projects_without_rights
1882 def test_bulk_update_on_different_projects_without_rights
1883 @request.session[:user_id] = 3
1883 @request.session[:user_id] = 3
1884 user = User.find(3)
1884 user = User.find(3)
1885 action = { :controller => "issues", :action => "bulk_update" }
1885 action = { :controller => "issues", :action => "bulk_update" }
1886 assert user.allowed_to?(action, Issue.find(1).project)
1886 assert user.allowed_to?(action, Issue.find(1).project)
1887 assert ! user.allowed_to?(action, Issue.find(6).project)
1887 assert ! user.allowed_to?(action, Issue.find(6).project)
1888 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
1888 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
1889 :issue => {:priority_id => 7,
1889 :issue => {:priority_id => 7,
1890 :assigned_to_id => '',
1890 :assigned_to_id => '',
1891 :custom_field_values => {'2' => ''}}
1891 :custom_field_values => {'2' => ''}}
1892 assert_response 403
1892 assert_response 403
1893 assert_not_equal "Bulk should fail", Journal.last.notes
1893 assert_not_equal "Bulk should fail", Journal.last.notes
1894 end
1894 end
1895
1895
1896 def test_bullk_update_should_send_a_notification
1896 def test_bullk_update_should_send_a_notification
1897 @request.session[:user_id] = 2
1897 @request.session[:user_id] = 2
1898 ActionMailer::Base.deliveries.clear
1898 ActionMailer::Base.deliveries.clear
1899 post(:bulk_update,
1899 post(:bulk_update,
1900 {
1900 {
1901 :ids => [1, 2],
1901 :ids => [1, 2],
1902 :notes => 'Bulk editing',
1902 :notes => 'Bulk editing',
1903 :issue => {
1903 :issue => {
1904 :priority_id => 7,
1904 :priority_id => 7,
1905 :assigned_to_id => '',
1905 :assigned_to_id => '',
1906 :custom_field_values => {'2' => ''}
1906 :custom_field_values => {'2' => ''}
1907 }
1907 }
1908 })
1908 })
1909
1909
1910 assert_response 302
1910 assert_response 302
1911 assert_equal 2, ActionMailer::Base.deliveries.size
1911 assert_equal 2, ActionMailer::Base.deliveries.size
1912 end
1912 end
1913
1913
1914 def test_bulk_update_status
1914 def test_bulk_update_status
1915 @request.session[:user_id] = 2
1915 @request.session[:user_id] = 2
1916 # update issues priority
1916 # update issues priority
1917 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
1917 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
1918 :issue => {:priority_id => '',
1918 :issue => {:priority_id => '',
1919 :assigned_to_id => '',
1919 :assigned_to_id => '',
1920 :status_id => '5'}
1920 :status_id => '5'}
1921
1921
1922 assert_response 302
1922 assert_response 302
1923 issue = Issue.find(1)
1923 issue = Issue.find(1)
1924 assert issue.closed?
1924 assert issue.closed?
1925 end
1925 end
1926
1926
1927 def test_bulk_update_parent_id
1927 def test_bulk_update_parent_id
1928 @request.session[:user_id] = 2
1928 @request.session[:user_id] = 2
1929 post :bulk_update, :ids => [1, 3],
1929 post :bulk_update, :ids => [1, 3],
1930 :notes => 'Bulk editing parent',
1930 :notes => 'Bulk editing parent',
1931 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
1931 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
1932
1932
1933 assert_response 302
1933 assert_response 302
1934 parent = Issue.find(2)
1934 parent = Issue.find(2)
1935 assert_equal parent.id, Issue.find(1).parent_id
1935 assert_equal parent.id, Issue.find(1).parent_id
1936 assert_equal parent.id, Issue.find(3).parent_id
1936 assert_equal parent.id, Issue.find(3).parent_id
1937 assert_equal [1, 3], parent.children.collect(&:id).sort
1937 assert_equal [1, 3], parent.children.collect(&:id).sort
1938 end
1938 end
1939
1939
1940 def test_bulk_update_custom_field
1940 def test_bulk_update_custom_field
1941 @request.session[:user_id] = 2
1941 @request.session[:user_id] = 2
1942 # update issues priority
1942 # update issues priority
1943 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
1943 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
1944 :issue => {:priority_id => '',
1944 :issue => {:priority_id => '',
1945 :assigned_to_id => '',
1945 :assigned_to_id => '',
1946 :custom_field_values => {'2' => '777'}}
1946 :custom_field_values => {'2' => '777'}}
1947
1947
1948 assert_response 302
1948 assert_response 302
1949
1949
1950 issue = Issue.find(1)
1950 issue = Issue.find(1)
1951 journal = issue.journals.find(:first, :order => 'created_on DESC')
1951 journal = issue.journals.find(:first, :order => 'created_on DESC')
1952 assert_equal '777', issue.custom_value_for(2).value
1952 assert_equal '777', issue.custom_value_for(2).value
1953 assert_equal 1, journal.details.size
1953 assert_equal 1, journal.details.size
1954 assert_equal '125', journal.details.first.old_value
1954 assert_equal '125', journal.details.first.old_value
1955 assert_equal '777', journal.details.first.value
1955 assert_equal '777', journal.details.first.value
1956 end
1956 end
1957
1957
1958 def test_bulk_update_unassign
1958 def test_bulk_update_unassign
1959 assert_not_nil Issue.find(2).assigned_to
1959 assert_not_nil Issue.find(2).assigned_to
1960 @request.session[:user_id] = 2
1960 @request.session[:user_id] = 2
1961 # unassign issues
1961 # unassign issues
1962 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
1962 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
1963 assert_response 302
1963 assert_response 302
1964 # check that the issues were updated
1964 # check that the issues were updated
1965 assert_nil Issue.find(2).assigned_to
1965 assert_nil Issue.find(2).assigned_to
1966 end
1966 end
1967
1967
1968 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
1968 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
1969 @request.session[:user_id] = 2
1969 @request.session[:user_id] = 2
1970
1970
1971 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
1971 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
1972
1972
1973 assert_response :redirect
1973 assert_response :redirect
1974 issues = Issue.find([1,2])
1974 issues = Issue.find([1,2])
1975 issues.each do |issue|
1975 issues.each do |issue|
1976 assert_equal 4, issue.fixed_version_id
1976 assert_equal 4, issue.fixed_version_id
1977 assert_not_equal issue.project_id, issue.fixed_version.project_id
1977 assert_not_equal issue.project_id, issue.fixed_version.project_id
1978 end
1978 end
1979 end
1979 end
1980
1980
1981 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1981 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1982 @request.session[:user_id] = 2
1982 @request.session[:user_id] = 2
1983 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1983 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1984
1984
1985 assert_response :redirect
1985 assert_response :redirect
1986 assert_redirected_to '/issues'
1986 assert_redirected_to '/issues'
1987 end
1987 end
1988
1988
1989 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1989 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1990 @request.session[:user_id] = 2
1990 @request.session[:user_id] = 2
1991 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1991 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1992
1992
1993 assert_response :redirect
1993 assert_response :redirect
1994 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1994 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1995 end
1995 end
1996
1996
1997 def test_destroy_issue_with_no_time_entries
1997 def test_destroy_issue_with_no_time_entries
1998 assert_nil TimeEntry.find_by_issue_id(2)
1998 assert_nil TimeEntry.find_by_issue_id(2)
1999 @request.session[:user_id] = 2
1999 @request.session[:user_id] = 2
2000 post :destroy, :id => 2
2000 delete :destroy, :id => 2
2001 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2001 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2002 assert_nil Issue.find_by_id(2)
2002 assert_nil Issue.find_by_id(2)
2003 end
2003 end
2004
2004
2005 def test_destroy_issues_with_time_entries
2005 def test_destroy_issues_with_time_entries
2006 @request.session[:user_id] = 2
2006 @request.session[:user_id] = 2
2007 post :destroy, :ids => [1, 3]
2007 delete :destroy, :ids => [1, 3]
2008 assert_response :success
2008 assert_response :success
2009 assert_template 'destroy'
2009 assert_template 'destroy'
2010 assert_not_nil assigns(:hours)
2010 assert_not_nil assigns(:hours)
2011 assert Issue.find_by_id(1) && Issue.find_by_id(3)
2011 assert Issue.find_by_id(1) && Issue.find_by_id(3)
2012 end
2012 end
2013
2013
2014 def test_destroy_issues_and_destroy_time_entries
2014 def test_destroy_issues_and_destroy_time_entries
2015 @request.session[:user_id] = 2
2015 @request.session[:user_id] = 2
2016 post :destroy, :ids => [1, 3], :todo => 'destroy'
2016 delete :destroy, :ids => [1, 3], :todo => 'destroy'
2017 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2017 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2018 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2018 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2019 assert_nil TimeEntry.find_by_id([1, 2])
2019 assert_nil TimeEntry.find_by_id([1, 2])
2020 end
2020 end
2021
2021
2022 def test_destroy_issues_and_assign_time_entries_to_project
2022 def test_destroy_issues_and_assign_time_entries_to_project
2023 @request.session[:user_id] = 2
2023 @request.session[:user_id] = 2
2024 post :destroy, :ids => [1, 3], :todo => 'nullify'
2024 delete :destroy, :ids => [1, 3], :todo => 'nullify'
2025 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2025 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2026 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2026 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2027 assert_nil TimeEntry.find(1).issue_id
2027 assert_nil TimeEntry.find(1).issue_id
2028 assert_nil TimeEntry.find(2).issue_id
2028 assert_nil TimeEntry.find(2).issue_id
2029 end
2029 end
2030
2030
2031 def test_destroy_issues_and_reassign_time_entries_to_another_issue
2031 def test_destroy_issues_and_reassign_time_entries_to_another_issue
2032 @request.session[:user_id] = 2
2032 @request.session[:user_id] = 2
2033 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
2033 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
2034 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2034 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
2035 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2035 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
2036 assert_equal 2, TimeEntry.find(1).issue_id
2036 assert_equal 2, TimeEntry.find(1).issue_id
2037 assert_equal 2, TimeEntry.find(2).issue_id
2037 assert_equal 2, TimeEntry.find(2).issue_id
2038 end
2038 end
2039
2039
2040 def test_destroy_issues_from_different_projects
2040 def test_destroy_issues_from_different_projects
2041 @request.session[:user_id] = 2
2041 @request.session[:user_id] = 2
2042 post :destroy, :ids => [1, 2, 6], :todo => 'destroy'
2042 delete :destroy, :ids => [1, 2, 6], :todo => 'destroy'
2043 assert_redirected_to :controller => 'issues', :action => 'index'
2043 assert_redirected_to :controller => 'issues', :action => 'index'
2044 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
2044 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
2045 end
2045 end
2046
2046
2047 def test_destroy_parent_and_child_issues
2047 def test_destroy_parent_and_child_issues
2048 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
2048 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
2049 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
2049 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
2050 assert child.is_descendant_of?(parent.reload)
2050 assert child.is_descendant_of?(parent.reload)
2051
2051
2052 @request.session[:user_id] = 2
2052 @request.session[:user_id] = 2
2053 assert_difference 'Issue.count', -2 do
2053 assert_difference 'Issue.count', -2 do
2054 post :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
2054 delete :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
2055 end
2055 end
2056 assert_response 302
2056 assert_response 302
2057 end
2057 end
2058
2058
2059 def test_default_search_scope
2059 def test_default_search_scope
2060 get :index
2060 get :index
2061 assert_tag :div, :attributes => {:id => 'quick-search'},
2061 assert_tag :div, :attributes => {:id => 'quick-search'},
2062 :child => {:tag => 'form',
2062 :child => {:tag => 'form',
2063 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
2063 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
2064 end
2064 end
2065 end
2065 end
General Comments 0
You need to be logged in to leave comments. Login now