diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-20 13:49:51 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-20 13:49:51 +0000 |
commit | 71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e (patch) | |
tree | 6a2d93ef3fb2d353bb7739e4b57e6541f51cdd71 /app/graphql/mutations/issues | |
parent | a7253423e3403b8c08f8a161e5937e1488f5f407 (diff) | |
download | gitlab-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.rb | 106 | ||||
-rw-r--r-- | app/graphql/mutations/issues/create.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/issues/move.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/issues/set_confidential.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/issues/set_due_date.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/issues/set_escalation_status.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/issues/set_locked.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/issues/set_severity.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/issues/update.rb | 16 |
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 |