Enhanced the Issue Bulk Copy feature:
* Add a Copy option to the Context menu for multiple issues. * Added assigned to, status, start and due date options to the move/copy form. * Allow Issue#move_to to change attributes on the moved/copied issue. #4117 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3122 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
c870a7b9ef
commit
e178123569
|
@ -271,13 +271,12 @@ class IssuesController < ApplicationController
|
|||
redirect_to(params[:back_to] || {:controller => 'issues', :action => 'index', :project_id => @project})
|
||||
return
|
||||
end
|
||||
# Find potential statuses the user could be allowed to switch issues to
|
||||
@available_statuses = Workflow.find(:all, :include => :new_status,
|
||||
:conditions => {:role_id => User.current.roles_for_project(@project).collect(&:id)}).collect(&:new_status).compact.uniq.sort
|
||||
@available_statuses = Workflow.available_statuses(@project)
|
||||
@custom_fields = @project.issue_custom_fields.select {|f| f.field_format == 'list'}
|
||||
end
|
||||
|
||||
def move
|
||||
@copy = params[:copy_options] && params[:copy_options][:copy]
|
||||
@allowed_projects = []
|
||||
# find projects to which the user is allowed to move the issue
|
||||
if User.current.admin?
|
||||
|
@ -289,13 +288,18 @@ class IssuesController < ApplicationController
|
|||
@target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id]
|
||||
@target_project ||= @project
|
||||
@trackers = @target_project.trackers
|
||||
@available_statuses = Workflow.available_statuses(@project)
|
||||
if request.post?
|
||||
new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id])
|
||||
unsaved_issue_ids = []
|
||||
moved_issues = []
|
||||
@issues.each do |issue|
|
||||
changed_attributes = {}
|
||||
[:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute|
|
||||
changed_attributes[valid_attribute] = params[valid_attribute] if params[valid_attribute]
|
||||
end
|
||||
issue.init_journal(User.current)
|
||||
if r = issue.move_to(@target_project, new_tracker, params[:copy_options])
|
||||
if r = issue.move_to(@target_project, new_tracker, {:copy => @copy, :attributes => changed_attributes})
|
||||
moved_issues << r
|
||||
else
|
||||
unsaved_issue_ids << issue.id
|
||||
|
|
|
@ -108,7 +108,15 @@ class Issue < ActiveRecord::Base
|
|||
end
|
||||
if options[:copy]
|
||||
issue.custom_field_values = self.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
|
||||
issue.status = self.status
|
||||
issue.status = if options[:attributes] && options[:attributes][:status_id]
|
||||
IssueStatus.find_by_id(options[:attributes][:status_id])
|
||||
else
|
||||
self.status
|
||||
end
|
||||
end
|
||||
# Allow bulk setting of attributes on the issue
|
||||
if options[:attributes]
|
||||
issue.attributes = options[:attributes]
|
||||
end
|
||||
if issue.save
|
||||
unless options[:copy]
|
||||
|
|
|
@ -40,4 +40,15 @@ class Workflow < ActiveRecord::Base
|
|||
|
||||
result
|
||||
end
|
||||
|
||||
# Find potential statuses the user could be allowed to switch issues to
|
||||
def self.available_statuses(project, user=User.current)
|
||||
Workflow.find(:all,
|
||||
:include => :new_status,
|
||||
:conditions => {:role_id => user.roles_for_project(project).collect(&:id)}).
|
||||
collect(&:new_status).
|
||||
compact.
|
||||
uniq.
|
||||
sort
|
||||
end
|
||||
end
|
||||
|
|
|
@ -88,8 +88,6 @@
|
|||
</li>
|
||||
|
||||
<% if !@issue.nil? %>
|
||||
<li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
|
||||
:class => 'icon-copy', :disabled => !@can[:copy] %></li>
|
||||
<% if @can[:log_time] -%>
|
||||
<li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue},
|
||||
:class => 'icon-time-add' %></li>
|
||||
|
@ -99,6 +97,14 @@
|
|||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if @issue.present? %>
|
||||
<li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
|
||||
:class => 'icon-copy', :disabled => !@can[:copy] %></li>
|
||||
<% else %>
|
||||
<li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id), :copy_options => {:copy => 't'}},
|
||||
:class => 'icon-copy', :disabled => !@can[:move] %></li>
|
||||
<% end %>
|
||||
|
||||
<li><%= context_menu_link l(:button_move), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id)},
|
||||
:class => 'icon-move', :disabled => !@can[:move] %></li>
|
||||
<li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)},
|
||||
|
|
|
@ -21,8 +21,30 @@
|
|||
<p><label for="new_tracker_id"><%=l(:field_tracker)%>:</label>
|
||||
<%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p>
|
||||
|
||||
<p>
|
||||
<label><%= l(:field_assigned_to) %></label>
|
||||
<%= select_tag('assigned_to_id', content_tag('option', l(:label_no_change_option), :value => '') +
|
||||
content_tag('option', l(:label_nobody), :value => 'none') +
|
||||
options_from_collection_for_select(@target_project.assignable_users, :id, :name)) %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label><%= l(:field_status) %></label>
|
||||
<%= select_tag('status_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label><%= l(:field_start_date) %></label>
|
||||
<%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label><%= l(:field_due_date) %></label>
|
||||
<%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %>
|
||||
</p>
|
||||
|
||||
<p><label for="copy_options_copy"><%= l(:button_copy)%></label>
|
||||
<%= check_box_tag "copy_options[copy]", "1" %></p>
|
||||
<%= check_box_tag "copy_options[copy]", "1", @copy %></p>
|
||||
</div>
|
||||
|
||||
<%= submit_tag l(:button_move) %>
|
||||
|
|
|
@ -1059,6 +1059,27 @@ class IssuesControllerTest < ActionController::TestCase
|
|||
assert_redirected_to 'projects/ecookbook/issues'
|
||||
end
|
||||
|
||||
context "#move via bulk copy" do
|
||||
should "allow changing the issue's attributes" do
|
||||
@request.session[:user_id] = 2
|
||||
assert_difference 'Issue.count', 2 do
|
||||
assert_no_difference 'Project.find(1).issues.count' do
|
||||
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'
|
||||
end
|
||||
end
|
||||
|
||||
copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
|
||||
assert_equal 2, copied_issues.size
|
||||
copied_issues.each do |issue|
|
||||
assert_equal 2, issue.project_id, "Project is incorrect"
|
||||
assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
|
||||
assert_equal 3, issue.status_id, "Status is incorrect"
|
||||
assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
|
||||
assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_copy_to_another_project_should_follow_when_needed
|
||||
@request.session[:user_id] = 2
|
||||
post :move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1'
|
||||
|
@ -1117,6 +1138,9 @@ class IssuesControllerTest < ActionController::TestCase
|
|||
assert_tag :tag => 'a', :content => 'Dave Lopper',
|
||||
:attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1&ids%5B%5D=2',
|
||||
:class => '' }
|
||||
assert_tag :tag => 'a', :content => 'Copy',
|
||||
:attributes => { :href => '/issues/move?copy_options%5Bcopy%5D=t&ids%5B%5D=1&ids%5B%5D=2',
|
||||
:class => 'icon-copy' }
|
||||
assert_tag :tag => 'a', :content => 'Move',
|
||||
:attributes => { :href => '/issues/move?ids%5B%5D=1&ids%5B%5D=2',
|
||||
:class => 'icon-move' }
|
||||
|
|
|
@ -352,6 +352,38 @@ class IssueTest < ActiveSupport::TestCase
|
|||
# Custom field #2 is not associated with target tracker
|
||||
assert_nil copy.custom_value_for(2)
|
||||
end
|
||||
|
||||
context "#move_to" do
|
||||
context "as a copy" do
|
||||
setup do
|
||||
@issue = Issue.find(1)
|
||||
@copy = nil
|
||||
end
|
||||
|
||||
should "allow assigned_to changes" do
|
||||
@copy = @issue.move_to(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:assigned_to_id => 3}})
|
||||
assert_equal 3, @copy.assigned_to_id
|
||||
end
|
||||
|
||||
should "allow status changes" do
|
||||
@copy = @issue.move_to(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:status_id => 2}})
|
||||
assert_equal 2, @copy.status_id
|
||||
end
|
||||
|
||||
should "allow start date changes" do
|
||||
date = Date.today
|
||||
@copy = @issue.move_to(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:start_date => date}})
|
||||
assert_equal date, @copy.start_date
|
||||
end
|
||||
|
||||
should "allow due date changes" do
|
||||
date = Date.today
|
||||
@copy = @issue.move_to(Project.find(3), Tracker.find(2), {:copy => true, :attributes => {:due_date => date}})
|
||||
|
||||
assert_equal date, @copy.due_date
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_recipients_should_not_include_users_that_cannot_view_the_issue
|
||||
issue = Issue.find(12)
|
||||
|
|
Loading…
Reference in New Issue