##// END OF EJS Templates
Enhanced the Issue Bulk Copy feature:...
Eric Davis -
r3008:e1781235696f
parent child
Show More
@@ -271,13 +271,12 class IssuesController < ApplicationController
271 redirect_to(params[:back_to] || {:controller => 'issues', :action => 'index', :project_id => @project})
271 redirect_to(params[:back_to] || {:controller => 'issues', :action => 'index', :project_id => @project})
272 return
272 return
273 end
273 end
274 # Find potential statuses the user could be allowed to switch issues to
274 @available_statuses = Workflow.available_statuses(@project)
275 @available_statuses = Workflow.find(:all, :include => :new_status,
276 :conditions => {:role_id => User.current.roles_for_project(@project).collect(&:id)}).collect(&:new_status).compact.uniq.sort
277 @custom_fields = @project.issue_custom_fields.select {|f| f.field_format == 'list'}
275 @custom_fields = @project.issue_custom_fields.select {|f| f.field_format == 'list'}
278 end
276 end
279
277
280 def move
278 def move
279 @copy = params[:copy_options] && params[:copy_options][:copy]
281 @allowed_projects = []
280 @allowed_projects = []
282 # find projects to which the user is allowed to move the issue
281 # find projects to which the user is allowed to move the issue
283 if User.current.admin?
282 if User.current.admin?
@@ -289,13 +288,18 class IssuesController < ApplicationController
289 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id]
288 @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id]
290 @target_project ||= @project
289 @target_project ||= @project
291 @trackers = @target_project.trackers
290 @trackers = @target_project.trackers
291 @available_statuses = Workflow.available_statuses(@project)
292 if request.post?
292 if request.post?
293 new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id])
293 new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id])
294 unsaved_issue_ids = []
294 unsaved_issue_ids = []
295 moved_issues = []
295 moved_issues = []
296 @issues.each do |issue|
296 @issues.each do |issue|
297 changed_attributes = {}
298 [:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute|
299 changed_attributes[valid_attribute] = params[valid_attribute] if params[valid_attribute]
300 end
297 issue.init_journal(User.current)
301 issue.init_journal(User.current)
298 if r = issue.move_to(@target_project, new_tracker, params[:copy_options])
302 if r = issue.move_to(@target_project, new_tracker, {:copy => @copy, :attributes => changed_attributes})
299 moved_issues << r
303 moved_issues << r
300 else
304 else
301 unsaved_issue_ids << issue.id
305 unsaved_issue_ids << issue.id
@@ -108,7 +108,15 class Issue < ActiveRecord::Base
108 end
108 end
109 if options[:copy]
109 if options[:copy]
110 issue.custom_field_values = self.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
110 issue.custom_field_values = self.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
111 issue.status = self.status
111 issue.status = if options[:attributes] && options[:attributes][:status_id]
112 IssueStatus.find_by_id(options[:attributes][:status_id])
113 else
114 self.status
115 end
116 end
117 # Allow bulk setting of attributes on the issue
118 if options[:attributes]
119 issue.attributes = options[:attributes]
112 end
120 end
113 if issue.save
121 if issue.save
114 unless options[:copy]
122 unless options[:copy]
@@ -40,4 +40,15 class Workflow < ActiveRecord::Base
40
40
41 result
41 result
42 end
42 end
43
44 # Find potential statuses the user could be allowed to switch issues to
45 def self.available_statuses(project, user=User.current)
46 Workflow.find(:all,
47 :include => :new_status,
48 :conditions => {:role_id => user.roles_for_project(project).collect(&:id)}).
49 collect(&:new_status).
50 compact.
51 uniq.
52 sort
53 end
43 end
54 end
@@ -88,8 +88,6
88 </li>
88 </li>
89
89
90 <% if !@issue.nil? %>
90 <% if !@issue.nil? %>
91 <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
92 :class => 'icon-copy', :disabled => !@can[:copy] %></li>
93 <% if @can[:log_time] -%>
91 <% if @can[:log_time] -%>
94 <li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue},
92 <li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue},
95 :class => 'icon-time-add' %></li>
93 :class => 'icon-time-add' %></li>
@@ -99,6 +97,14
99 <% end %>
97 <% end %>
100 <% end %>
98 <% end %>
101
99
100 <% if @issue.present? %>
101 <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
102 :class => 'icon-copy', :disabled => !@can[:copy] %></li>
103 <% else %>
104 <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id), :copy_options => {:copy => 't'}},
105 :class => 'icon-copy', :disabled => !@can[:move] %></li>
106 <% end %>
107
102 <li><%= context_menu_link l(:button_move), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id)},
108 <li><%= context_menu_link l(:button_move), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id)},
103 :class => 'icon-move', :disabled => !@can[:move] %></li>
109 :class => 'icon-move', :disabled => !@can[:move] %></li>
104 <li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)},
110 <li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)},
@@ -21,8 +21,30
21 <p><label for="new_tracker_id"><%=l(:field_tracker)%>:</label>
21 <p><label for="new_tracker_id"><%=l(:field_tracker)%>:</label>
22 <%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p>
22 <%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p>
23
23
24 <p>
25 <label><%= l(:field_assigned_to) %></label>
26 <%= select_tag('assigned_to_id', content_tag('option', l(:label_no_change_option), :value => '') +
27 content_tag('option', l(:label_nobody), :value => 'none') +
28 options_from_collection_for_select(@target_project.assignable_users, :id, :name)) %>
29 </p>
30
31 <p>
32 <label><%= l(:field_status) %></label>
33 <%= select_tag('status_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %>
34 </p>
35
36 <p>
37 <label><%= l(:field_start_date) %></label>
38 <%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %>
39 </p>
40
41 <p>
42 <label><%= l(:field_due_date) %></label>
43 <%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %>
44 </p>
45
24 <p><label for="copy_options_copy"><%= l(:button_copy)%></label>
46 <p><label for="copy_options_copy"><%= l(:button_copy)%></label>
25 <%= check_box_tag "copy_options[copy]", "1" %></p>
47 <%= check_box_tag "copy_options[copy]", "1", @copy %></p>
26 </div>
48 </div>
27
49
28 <%= submit_tag l(:button_move) %>
50 <%= submit_tag l(:button_move) %>
@@ -1059,6 +1059,27 class IssuesControllerTest < ActionController::TestCase
1059 assert_redirected_to 'projects/ecookbook/issues'
1059 assert_redirected_to 'projects/ecookbook/issues'
1060 end
1060 end
1061
1061
1062 context "#move via bulk copy" do
1063 should "allow changing the issue's attributes" do
1064 @request.session[:user_id] = 2
1065 assert_difference 'Issue.count', 2 do
1066 assert_no_difference 'Project.find(1).issues.count' do
1067 post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}, :assigned_to_id => 4, :status_id => 3, :start_date => '2009-12-01', :due_date => '2009-12-31'
1068 end
1069 end
1070
1071 copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
1072 assert_equal 2, copied_issues.size
1073 copied_issues.each do |issue|
1074 assert_equal 2, issue.project_id, "Project is incorrect"
1075 assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
1076 assert_equal 3, issue.status_id, "Status is incorrect"
1077 assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
1078 assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
1079 end
1080 end
1081 end
1082
1062 def test_copy_to_another_project_should_follow_when_needed
1083 def test_copy_to_another_project_should_follow_when_needed
1063 @request.session[:user_id] = 2
1084 @request.session[:user_id] = 2
1064 post :move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1'
1085 post :move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1'
@@ -1117,6 +1138,9 class IssuesControllerTest < ActionController::TestCase
1117 assert_tag :tag => 'a', :content => 'Dave Lopper',
1138 assert_tag :tag => 'a', :content => 'Dave Lopper',
1118 :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&amp;ids%5B%5D=1&amp;ids%5B%5D=2',
1139 :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&amp;ids%5B%5D=1&amp;ids%5B%5D=2',
1119 :class => '' }
1140 :class => '' }
1141 assert_tag :tag => 'a', :content => 'Copy',
1142 :attributes => { :href => '/issues/move?copy_options%5Bcopy%5D=t&amp;ids%5B%5D=1&amp;ids%5B%5D=2',
1143 :class => 'icon-copy' }
1120 assert_tag :tag => 'a', :content => 'Move',
1144 assert_tag :tag => 'a', :content => 'Move',
1121 :attributes => { :href => '/issues/move?ids%5B%5D=1&amp;ids%5B%5D=2',
1145 :attributes => { :href => '/issues/move?ids%5B%5D=1&amp;ids%5B%5D=2',
1122 :class => 'icon-move' }
1146 :class => 'icon-move' }
@@ -352,6 +352,38 class IssueTest < ActiveSupport::TestCase
352 # Custom field #2 is not associated with target tracker
352 # Custom field #2 is not associated with target tracker
353 assert_nil copy.custom_value_for(2)
353 assert_nil copy.custom_value_for(2)
354 end
354 end
355
356 context "#move_to" do
357 context "as a copy" do
358 setup do
359 @issue = Issue.find(1)
360 @copy = nil
361 end
362
363 should "allow assigned_to changes" do
364 @copy = @issue.move_to(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}})
365 assert_equal 3, @copy.assigned_to_id
366 end
367
368 should "allow status changes" do
369 @copy = @issue.move_to(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:status_id => 2}})
370 assert_equal 2, @copy.status_id
371 end
372
373 should "allow start date changes" do
374 date = Date.today
375 @copy = @issue.move_to(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}})
376 assert_equal date, @copy.start_date
377 end
378
379 should "allow due date changes" do
380 date = Date.today
381 @copy = @issue.move_to(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:due_date => date}})
382
383 assert_equal date, @copy.due_date
384 end
385 end
386 end
355
387
356 def test_recipients_should_not_include_users_that_cannot_view_the_issue
388 def test_recipients_should_not_include_users_that_cannot_view_the_issue
357 issue = Issue.find(12)
389 issue = Issue.find(12)
General Comments 0
You need to be logged in to leave comments. Login now