summaryrefslogtreecommitdiff
path: root/app/graphql/mutations/issues
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-20 13:49:51 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-20 13:49:51 +0000
commit71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e (patch)
tree6a2d93ef3fb2d353bb7739e4b57e6541f51cdd71 /app/graphql/mutations/issues
parenta7253423e3403b8c08f8a161e5937e1488f5f407 (diff)
downloadgitlab-ce-71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e.tar.gz
Add latest changes from gitlab-org/gitlab@15-9-stable-eev15.9.0-rc42
Diffstat (limited to 'app/graphql/mutations/issues')
-rw-r--r--app/graphql/mutations/issues/bulk_update.rb106
-rw-r--r--app/graphql/mutations/issues/create.rb2
-rw-r--r--app/graphql/mutations/issues/move.rb2
-rw-r--r--app/graphql/mutations/issues/set_confidential.rb2
-rw-r--r--app/graphql/mutations/issues/set_due_date.rb2
-rw-r--r--app/graphql/mutations/issues/set_escalation_status.rb2
-rw-r--r--app/graphql/mutations/issues/set_locked.rb2
-rw-r--r--app/graphql/mutations/issues/set_severity.rb2
-rw-r--r--app/graphql/mutations/issues/update.rb16
9 files changed, 127 insertions, 9 deletions
diff --git a/app/graphql/mutations/issues/bulk_update.rb b/app/graphql/mutations/issues/bulk_update.rb
new file mode 100644
index 00000000000..7f3d5f6ffb2
--- /dev/null
+++ b/app/graphql/mutations/issues/bulk_update.rb
@@ -0,0 +1,106 @@
+# 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
+
+ prepared.transform_keys(param_mappings)
+ 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
diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb
index 0389a482822..0c1acdf316e 100644
--- a/app/graphql/mutations/issues/create.rb
+++ b/app/graphql/mutations/issues/create.rb
@@ -83,7 +83,7 @@ module Mutations
params = build_create_issue_params(attributes.merge(author_id: current_user.id), project)
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
- result = ::Issues::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute
+ result = ::Issues::CreateService.new(container: project, current_user: current_user, params: params, spam_params: spam_params).execute
check_spam_action_response!(result[:issue]) if result[:issue]
diff --git a/app/graphql/mutations/issues/move.rb b/app/graphql/mutations/issues/move.rb
index 63bc9dabbf9..ef3f70c78b9 100644
--- a/app/graphql/mutations/issues/move.rb
+++ b/app/graphql/mutations/issues/move.rb
@@ -18,7 +18,7 @@ module Mutations
target_project = resolve_project(full_path: target_project_path).sync
begin
- moved_issue = ::Issues::MoveService.new(project: source_project, current_user: current_user).execute(issue, target_project)
+ moved_issue = ::Issues::MoveService.new(container: source_project, current_user: current_user).execute(issue, target_project)
rescue ::Issues::MoveService::MoveError => e
errors = e.message
end
diff --git a/app/graphql/mutations/issues/set_confidential.rb b/app/graphql/mutations/issues/set_confidential.rb
index b795d66c16f..08578881a13 100644
--- a/app/graphql/mutations/issues/set_confidential.rb
+++ b/app/graphql/mutations/issues/set_confidential.rb
@@ -19,7 +19,7 @@ module Mutations
# spam_params so a check can be performed.
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: { confidential: confidential }, spam_params: spam_params)
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: { confidential: confidential }, spam_params: spam_params)
.execute(issue)
check_spam_action_response!(issue)
diff --git a/app/graphql/mutations/issues/set_due_date.rb b/app/graphql/mutations/issues/set_due_date.rb
index 70b76da4fcb..e361d241083 100644
--- a/app/graphql/mutations/issues/set_due_date.rb
+++ b/app/graphql/mutations/issues/set_due_date.rb
@@ -14,7 +14,7 @@ module Mutations
issue = authorized_find!(project_path: project_path, iid: iid)
project = issue.project
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: { due_date: due_date })
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: { due_date: due_date })
.execute(issue)
{
diff --git a/app/graphql/mutations/issues/set_escalation_status.rb b/app/graphql/mutations/issues/set_escalation_status.rb
index 4f3fcb4886d..13286034ada 100644
--- a/app/graphql/mutations/issues/set_escalation_status.rb
+++ b/app/graphql/mutations/issues/set_escalation_status.rb
@@ -17,7 +17,7 @@ module Mutations
check_feature_availability!(issue)
::Issues::UpdateService.new(
- project: project,
+ container: project,
current_user: current_user,
params: { escalation_status: { status: status } }
).execute(issue)
diff --git a/app/graphql/mutations/issues/set_locked.rb b/app/graphql/mutations/issues/set_locked.rb
index 93b31350bbf..86ad129f4cb 100644
--- a/app/graphql/mutations/issues/set_locked.rb
+++ b/app/graphql/mutations/issues/set_locked.rb
@@ -13,7 +13,7 @@ module Mutations
def resolve(project_path:, iid:, locked:)
issue = authorized_find!(project_path: project_path, iid: iid)
- ::Issues::UpdateService.new(project: issue.project, current_user: current_user, params: { discussion_locked: locked })
+ ::Issues::UpdateService.new(container: issue.project, current_user: current_user, params: { discussion_locked: locked })
.execute(issue)
{
diff --git a/app/graphql/mutations/issues/set_severity.rb b/app/graphql/mutations/issues/set_severity.rb
index 4a24bfd18ef..68d7fb7d0c0 100644
--- a/app/graphql/mutations/issues/set_severity.rb
+++ b/app/graphql/mutations/issues/set_severity.rb
@@ -15,7 +15,7 @@ module Mutations
issue = authorized_find!(project_path: project_path, iid: iid)
project = issue.project
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: { severity: severity })
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: { severity: severity })
.execute(issue)
{
diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb
index 6cab1214d24..b5af048dc07 100644
--- a/app/graphql/mutations/issues/update.rb
+++ b/app/graphql/mutations/issues/update.rb
@@ -31,6 +31,10 @@ module Mutations
description: 'Close or reopen an issue.',
required: false
+ argument :time_estimate, GraphQL::Types::String,
+ required: false,
+ description: 'Estimated time to complete the issue, or `0` to remove the current estimate.'
+
def resolve(project_path:, iid:, **args)
issue = authorized_find!(project_path: project_path, iid: iid)
project = issue.project
@@ -38,7 +42,7 @@ module Mutations
args = parse_arguments(args)
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: args, spam_params: spam_params).execute(issue)
+ ::Issues::UpdateService.new(container: project, current_user: current_user, params: args, spam_params: spam_params).execute(issue)
{
issue: issue,
@@ -46,11 +50,15 @@ module Mutations
}
end
- def ready?(label_ids: [], add_label_ids: [], remove_label_ids: [], **args)
+ def ready?(label_ids: [], add_label_ids: [], remove_label_ids: [], time_estimate: nil, **args)
if label_ids.any? && (add_label_ids.any? || remove_label_ids.any?)
raise Gitlab::Graphql::Errors::ArgumentError, 'labelIds is mutually exclusive with any of addLabelIds or removeLabelIds'
end
+ if !time_estimate.nil? && Gitlab::TimeTrackingFormatter.parse(time_estimate, keep_zero: true).nil?
+ raise Gitlab::Graphql::Errors::ArgumentError, 'timeEstimate must be formatted correctly, for example `1h 30m`'
+ end
+
super
end
@@ -61,6 +69,10 @@ module Mutations
args[:remove_label_ids] = parse_label_ids(args[:remove_label_ids])
args[:label_ids] = parse_label_ids(args[:label_ids])
+ unless args[:time_estimate].nil?
+ args[:time_estimate] = Gitlab::TimeTrackingFormatter.parse(args[:time_estimate], keep_zero: true)
+ end
+
args
end