summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2009-01-25 13:12:56 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2009-01-25 13:12:56 +0000
commit1ad255155949930d2a7bdf667b415939fd71e16d (patch)
tree6cc4801f6379e3e5e7f178e417d158f410c3a9ac
parent41f3bae9170c5231a85c1b85b1596fba8e2f6d77 (diff)
downloadredmine-1ad255155949930d2a7bdf667b415939fd71e16d.tar.gz
redmine-1ad255155949930d2a7bdf667b415939fd71e16d.zip
Adds ability to bulk copy issues (#1847).
This can be done by checking the 'Copy' checkbox on the 'Move' form. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2313 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r--app/controllers/issues_controller.rb2
-rw-r--r--app/models/issue.rb39
-rw-r--r--app/views/issues/move.rhtml3
-rw-r--r--test/functional/issues_controller_test.rb10
-rw-r--r--test/unit/issue_test.rb24
5 files changed, 62 insertions, 16 deletions
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index 3b7587c15..27d00e721 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -283,7 +283,7 @@ class IssuesController < ApplicationController
unsaved_issue_ids = []
@issues.each do |issue|
issue.init_journal(User.current)
- unsaved_issue_ids << issue.id unless issue.move_to(@target_project, new_tracker)
+ unsaved_issue_ids << issue.id unless issue.move_to(@target_project, new_tracker, params[:copy_options])
end
if unsaved_issue_ids.empty?
flash[:notice] = l(:notice_successful_update) unless @issues.empty?
diff --git a/app/models/issue.rb b/app/models/issue.rb
index fa059cbd9..11db3f89d 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -71,34 +71,43 @@ class Issue < ActiveRecord::Base
self
end
- # Move an issue to a new project and tracker
- def move_to(new_project, new_tracker = nil)
+ # Moves/copies an issue to a new project and tracker
+ # Returns the moved/copied issue on success, false on failure
+ def move_to(new_project, new_tracker = nil, options = {})
+ options ||= {}
+ issue = options[:copy] ? self.clone : self
transaction do
- if new_project && project_id != new_project.id
+ if new_project && issue.project_id != new_project.id
# delete issue relations
unless Setting.cross_project_issue_relations?
- self.relations_from.clear
- self.relations_to.clear
+ issue.relations_from.clear
+ issue.relations_to.clear
end
# issue is moved to another project
# reassign to the category with same name if any
- new_category = category.nil? ? nil : new_project.issue_categories.find_by_name(category.name)
- self.category = new_category
- self.fixed_version = nil
- self.project = new_project
+ new_category = issue.category.nil? ? nil : new_project.issue_categories.find_by_name(issue.category.name)
+ issue.category = new_category
+ issue.fixed_version = nil
+ issue.project = new_project
end
if new_tracker
- self.tracker = new_tracker
+ issue.tracker = new_tracker
end
- if save
- # Manually update project_id on related time entries
- TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id})
+ 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
+ end
+ if issue.save
+ unless options[:copy]
+ # Manually update project_id on related time entries
+ TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id})
+ end
else
- rollback_db_transaction
+ Issue.connection.rollback_db_transaction
return false
end
end
- return true
+ return issue
end
def priority_id=(pid)
diff --git a/app/views/issues/move.rhtml b/app/views/issues/move.rhtml
index 35761e160..8f43f18c5 100644
--- a/app/views/issues/move.rhtml
+++ b/app/views/issues/move.rhtml
@@ -16,6 +16,9 @@
<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 for="copy_options_copy"><%= l(:button_copy)%></label>
+<%= check_box_tag "copy_options[copy]", "1" %></p>
</div>
<%= submit_tag l(:button_move) %>
diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb
index 093797e38..b3978c39c 100644
--- a/test/functional/issues_controller_test.rb
+++ b/test/functional/issues_controller_test.rb
@@ -672,6 +672,16 @@ class IssuesControllerTest < Test::Unit::TestCase
assert_equal 2, Issue.find(1).tracker_id
assert_equal 2, Issue.find(2).tracker_id
end
+
+ def test_bulk_copy_to_another_project
+ @request.session[:user_id] = 1
+ 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'}
+ end
+ end
+ assert_redirected_to 'projects/ecookbook/issues'
+ end
def test_context_menu_one_issue
@request.session[:user_id] = 2
diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb
index ed7593a30..b82303264 100644
--- a/test/unit/issue_test.rb
+++ b/test/unit/issue_test.rb
@@ -191,6 +191,30 @@ class IssueTest < Test::Unit::TestCase
assert_nil issue.category_id
end
+ def test_copy_to_the_same_project
+ issue = Issue.find(1)
+ copy = nil
+ assert_difference 'Issue.count' do
+ copy = issue.move_to(issue.project, nil, :copy => true)
+ end
+ assert_kind_of Issue, copy
+ assert_equal issue.project, copy.project
+ assert_equal "125", copy.custom_value_for(2).value
+ end
+
+ def test_copy_to_another_project_and_tracker
+ issue = Issue.find(1)
+ copy = nil
+ assert_difference 'Issue.count' do
+ copy = issue.move_to(Project.find(3), Tracker.find(2), :copy => true)
+ end
+ assert_kind_of Issue, copy
+ assert_equal Project.find(3), copy.project
+ assert_equal Tracker.find(2), copy.tracker
+ # Custom field #2 is not associated with target tracker
+ assert_nil copy.custom_value_for(2)
+ end
+
def test_issue_destroy
Issue.find(1).destroy
assert_nil Issue.find_by_id(1)