From cc4cff9f11b453c6fe308da6867819b4717e8d1a Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Thu, 27 Sep 2012 19:09:30 +0000 Subject: [PATCH] Adds a "Copied from/to" relation when copying issue(s) (#6899). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@10491 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/issue.rb | 17 +++++++++++---- app/models/issue_relation.rb | 6 +++++- config/locales/en.yml | 2 ++ config/locales/fr.yml | 2 ++ test/functional/issues_controller_test.rb | 26 +++++++++++++++++++++++ test/unit/issue_test.rb | 13 ++++++++++++ 6 files changed, 61 insertions(+), 5 deletions(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index 86371d5f7..0d226455d 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -1011,11 +1011,20 @@ class Issue < ActiveRecord::Base end end - # Copies subtasks from the copied issue + # Callback for after the creation of an issue by copy + # * adds a "copied to" relation with the copied issue + # * copies subtasks from the copied issue def after_create_from_copy - return unless copy? + return unless copy? && !@after_create_from_copy_handled - unless @copied_from.leaf? || @copy_options[:subtasks] == false || @subtasks_copied + if @copied_from.project_id == project_id || Setting.cross_project_issue_relations? + relation = IssueRelation.new(:issue_from => @copied_from, :issue_to => self, :relation_type => IssueRelation::TYPE_COPIED_TO) + unless relation.save + logger.error "Could not create relation while copying ##{@copied_from.id} to ##{id} due to validation errors: #{relation.errors.full_messages.join(', ')}" if logger + end + end + + unless @copied_from.leaf? || @copy_options[:subtasks] == false @copied_from.children.each do |child| unless child.visible? # Do not copy subtasks that are not visible to avoid potential disclosure of private data @@ -1031,8 +1040,8 @@ class Issue < ActiveRecord::Base logger.error "Could not copy subtask ##{child.id} while copying ##{@copied_from.id} to ##{id} due to validation errors: #{copy.errors.full_messages.join(', ')}" if logger end end - @subtasks_copied = true end + @after_create_from_copy_handled = true end def update_nested_set_attributes diff --git a/app/models/issue_relation.rb b/app/models/issue_relation.rb index 2efcfb41a..c145b87b9 100644 --- a/app/models/issue_relation.rb +++ b/app/models/issue_relation.rb @@ -26,6 +26,8 @@ class IssueRelation < ActiveRecord::Base TYPE_BLOCKED = "blocked" TYPE_PRECEDES = "precedes" TYPE_FOLLOWS = "follows" + TYPE_COPIED_TO = "copied_to" + TYPE_COPIED_FROM = "copied_from" TYPES = { TYPE_RELATES => { :name => :label_relates_to, :sym_name => :label_relates_to, :order => 1, :sym => TYPE_RELATES }, TYPE_DUPLICATES => { :name => :label_duplicates, :sym_name => :label_duplicated_by, :order => 2, :sym => TYPE_DUPLICATED }, @@ -33,7 +35,9 @@ class IssueRelation < ActiveRecord::Base TYPE_BLOCKS => { :name => :label_blocks, :sym_name => :label_blocked_by, :order => 4, :sym => TYPE_BLOCKED }, TYPE_BLOCKED => { :name => :label_blocked_by, :sym_name => :label_blocks, :order => 5, :sym => TYPE_BLOCKS, :reverse => TYPE_BLOCKS }, TYPE_PRECEDES => { :name => :label_precedes, :sym_name => :label_follows, :order => 6, :sym => TYPE_FOLLOWS }, - TYPE_FOLLOWS => { :name => :label_follows, :sym_name => :label_precedes, :order => 7, :sym => TYPE_PRECEDES, :reverse => TYPE_PRECEDES } + TYPE_FOLLOWS => { :name => :label_follows, :sym_name => :label_precedes, :order => 7, :sym => TYPE_PRECEDES, :reverse => TYPE_PRECEDES }, + TYPE_COPIED_TO => { :name => :label_copied_to, :sym_name => :label_copied_from, :order => 8, :sym => TYPE_COPIED_FROM }, + TYPE_COPIED_FROM => { :name => :label_copied_from, :sym_name => :label_copied_to, :order => 9, :sym => TYPE_COPIED_TO, :reverse => TYPE_COPIED_TO } }.freeze validates_presence_of :issue_from, :issue_to, :relation_type diff --git a/config/locales/en.yml b/config/locales/en.yml index 0133ce247..7ccf38231 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -744,6 +744,8 @@ en: label_blocked_by: blocked by label_precedes: precedes label_follows: follows + label_copied_to: copied to + label_copied_from: copied from label_end_to_start: end to start label_end_to_end: end to end label_start_to_start: start to start diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 7bc0d3a02..f71de45a2 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -728,6 +728,8 @@ fr: label_blocked_by: bloqué par label_precedes: précède label_follows: suit + label_copied_to: copié vers + label_copied_from: copié depuis label_end_to_start: fin à début label_end_to_end: fin à fin label_start_to_start: début à début diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index fdd995c56..b6e583fda 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -2357,6 +2357,19 @@ class IssuesControllerTest < ActionController::TestCase assert_equal count + 1, copy.attachments.count end + def test_create_as_copy_should_add_relation_with_copied_issue + @request.session[:user_id] = 2 + + assert_difference 'Issue.count' do + assert_difference 'IssueRelation.count' do + post :create, :project_id => 1, :copy_from => 1, + :issue => {:project_id => '1', :tracker_id => '3', :status_id => '1', :subject => 'Copy'} + end + end + copy = Issue.first(:order => 'id DESC') + assert_equal 1, copy.relations.size + end + def test_create_as_copy_should_copy_subtasks @request.session[:user_id] = 2 issue = Issue.generate_with_descendants!(Project.find(1), :subject => 'Parent') @@ -3512,6 +3525,19 @@ class IssuesControllerTest < ActionController::TestCase end end + def test_bulk_copy_should_add_relations_with_copied_issues + @request.session[:user_id] = 2 + + assert_difference 'Issue.count', 2 do + assert_difference 'IssueRelation.count', 2 do + post :bulk_update, :ids => [1, 3], :copy => '1', + :issue => { + :project_id => '1' + } + end + end + end + def test_bulk_copy_should_allow_not_copying_the_subtasks issue = Issue.generate_with_descendants!(Project.find(1), :subject => 'Parent') @request.session[:user_id] = 2 diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index fc08313bc..7fdd9cf0f 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -636,6 +636,19 @@ class IssueTest < ActiveSupport::TestCase assert_equal orig.status, issue.status end + def test_copy_should_add_relation_with_copied_issue + copied = Issue.find(1) + issue = Issue.new.copy_from(copied) + assert issue.save + issue.reload + + assert_equal 1, issue.relations.size + relation = issue.relations.first + assert_equal 'copied_to', relation.relation_type + assert_equal copied, relation.issue_from + assert_equal issue, relation.issue_to + end + def test_copy_should_copy_subtasks issue = Issue.generate_with_descendants!(Project.find(1), :subject => 'Parent')