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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
# frozen_string_literal: true
module Gitlab
module ImportExport
class MembersMapper
def initialize(exported_members:, user:, importable:)
@exported_members = user.admin? ? exported_members : []
@user = user
@importable = importable
# This needs to run first, as second call would be from #map
# which means Project/Group members already exist.
ensure_default_member!
end
def map
@map ||=
begin
@exported_members.inject(missing_keys_tracking_hash) do |hash, member|
if member['user']
old_user_id = member['user']['id']
existing_user = User.find_by(find_user_query(member))
hash[old_user_id] = existing_user.id if existing_user && add_team_member(member, existing_user)
else
add_team_member(member)
end
hash
end
end
end
def default_user_id
@user.id
end
def include?(old_author_id)
map.has_key?(old_author_id) && map[old_author_id] != default_user_id
end
private
def missing_keys_tracking_hash
Hash.new do |_, key|
default_user_id
end
end
def ensure_default_member!
return if user_already_member?
@importable.members.destroy_all # rubocop: disable DestroyAll
relation_class.create!(user: @user, access_level: highest_access_level, source_id: @importable.id, importing: true)
rescue => e
raise e, "Error adding importer user to #{@importable.class} members. #{e.message}"
end
def user_already_member?
member = @importable.members&.first
member&.user == @user && member.access_level >= highest_access_level
end
def add_team_member(member, existing_user = nil)
member['user'] = existing_user
member_hash = member_hash(member)
member = relation_class.create(member_hash)
if member.persisted?
log_member_addition(member_hash)
true
else
log_member_addition_failure(member_hash, member.errors.full_messages)
false
end
end
def member_hash(member)
parsed_hash(member).merge(
'source_id' => @importable.id,
'importing' => true,
'access_level' => [member['access_level'], highest_access_level].min
).except('user_id')
end
def parsed_hash(member)
Gitlab::ImportExport::AttributeCleaner.clean(relation_hash: member.deep_stringify_keys,
relation_class: relation_class)
end
def find_user_query(member)
user_arel[:email].eq(member['user']['email'])
end
def user_arel
@user_arel ||= User.arel_table
end
def relation_class
case @importable
when ::Project
ProjectMember
when ::Group
GroupMember
end
end
def highest_access_level
return relation_class::OWNER if relation_class == GroupMember
relation_class::MAINTAINER
end
def log_member_addition(member_hash)
log_params = base_log_params(member_hash)
log_params[:message] = '[Project/Group Import] Added new member'
logger.info(log_params)
end
def log_member_addition_failure(member_hash, errors)
log_params = base_log_params(member_hash)
log_params[:message] = "[Project/Group Import] Member addition failed: #{errors&.join(', ')}"
logger.info(log_params)
end
def base_log_params(member_hash)
{
user_id: member_hash['user']&.id,
access_level: member_hash['access_level'],
importable_type: @importable.class.to_s,
importable_id: @importable.id,
root_namespace_id: @importable.try(:root_ancestor)&.id
}
end
def logger
@logger ||= Gitlab::Import::Logger.build
end
end
end
end
|