OSDN Git Service

Adds ability to bulk copy issues (#1847).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 25 Jan 2009 13:12:56 +0000 (13:12 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 25 Jan 2009 13:12:56 +0000 (13:12 +0000)
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

app/controllers/issues_controller.rb
app/models/issue.rb
app/views/issues/move.rhtml
test/functional/issues_controller_test.rb
test/unit/issue_test.rb

index 3b7587c..27d00e7 100644 (file)
@@ -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?
index fa059cb..11db3f8 100644 (file)
@@ -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)
index 35761e1..8f43f18 100644 (file)
@@ -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) %>
index 093797e..b3978c3 100644 (file)
@@ -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
index ed7593a..b823032 100644 (file)
@@ -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)