Fixes #2347 - Merging two Tickets with link to same other Ticket fails.
This commit is contained in:
parent
7e9ce7e3ed
commit
f132225b2f
4 changed files with 144 additions and 5 deletions
|
@ -244,4 +244,32 @@ class Link < ApplicationModel
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.duplicates(object1_id:, object1_value:, object2_value:, object2_id: nil)
|
||||||
|
if !object2_id
|
||||||
|
object2_id = object1_id
|
||||||
|
end
|
||||||
|
|
||||||
|
Link.joins(', links as linksb').where('
|
||||||
|
(
|
||||||
|
links.link_type_id = linksb.link_type_id
|
||||||
|
AND links.link_object_source_id = linksb.link_object_source_id
|
||||||
|
AND links.link_object_source_value = linksb.link_object_source_value
|
||||||
|
AND links.link_object_target_id = ?
|
||||||
|
AND linksb.link_object_target_id = ?
|
||||||
|
AND links.link_object_target_value = ?
|
||||||
|
AND linksb.link_object_target_value = ?
|
||||||
|
)
|
||||||
|
OR
|
||||||
|
(
|
||||||
|
links.link_type_id = linksb.link_type_id
|
||||||
|
AND links.link_object_target_id = linksb.link_object_target_id
|
||||||
|
AND links.link_object_target_value = linksb.link_object_target_value
|
||||||
|
AND links.link_object_source_id = ?
|
||||||
|
AND linksb.link_object_source_id = ?
|
||||||
|
AND links.link_object_source_value = ?
|
||||||
|
AND linksb.link_object_source_value = ?
|
||||||
|
)
|
||||||
|
', object1_id, object2_id, object1_value, object2_value, object1_id, object2_id, object1_value, object2_value)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -357,12 +357,21 @@ returns
|
||||||
|
|
||||||
# reassign links to the new ticket
|
# reassign links to the new ticket
|
||||||
# rubocop:disable Rails/SkipsModelValidations
|
# rubocop:disable Rails/SkipsModelValidations
|
||||||
|
ticket_source_id = Link::Object.find_by(name: 'Ticket').id
|
||||||
|
|
||||||
|
# search for all duplicate source and target links and destroy them
|
||||||
|
# before link merging
|
||||||
|
Link.duplicates(
|
||||||
|
object1_id: ticket_source_id,
|
||||||
|
object1_value: id,
|
||||||
|
object2_value: data[:ticket_id]
|
||||||
|
).destroy_all
|
||||||
Link.where(
|
Link.where(
|
||||||
link_object_source_id: Link::Object.find_by(name: 'Ticket').id,
|
link_object_source_id: ticket_source_id,
|
||||||
link_object_source_value: id,
|
link_object_source_value: id,
|
||||||
).update_all(link_object_source_value: data[:ticket_id])
|
).update_all(link_object_source_value: data[:ticket_id])
|
||||||
Link.where(
|
Link.where(
|
||||||
link_object_target_id: Link::Object.find_by(name: 'Ticket').id,
|
link_object_target_id: ticket_source_id,
|
||||||
link_object_target_value: id,
|
link_object_target_value: id,
|
||||||
).update_all(link_object_target_value: data[:ticket_id])
|
).update_all(link_object_target_value: data[:ticket_id])
|
||||||
# rubocop:enable Rails/SkipsModelValidations
|
# rubocop:enable Rails/SkipsModelValidations
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :link do
|
factory :link do
|
||||||
transient do
|
transient do
|
||||||
|
link_type { 'normal' }
|
||||||
|
link_object_source { 'Ticket' }
|
||||||
|
link_object_target { 'Ticket' }
|
||||||
from { Ticket.first }
|
from { Ticket.first }
|
||||||
to { Ticket.last }
|
to { Ticket.last }
|
||||||
end
|
end
|
||||||
|
|
||||||
link_type_id { Link::Type.find_by(name: 'normal').id }
|
link_type_id { Link::Type.create_if_not_exists(name: link_type, active: true).id }
|
||||||
link_object_source_id { Link::Object.find_by(name: 'Ticket').id }
|
link_object_source_id { Link::Object.create_if_not_exists(name: link_object_source).id }
|
||||||
link_object_target_id { Link::Object.find_by(name: 'Ticket').id }
|
link_object_target_id { Link::Object.create_if_not_exists(name: link_object_target).id }
|
||||||
link_object_source_value { from.id }
|
link_object_source_value { from.id }
|
||||||
link_object_target_value { to.id }
|
link_object_target_value { to.id }
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,6 +83,105 @@ RSpec.describe Ticket, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when both tickets are linked with the same parent (parent->child)' do
|
||||||
|
let(:parent) { create(:ticket) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:link,
|
||||||
|
link_type: 'child',
|
||||||
|
link_object_source_value: ticket.id,
|
||||||
|
link_object_target_value: parent.id)
|
||||||
|
create(:link,
|
||||||
|
link_type: 'child',
|
||||||
|
link_object_source_value: target_ticket.id,
|
||||||
|
link_object_target_value: parent.id)
|
||||||
|
|
||||||
|
ticket.merge_to(ticket_id: target_ticket.id, user_id: 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does remove the link from the merged ticket' do
|
||||||
|
links = Link.list(
|
||||||
|
link_object: 'Ticket',
|
||||||
|
link_object_value: ticket.id
|
||||||
|
)
|
||||||
|
expect(links.count).to eq(1) # one link to the source ticket (no parent link)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not remove the link from the target ticket' do
|
||||||
|
links = Link.list(
|
||||||
|
link_object: 'Ticket',
|
||||||
|
link_object_value: target_ticket.id
|
||||||
|
)
|
||||||
|
expect(links.count).to eq(2) # one link to the merged ticket + parent link
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when both tickets are linked with the same parent (child->parent)' do
|
||||||
|
let(:parent) { create(:ticket) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:link,
|
||||||
|
link_type: 'child',
|
||||||
|
link_object_source_value: parent.id,
|
||||||
|
link_object_target_value: ticket.id)
|
||||||
|
create(:link,
|
||||||
|
link_type: 'child',
|
||||||
|
link_object_source_value: parent.id,
|
||||||
|
link_object_target_value: target_ticket.id)
|
||||||
|
|
||||||
|
ticket.merge_to(ticket_id: target_ticket.id, user_id: 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does remove the link from the merged ticket' do
|
||||||
|
links = Link.list(
|
||||||
|
link_object: 'Ticket',
|
||||||
|
link_object_value: ticket.id
|
||||||
|
)
|
||||||
|
expect(links.count).to eq(1) # one link to the source ticket (no parent link)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not remove the link from the target ticket' do
|
||||||
|
links = Link.list(
|
||||||
|
link_object: 'Ticket',
|
||||||
|
link_object_value: target_ticket.id
|
||||||
|
)
|
||||||
|
expect(links.count).to eq(2) # one link to the merged ticket + parent link
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when both tickets are linked with the same parent (different link types)' do
|
||||||
|
let(:parent) { create(:ticket) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:link,
|
||||||
|
link_type: 'normal',
|
||||||
|
link_object_source_value: parent.id,
|
||||||
|
link_object_target_value: ticket.id)
|
||||||
|
create(:link,
|
||||||
|
link_type: 'child',
|
||||||
|
link_object_source_value: parent.id,
|
||||||
|
link_object_target_value: target_ticket.id)
|
||||||
|
|
||||||
|
ticket.merge_to(ticket_id: target_ticket.id, user_id: 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does remove the link from the merged ticket' do
|
||||||
|
links = Link.list(
|
||||||
|
link_object: 'Ticket',
|
||||||
|
link_object_value: ticket.id
|
||||||
|
)
|
||||||
|
expect(links.count).to eq(1) # one link to the source ticket (no normal link)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not remove the link from the target ticket' do
|
||||||
|
links = Link.list(
|
||||||
|
link_object: 'Ticket',
|
||||||
|
link_object_value: target_ticket.id
|
||||||
|
)
|
||||||
|
expect(links.count).to eq(3) # one lin to the merged ticket + parent link + normal link
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when merging' do
|
context 'when merging' do
|
||||||
let(:merge_user) { create(:user) }
|
let(:merge_user) { create(:user) }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue