summaryrefslogtreecommitdiff
path: root/lib/gitlab/import_export/group/legacy_tree_restorer.rb
blob: fa9e765b33a24c2171df4076a198f06043d3708e (plain)
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
# frozen_string_literal: true

module Gitlab
  module ImportExport
    module Group
      class LegacyTreeRestorer
        include Gitlab::Utils::StrongMemoize

        attr_reader :user
        attr_reader :shared
        attr_reader :group

        def initialize(user:, shared:, group:, group_hash:)
          @user = user
          @shared = shared
          @group = group
          @group_hash = group_hash
        end

        def restore
          @group_attributes = relation_reader.consume_attributes(nil)
          @group_members = relation_reader.consume_relation(nil, 'members')
            .map(&:first)

          # We need to remove `name` and `path` as we did consume it in previous pass
          @group_attributes.delete('name')
          @group_attributes.delete('path')

          @children = @group_attributes.delete('children')

          if members_mapper.map && restorer.restore
            @children&.each do |group_hash|
              group = create_group(group_hash: group_hash, parent_group: @group)
              shared = Gitlab::ImportExport::Shared.new(group)

              self.class.new(
                user: @user,
                shared: shared,
                group: group,
                group_hash: group_hash
              ).restore
            end
          end

          return false if @shared.errors.any?

          true
        rescue StandardError => e
          @shared.error(e)
          false
        end

        private

        def relation_reader
          strong_memoize(:relation_reader) do
            if @group_hash.present?
              ImportExport::Json::LegacyReader::Hash.new(
                @group_hash,
                relation_names: reader.group_relation_names)
            else
              ImportExport::Json::LegacyReader::File.new(
                File.join(shared.export_path, 'group.json'),
                relation_names: reader.group_relation_names)
            end
          end
        end

        def restorer
          @relation_tree_restorer ||= RelationTreeRestorer.new(
            user: @user,
            shared: @shared,
            relation_reader: relation_reader,
            members_mapper: members_mapper,
            object_builder: object_builder,
            relation_factory: relation_factory,
            reader: reader,
            importable: @group,
            importable_attributes: @group_attributes,
            importable_path: nil
          )
        end

        def create_group(group_hash:, parent_group:)
          group_params = {
            name: group_hash['name'],
            path: group_hash['path'],
            parent_id: parent_group&.id,
            visibility_level: sub_group_visibility_level(group_hash, parent_group)
          }

          ::Groups::CreateService.new(@user, group_params).execute
        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 members_mapper
          @members_mapper ||= Gitlab::ImportExport::MembersMapper.new(
            exported_members: @group_members,
            user: @user,
            importable: @group
          )
        end

        def relation_factory
          Gitlab::ImportExport::Group::RelationFactory
        end

        def object_builder
          Gitlab::ImportExport::Group::ObjectBuilder
        end

        def reader
          @reader ||= Gitlab::ImportExport::Reader.new(
            shared: @shared,
            config: Gitlab::ImportExport::Config.new(
              config: Gitlab::ImportExport.legacy_group_config_file
            ).to_h
          )
        end
      end
    end
  end
end