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
|
# frozen_string_literal: true
module Mutations
module Issues
class BulkUpdate < BaseMutation
graphql_name 'IssuesBulkUpdate'
include Gitlab::Graphql::Authorize::AuthorizeResource
MAX_ISSUES = 100
description 'Allows updating several properties for a set of issues. ' \
'Does nothing if the `bulk_update_issues_mutation` feature flag is disabled.'
argument :parent_id, ::Types::GlobalIDType[::IssueParent],
required: true,
description: 'Global ID of the parent that the bulk update will be scoped to . ' \
'Example `IssueParentID` are `"gid://gitlab/Project/1"` and `"gid://gitlab/Group/1"`.'
argument :ids, [::Types::GlobalIDType[::Issue]],
required: true,
description: 'Global ID array of the issues that will be updated. ' \
"IDs that the user can\'t update will be ignored. A max of #{MAX_ISSUES} can be provided."
argument :assignee_ids, [::Types::GlobalIDType[::User]],
required: false,
description: 'Global ID array of the users that will be assigned to the given issues. ' \
'Existing assignees will be replaced with the ones on this list.'
argument :milestone_id, ::Types::GlobalIDType[::Milestone],
required: false,
description: 'Global ID of the milestone that will be assigned to the issues.'
field :updated_issue_count, GraphQL::Types::Int,
null: true,
description: 'Number of issues that were successfully updated.'
def ready?(**args)
if Feature.disabled?(:bulk_update_issues_mutation)
raise Gitlab::Graphql::Errors::ResourceNotAvailable, '`bulk_update_issues_mutation` feature flag is disabled.'
end
if args[:ids].size > MAX_ISSUES
raise Gitlab::Graphql::Errors::ArgumentError,
format(_('No more than %{max_issues} issues can be updated at the same time'), max_issues: MAX_ISSUES)
end
super
end
def resolve(ids:, parent_id:, **attributes)
parent = find_parent!(parent_id)
result = Issuable::BulkUpdateService.new(
parent,
current_user,
prepared_params(attributes, ids)
).execute('issue')
if result.success?
{ updated_issue_count: result.payload[:count], errors: [] }
else
{ errors: result.errors }
end
end
private
def find_parent!(parent_id)
parent = GitlabSchema.find_by_gid(parent_id).sync
raise_resource_not_available_error! unless current_user.can?("read_#{parent.to_ability_name}", parent)
parent
end
def prepared_params(attributes, ids)
prepared = { issuable_ids: model_ids_from(ids).uniq }
global_id_arguments.each do |argument|
next unless attributes.key?(argument)
prepared[argument] = model_ids_from(attributes[argument])
end
# Ruby 3+: This can be simplified to:
# prepared.transform_keys(param_mappings)
prepared.transform_keys { |key| param_mappings[key] || key }
end
def param_mappings
{}
end
def global_id_arguments
%i[assignee_ids milestone_id]
end
def model_ids_from(attributes)
return if attributes.nil?
return attributes.map(&:model_id) if attributes.is_a?(Array)
attributes.model_id
end
end
end
end
Mutations::Issues::BulkUpdate.prepend_mod
|