git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@10491 e93f8b46-1217-0410-a6f0-8f06a7374b81tags/2.2.0
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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') | |||