1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# frozen_string_literal: true
module Issuable
module Clone
class AttributesRewriter < ::Issuable::Clone::BaseService
def initialize(current_user, original_entity, new_entity)
@current_user = current_user
@original_entity = original_entity
@new_entity = new_entity
end
def execute
update_attributes = { labels: cloneable_labels }
milestone = matching_milestone(original_entity.milestone&.title)
update_attributes[:milestone] = milestone if milestone.present?
new_entity.update(update_attributes)
copy_resource_label_events
copy_resource_weight_events
copy_resource_milestone_events
copy_resource_state_events
end
private
def matching_milestone(title)
return if title.blank? || !new_entity.supports_milestone?
params = { title: title, project_ids: new_entity.project&.id, group_ids: group&.id }
milestones = MilestonesFinder.new(params).execute
milestones.first
end
def cloneable_labels
params = {
project_id: new_entity.project&.id,
group_id: group&.id,
title: original_entity.labels.select(:title),
include_ancestor_groups: true
}
params[:only_group_labels] = true if new_parent.is_a?(Group)
LabelsFinder.new(current_user, params).execute
end
def copy_resource_label_events
copy_events(ResourceLabelEvent.table_name, original_entity.resource_label_events) do |event|
event.attributes
.except('id', 'reference', 'reference_html')
.merge(entity_key => new_entity.id, 'action' => ResourceLabelEvent.actions[event.action])
end
end
def copy_resource_weight_events
return unless original_entity.respond_to?(:resource_weight_events)
copy_events(ResourceWeightEvent.table_name, original_entity.resource_weight_events) do |event|
event.attributes
.except('id', 'reference', 'reference_html')
.merge('issue_id' => new_entity.id)
end
end
def copy_resource_milestone_events
return unless milestone_events_supported?
copy_events(ResourceMilestoneEvent.table_name, original_entity.resource_milestone_events) do |event|
if event.remove?
event_attributes_with_milestone(event, nil)
else
matching_destination_milestone = matching_milestone(event.milestone_title)
event_attributes_with_milestone(event, matching_destination_milestone) if matching_destination_milestone.present?
end
end
end
def copy_resource_state_events
return unless state_events_supported?
copy_events(ResourceStateEvent.table_name, original_entity.resource_state_events) do |event|
event.attributes
.except('id')
.merge(entity_key => new_entity.id,
'state' => ResourceStateEvent.states[event.state])
end
end
def event_attributes_with_milestone(event, milestone)
event.attributes
.except('id')
.merge(entity_key => new_entity.id,
'milestone_id' => milestone&.id,
'action' => ResourceMilestoneEvent.actions[event.action],
'state' => ResourceMilestoneEvent.states[event.state])
end
def copy_events(table_name, events_to_copy)
events_to_copy.find_in_batches do |batch|
events = batch.map do |event|
yield(event)
end.compact
Gitlab::Database.bulk_insert(table_name, events)
end
end
def entity_key
new_entity.class.name.underscore.foreign_key
end
def milestone_events_supported?
both_respond_to?(:resource_milestone_events)
end
def state_events_supported?
both_respond_to?(:resource_state_events)
end
def both_respond_to?(method)
original_entity.respond_to?(method) &&
new_entity.respond_to?(method)
end
end
end
end
|