Commit ff0b736a authored by Dylan Griffith's avatar Dylan Griffith

Merge branch '214583-change-mutation-to-add-projects-to-security-dashboard' into 'master'

Modify mutation to add Project to Instance Security Dashboard

See merge request gitlab-org/gitlab!30865
parents 4c9f3782 460d7af3
......@@ -39,48 +39,38 @@ type AddAwardEmojiPayload {
}
"""
Autogenerated input type of AddProjectsToSecurityDashboard
Autogenerated input type of AddProjectToSecurityDashboard
"""
input AddProjectsToSecurityDashboardInput {
input AddProjectToSecurityDashboardInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
IDs of projects to be added to Instance Security Dashboard
ID of the project to be added to Instance Security Dashboard
"""
projectIds: [ID!]!
id: ID!
}
"""
Autogenerated return type of AddProjectsToSecurityDashboard
Autogenerated return type of AddProjectToSecurityDashboard
"""
type AddProjectsToSecurityDashboardPayload {
"""
IDs of projects that were added to the Instance Security Dashboard
"""
addedProjectIds: [ID!]
type AddProjectToSecurityDashboardPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
IDs of projects that are already added to the Instance Security Dashboard
"""
duplicatedProjectIds: [ID!]
"""
Reasons why the mutation failed.
"""
errors: [String!]!
"""
IDs of projects that were not added to the Instance Security Dashboard
Project that was added to the Instance Security Dashboard
"""
invalidProjectIds: [ID!]
project: Project
}
"""
......@@ -6049,7 +6039,7 @@ enum MoveType {
type Mutation {
addAwardEmoji(input: AddAwardEmojiInput!): AddAwardEmojiPayload
addProjectsToSecurityDashboard(input: AddProjectsToSecurityDashboardInput!): AddProjectsToSecurityDashboardPayload
addProjectToSecurityDashboard(input: AddProjectToSecurityDashboardInput!): AddProjectToSecurityDashboardPayload
adminSidekiqQueuesDeleteJobs(input: AdminSidekiqQueuesDeleteJobsInput!): AdminSidekiqQueuesDeleteJobsPayload
boardListUpdateLimitMetrics(input: BoardListUpdateLimitMetricsInput!): BoardListUpdateLimitMetricsPayload
createBranch(input: CreateBranchInput!): CreateBranchPayload
......
......@@ -127,28 +127,20 @@
},
{
"kind": "INPUT_OBJECT",
"name": "AddProjectsToSecurityDashboardInput",
"description": "Autogenerated input type of AddProjectsToSecurityDashboard",
"name": "AddProjectToSecurityDashboardInput",
"description": "Autogenerated input type of AddProjectToSecurityDashboard",
"fields": null,
"inputFields": [
{
"name": "projectIds",
"description": "IDs of projects to be added to Instance Security Dashboard",
"name": "id",
"description": "ID of the project to be added to Instance Security Dashboard",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
......@@ -170,31 +162,9 @@
},
{
"kind": "OBJECT",
"name": "AddProjectsToSecurityDashboardPayload",
"description": "Autogenerated return type of AddProjectsToSecurityDashboard",
"name": "AddProjectToSecurityDashboardPayload",
"description": "Autogenerated return type of AddProjectToSecurityDashboard",
"fields": [
{
"name": "addedProjectIds",
"description": "IDs of projects that were added to the Instance Security Dashboard",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
......@@ -209,28 +179,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "duplicatedProjectIds",
"description": "IDs of projects that are already added to the Instance Security Dashboard",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "errors",
"description": "Reasons why the mutation failed.",
......@@ -258,23 +206,15 @@
"deprecationReason": null
},
{
"name": "invalidProjectIds",
"description": "IDs of projects that were not added to the Instance Security Dashboard",
"name": "project",
"description": "Project that was added to the Instance Security Dashboard",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
"kind": "OBJECT",
"name": "Project",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
......@@ -17245,7 +17185,7 @@
"deprecationReason": null
},
{
"name": "addProjectsToSecurityDashboard",
"name": "addProjectToSecurityDashboard",
"description": null,
"args": [
{
......@@ -17256,7 +17196,7 @@
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "AddProjectsToSecurityDashboardInput",
"name": "AddProjectToSecurityDashboardInput",
"ofType": null
}
},
......@@ -17265,7 +17205,7 @@
],
"type": {
"kind": "OBJECT",
"name": "AddProjectsToSecurityDashboardPayload",
"name": "AddProjectToSecurityDashboardPayload",
"ofType": null
},
"isDeprecated": false,
......
......@@ -26,17 +26,15 @@ Autogenerated return type of AddAwardEmoji
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
## AddProjectsToSecurityDashboardPayload
## AddProjectToSecurityDashboardPayload
Autogenerated return type of AddProjectsToSecurityDashboard
Autogenerated return type of AddProjectToSecurityDashboard
| Name | Type | Description |
| --- | ---- | ---------- |
| `addedProjectIds` | ID! => Array | IDs of projects that were added to the Instance Security Dashboard |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `duplicatedProjectIds` | ID! => Array | IDs of projects that are already added to the Instance Security Dashboard |
| `errors` | String! => Array | Reasons why the mutation failed. |
| `invalidProjectIds` | ID! => Array | IDs of projects that were not added to the Instance Security Dashboard |
| `project` | Project | Project that was added to the Instance Security Dashboard |
## AdminSidekiqQueuesDeleteJobsPayload
......
......@@ -18,7 +18,7 @@ module EE
mount_mutation ::Mutations::Requirements::Update
mount_mutation ::Mutations::Vulnerabilities::Dismiss
mount_mutation ::Mutations::Boards::Lists::UpdateLimitMetrics
mount_mutation ::Mutations::SecurityDashboard::AddProjects
mount_mutation ::Mutations::SecurityDashboard::AddProject
end
end
end
......
# frozen_string_literal: true
module Mutations
module SecurityDashboard
class AddProject < BaseMutation
graphql_name 'AddProjectToSecurityDashboard'
authorize :read_vulnerability
field :project, Types::ProjectType,
null: true,
description: 'Project that was added to the Instance Security Dashboard'
argument :id, GraphQL::ID_TYPE,
required: true,
description: 'ID of the project to be added to Instance Security Dashboard'
def resolve(id:)
project = authorized_find!(id: id)
result = add_project(project)
{
project: result ? project : nil,
errors: result ? [] : ['The project already belongs to your dashboard or you don\'t have permission to perform this action']
}
end
private
def find_object(id:)
GitlabSchema.object_from_id(id)
end
def add_project(project)
Dashboard::Projects::CreateService
.new(current_user, current_user.security_dashboard_projects, feature: :security_dashboard)
.execute([project.id])
.then { |result| result.added_project_ids.include?(project.id) }
end
end
end
end
# frozen_string_literal: true
module Mutations
module SecurityDashboard
class AddProjects < BaseMutation
graphql_name 'AddProjectsToSecurityDashboard'
authorize :read_instance_security_dashboard
field :invalid_project_ids, [GraphQL::ID_TYPE],
null: true,
description: 'IDs of projects that were not added to the Instance Security Dashboard'
field :added_project_ids, [GraphQL::ID_TYPE],
null: true,
description: 'IDs of projects that were added to the Instance Security Dashboard'
field :duplicated_project_ids, [GraphQL::ID_TYPE],
null: true,
description: 'IDs of projects that are already added to the Instance Security Dashboard'
argument :project_ids, [GraphQL::ID_TYPE],
required: true,
description: 'IDs of projects to be added to Instance Security Dashboard'
def resolve(project_ids:)
dashboard = authorized_find!
raise_resource_not_available_error! unless dashboard.feature_available?(:security_dashboard)
result = add_projects(project_ids.map(&method(:extract_project_id)))
{
invalid_project_ids: result.invalid_project_ids.map(&method(:to_global_id)),
added_project_ids: result.added_project_ids.map(&method(:to_global_id)),
duplicated_project_ids: result.duplicate_project_ids.map(&method(:to_global_id)),
errors: []
}
end
private
def find_object(*args)
InstanceSecurityDashboard.new(current_user)
end
def extract_project_id(global_id)
return unless global_id.present?
GitlabSchema.parse_gid(global_id, expected_type: ::Project).model_id
end
def add_projects(project_ids)
Dashboard::Projects::CreateService.new(
current_user,
current_user.security_dashboard_projects,
feature: :security_dashboard
).execute(project_ids.compact)
end
def to_global_id(project_id)
GitlabSchema.id_from_object(Project.new(id: project_id))
end
end
end
end
---
title: Modify GraphQL mutation for adding projects to Instance Security Dashboard
to support only single project id
merge_request: 30865
author:
type: changed
# frozen_string_literal: true
require 'spec_helper'
describe Mutations::SecurityDashboard::AddProjects do
describe Mutations::SecurityDashboard::AddProject do
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
describe '#resolve' do
......@@ -11,14 +11,14 @@ describe Mutations::SecurityDashboard::AddProjects do
let_it_be(:user) { create(:user, security_dashboard_projects: [already_added_project]) }
let(:project_ids) { [project, my_project, already_added_project].map(&GitlabSchema.method(:id_from_object)).map(&:to_s) }
let(:selected_project) { project }
before do
my_project.add_developer(user)
already_added_project.add_developer(user)
end
subject { mutation.resolve(project_ids: project_ids) }
subject { mutation.resolve(id: GitlabSchema.id_from_object(selected_project)) }
context 'when user is not logged_in' do
let(:current_user) { nil }
......@@ -42,25 +42,31 @@ describe Mutations::SecurityDashboard::AddProjects do
stub_licensed_features(security_dashboard: true)
end
context 'when project_ids is empty' do
let(:project_ids) { [] }
context 'when project is available to the user and can be added to the security dashboard' do
let(:selected_project) { my_project }
it { is_expected.to eq(added_project_ids: [], duplicated_project_ids: [], invalid_project_ids: [], errors: []) }
end
context 'when project_ids contains ids' do
it 'adds project that is available to the user to the security dashboard', :aggregate_failures do
expect(subject[:added_project_ids]).to eq([GitlabSchema.id_from_object(my_project)])
it 'adds project to the security dashboard', :aggregate_failures do
expect(subject[:project]).to eq(my_project)
expect(subject[:errors]).to be_empty
expect(user.security_dashboard_projects).to include(my_project)
end
end
it 'does not add project that already exist in the security dashboard', :aggregate_failures do
expect(subject[:duplicated_project_ids]).to eq([GitlabSchema.id_from_object(already_added_project)])
expect(user.security_dashboard_projects).to include(already_added_project)
context 'when project is not available to the user' do
let(:selected_project) { project }
it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
it 'does not add project that is not available for the user' do
expect(subject[:invalid_project_ids]).to eq([GitlabSchema.id_from_object(project)])
context 'when project is already added to the security dashboard' do
let(:selected_project) { already_added_project }
it 'does not add project to the security dashboard', :aggregate_failures do
expect(subject[:project]).to be_nil
expect(subject[:errors]).to eq(['The project already belongs to your dashboard or you don\'t have permission to perform this action'])
expect(user.security_dashboard_projects).to include(already_added_project)
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment