141 lines
4.0 KiB
Ruby
141 lines
4.0 KiB
Ruby
![]() |
# frozen_string_literal: true
|
||
|
|
||
|
module Gitlab
|
||
|
module ImportExport
|
||
|
module Group
|
||
|
class TreeRestorer
|
||
|
include Gitlab::Utils::StrongMemoize
|
||
|
|
||
|
attr_reader :user, :shared
|
||
|
|
||
|
def initialize(user:, shared:, group:)
|
||
|
@user = user
|
||
|
@shared = shared
|
||
|
@top_level_group = group
|
||
|
@groups_mapping = {}
|
||
|
end
|
||
|
|
||
|
def restore
|
||
|
group_ids = relation_reader.consume_relation('groups', '_all').map { |value, _idx| Integer(value) }
|
||
|
root_group_id = group_ids.delete_at(0)
|
||
|
|
||
|
process_root(root_group_id)
|
||
|
|
||
|
group_ids.each do |group_id|
|
||
|
process_child(group_id)
|
||
|
end
|
||
|
|
||
|
true
|
||
|
rescue => e
|
||
|
shared.error(e)
|
||
|
false
|
||
|
end
|
||
|
|
||
|
class GroupAttributes
|
||
|
attr_reader :attributes, :group_id, :id, :path
|
||
|
|
||
|
def initialize(group_id, relation_reader)
|
||
|
@group_id = group_id
|
||
|
|
||
|
@path = "groups/#{group_id}"
|
||
|
@attributes = relation_reader.consume_attributes(@path)
|
||
|
@id = @attributes.delete('id')
|
||
|
|
||
|
unless @id == @group_id
|
||
|
raise ArgumentError, "Invalid group_id for #{group_id}"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def delete_attribute(name)
|
||
|
attributes.delete(name)
|
||
|
end
|
||
|
|
||
|
def delete_attributes(*names)
|
||
|
names.map(&method(:delete_attribute))
|
||
|
end
|
||
|
end
|
||
|
private_constant :GroupAttributes
|
||
|
|
||
|
private
|
||
|
|
||
|
def process_root(group_id)
|
||
|
group_attributes = GroupAttributes.new(group_id, relation_reader)
|
||
|
|
||
|
# name and path are not imported on the root group to avoid conflict
|
||
|
# with existing groups name and/or path.
|
||
|
group_attributes.delete_attributes('name', 'path')
|
||
|
|
||
|
restore_group(@top_level_group, group_attributes)
|
||
|
end
|
||
|
|
||
|
def process_child(group_id)
|
||
|
group_attributes = GroupAttributes.new(group_id, relation_reader)
|
||
|
|
||
|
group = create_group(group_attributes)
|
||
|
|
||
|
restore_group(group, group_attributes)
|
||
|
end
|
||
|
|
||
|
def create_group(group_attributes)
|
||
|
parent_id = group_attributes.delete_attribute('parent_id')
|
||
|
name = group_attributes.delete_attribute('name')
|
||
|
path = group_attributes.delete_attribute('path')
|
||
|
|
||
|
parent_group = @groups_mapping.fetch(parent_id) { raise(ArgumentError, 'Parent group not found') }
|
||
|
|
||
|
::Groups::CreateService.new(
|
||
|
user,
|
||
|
name: name,
|
||
|
path: path,
|
||
|
parent_id: parent_group.id,
|
||
|
visibility_level: sub_group_visibility_level(group_attributes.attributes, parent_group)
|
||
|
).execute
|
||
|
end
|
||
|
|
||
|
def restore_group(group, group_attributes)
|
||
|
@groups_mapping[group_attributes.id] = group
|
||
|
|
||
|
Group::GroupRestorer.new(
|
||
|
user: user,
|
||
|
shared: shared,
|
||
|
group: group,
|
||
|
attributes: group_attributes.attributes,
|
||
|
importable_path: group_attributes.path,
|
||
|
relation_reader: relation_reader,
|
||
|
reader: reader
|
||
|
).restore
|
||
|
end
|
||
|
|
||
|
def relation_reader
|
||
|
strong_memoize(:relation_reader) do
|
||
|
ImportExport::JSON::NdjsonReader.new(
|
||
|
File.join(shared.export_path, 'tree')
|
||
|
)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def sub_group_visibility_level(group_hash, parent_group)
|
||
|
original_visibility_level = group_hash['visibility_level'] || Gitlab::VisibilityLevel::PRIVATE
|
||
|
|
||
|
if parent_group && parent_group.visibility_level < original_visibility_level
|
||
|
Gitlab::VisibilityLevel.closest_allowed_level(parent_group.visibility_level)
|
||
|
else
|
||
|
original_visibility_level
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def reader
|
||
|
strong_memoize(:reader) do
|
||
|
Gitlab::ImportExport::Reader.new(
|
||
|
shared: @shared,
|
||
|
config: Gitlab::ImportExport::Config.new(
|
||
|
config: Gitlab::ImportExport.group_config_file
|
||
|
).to_h
|
||
|
)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|