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