diff options
Diffstat (limited to 'app/graphql/mutations/issues/create.rb')
-rw-r--r-- | app/graphql/mutations/issues/create.rb | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb new file mode 100644 index 00000000000..1454916bc77 --- /dev/null +++ b/app/graphql/mutations/issues/create.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +module Mutations + module Issues + class Create < BaseMutation + include ResolvesProject + graphql_name 'CreateIssue' + + authorize :create_issue + + include CommonMutationArguments + + argument :project_path, GraphQL::ID_TYPE, + required: true, + description: 'Project full path the issue is associated with' + + argument :iid, GraphQL::INT_TYPE, + required: false, + description: 'The IID (internal ID) of a project issue. Only admins and project owners can modify' + + argument :title, GraphQL::STRING_TYPE, + required: true, + description: copy_field_description(Types::IssueType, :title) + + argument :milestone_id, ::Types::GlobalIDType[::Milestone], + required: false, + description: 'The ID of the milestone to assign to the issue. On update milestone will be removed if set to null' + + argument :labels, [GraphQL::STRING_TYPE], + required: false, + description: copy_field_description(Types::IssueType, :labels) + + argument :label_ids, [::Types::GlobalIDType[::Label]], + required: false, + description: 'The IDs of labels to be added to the issue' + + argument :created_at, Types::TimeType, + required: false, + description: 'Timestamp when the issue was created. Available only for admins and project owners' + + argument :merge_request_to_resolve_discussions_of, ::Types::GlobalIDType[::MergeRequest], + required: false, + description: 'The IID of a merge request for which to resolve discussions' + + argument :discussion_to_resolve, GraphQL::STRING_TYPE, + required: false, + description: 'The ID of a discussion to resolve. Also pass `merge_request_to_resolve_discussions_of`' + + argument :assignee_ids, [::Types::GlobalIDType[::User]], + required: false, + description: 'The array of user IDs to assign to the issue' + + field :issue, + Types::IssueType, + null: true, + description: 'The issue after mutation' + + def ready?(**args) + if args.slice(*mutually_exclusive_label_args).size > 1 + arg_str = mutually_exclusive_label_args.map { |x| x.to_s.camelize(:lower) }.join(' or ') + raise Gitlab::Graphql::Errors::ArgumentError, "one and only one of #{arg_str} is required." + end + + if args[:discussion_to_resolve].present? && args[:merge_request_to_resolve_discussions_of].blank? + raise Gitlab::Graphql::Errors::ArgumentError, + 'to resolve a discussion please also provide `merge_request_to_resolve_discussions_of` parameter' + end + + super + end + + def resolve(project_path:, **attributes) + project = authorized_find!(full_path: project_path) + params = build_create_issue_params(attributes.merge(author_id: current_user.id)) + + issue = ::Issues::CreateService.new(project, current_user, params).execute + + if issue.spam? + issue.errors.add(:base, 'Spam detected.') + end + + { + issue: issue.valid? ? issue : nil, + errors: errors_on_object(issue) + } + end + + private + + def build_create_issue_params(params) + params[:milestone_id] &&= params[:milestone_id]&.model_id + params[:assignee_ids] &&= params[:assignee_ids].map { |assignee_id| assignee_id&.model_id } + params[:label_ids] &&= params[:label_ids].map { |label_id| label_id&.model_id } + + params + end + + def mutually_exclusive_label_args + [:labels, :label_ids] + end + + def find_object(full_path:) + resolve_project(full_path: full_path) + end + end + end +end + +Mutations::Issues::Create.prepend_if_ee('::EE::Mutations::Issues::Create') |