File: clone_service.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (93 lines) | stat: -rw-r--r-- 3,544 bytes parent folder | download
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
# frozen_string_literal: true

module WorkItems
  module DataSync
    class CloneService < ::WorkItems::DataSync::BaseService
      private

      def verify_work_item_action_permission
        verify_can_clone_work_item(work_item, target_namespace)
      end

      def data_sync_action
        service_response = clone_work_item
        new_work_item = service_response[:work_item]

        # this may need to be moved inside `BaseCopyDataService` so that this would be the first system note after
        # clone action started, followed by some other system notes related to data that was not copied over for
        # various reasons, e.g. labels or milestone not being copied/set due to not being found in the target namespace
        clone_system_notes(new_work_item) if service_response.success? && new_work_item.present?

        service_response
      end

      def verify_can_clone_work_item(work_item, target_namespace)
        unless work_item.namespace.instance_of?(target_namespace.class)
          error_message = s_('CloneWorkItem|Cannot clone work item between Projects and Groups.')

          return error(error_message, :unprocessable_entity)
        end

        unless work_item.supports_move_and_clone?
          error_message = format(s_('CloneWorkItem|Cannot clone work items of \'%{work_item_type}\' type.'),
            { work_item_type: work_item.work_item_type.name })

          return error(error_message, :unprocessable_entity)
        end

        unless work_item.can_clone?(current_user, target_namespace)
          error_message = s_('CloneWorkItem|Cannot clone work item due to insufficient permissions!')

          return error(error_message, :unprocessable_entity)
        end

        if target_namespace.pending_delete? # rubocop:disable Style/GuardClause -- does not read right with other checks above
          error_message = s_('CloneWorkItem|Cannot clone work item to target namespace as it is pending deletion.')

          return error(error_message, :unprocessable_entity)
        end

        success({})
      end

      def clone_work_item
        # Each widget is responsible for handling the copying of data during clone. Some widgets data is copied some
        # is not.
        # todo: add a user facing documentation which data is copied during clone.
        WorkItems::DataSync::Handlers::CopyDataHandler.new(
          work_item: work_item,
          target_namespace: target_namespace,
          current_user: current_user,
          target_work_item_type: work_item.work_item_type,
          params: params.merge(operation: :clone),
          overwritten_params: {
            author: current_user, created_at: nil, updated_by: current_user, updated_at: nil,
            last_edited_at: nil, last_edited_by: nil, closed_at: nil, closed_by: nil,
            duplicated_to_id: nil, moved_to_id: nil, promoted_to_epic_id: nil, external_key: nil,
            upvotes_count: 0, blocking_issues_count: 0,
            state_id: WorkItem.available_states[:opened]
          }
        ).execute
      end

      def clone_system_notes(new_work_item)
        SystemNoteService.noteable_cloned(
          new_work_item,
          new_work_item.project,
          work_item,
          current_user,
          direction: :from,
          created_at: new_work_item.created_at
        )

        SystemNoteService.noteable_cloned(
          work_item,
          work_item.project,
          new_work_item,
          current_user,
          direction: :to
        )
      end
    end
  end
end