From 1ad255155949930d2a7bdf667b415939fd71e16d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 25 Jan 2009 13:12:56 +0000 Subject: [PATCH] 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 --- app/controllers/issues_controller.rb | 2 +- app/models/issue.rb | 39 ++++++++++++++--------- app/views/issues/move.rhtml | 3 ++ test/functional/issues_controller_test.rb | 10 ++++++ test/unit/issue_test.rb | 24 ++++++++++++++ 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 @@

<%= select_tag "new_tracker_id", "" + options_from_collection_for_select(@trackers, "id", "name") %>

+ +

+<%= check_box_tag "copy_options[copy]", "1" %>

<%= 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)