@@ -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, |
|
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&ids%5B%5D=1&ids%5B%5D=2', |
|
1139 | :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1&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&ids%5B%5D=1&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&ids%5B%5D=2', |
|
1145 | :attributes => { :href => '/issues/move?ids%5B%5D=1&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