File: bulk_update_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 (62 lines) | stat: -rw-r--r-- 1,953 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
# frozen_string_literal: true

module WorkItems
  class BulkUpdateService
    def initialize(parent:, current_user:, work_item_ids:, widget_params: {})
      @parent = parent
      @work_item_ids = work_item_ids
      @current_user = current_user
      @widget_params = widget_params.dup
    end

    def execute
      unless @current_user.can?(:"read_#{@parent.to_ability_name}", @parent)
        return ServiceResponse.error(message: "User can't read parent", reason: :authorization)
      end

      updated_work_items = scoped_work_items.find_each(batch_size: 100) # rubocop:disable CodeReuse/ActiveRecord -- Implementation would be identical in model
                                            .filter_map do |work_item|
        next unless @current_user.can?(:update_work_item, work_item)

        update_result = WorkItems::UpdateService.new(
          container: work_item.resource_parent,
          widget_params: @widget_params,
          current_user: @current_user
        ).execute(work_item)

        work_item if update_result[:status] == :success
      end

      ServiceResponse.success(payload: { updated_work_item_count: updated_work_items.count })
    end

    private

    def scoped_work_items
      ids = WorkItem.id_in(@work_item_ids)
      cte = Gitlab::SQL::CTE.new(:work_item_ids_cte, ids)
      work_item_scope = WorkItem.all
      cte.apply_to(work_item_scope).in_namespaces_with_cte(namespaces)
    end

    def namespaces
      relations = [group_namespaces, project_namespaces].compact

      Namespace.from_union(relations, remove_duplicates: false)
    end

    def group_namespaces
      return unless @parent.is_a?(Group)

      @parent.self_and_descendants.select(:id)
    end

    def project_namespaces
      if @parent.is_a?(Project)
        Project.id_in(@parent)
      else
        Project.in_namespace(@parent.self_and_descendant_ids)
      end.select('projects.project_namespace_id as id')
    end
  end
end