Commit 23fad217 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch '214583-add-mutation-to-remove-project-from-security-dashboard' into 'master'

Add mutation to remove project from Instance Security Dashboard

See merge request gitlab-org/gitlab!30100
parents e8ee5559 25ab0245
......@@ -6221,6 +6221,7 @@ type Mutation {
mergeRequestSetSubscription(input: MergeRequestSetSubscriptionInput!): MergeRequestSetSubscriptionPayload
mergeRequestSetWip(input: MergeRequestSetWipInput!): MergeRequestSetWipPayload
removeAwardEmoji(input: RemoveAwardEmojiInput!): RemoveAwardEmojiPayload
removeProjectFromSecurityDashboard(input: RemoveProjectFromSecurityDashboardInput!): RemoveProjectFromSecurityDashboardPayload
todoMarkDone(input: TodoMarkDoneInput!): TodoMarkDonePayload
todoRestore(input: TodoRestoreInput!): TodoRestorePayload
todoRestoreMany(input: TodoRestoreManyInput!): TodoRestoreManyPayload
......@@ -8401,6 +8402,36 @@ type RemoveAwardEmojiPayload {
errors: [String!]!
}
"""
Autogenerated input type of RemoveProjectFromSecurityDashboard
"""
input RemoveProjectFromSecurityDashboardInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
ID of the project to remove from the Instance Security Dashboard
"""
projectId: ID!
}
"""
Autogenerated return type of RemoveProjectFromSecurityDashboard
"""
type RemoveProjectFromSecurityDashboardPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Reasons why the mutation failed.
"""
errors: [String!]!
}
type Repository {
"""
Indicates repository has no visible content
......
......@@ -18271,6 +18271,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "removeProjectFromSecurityDashboard",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "RemoveProjectFromSecurityDashboardInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "RemoveProjectFromSecurityDashboardPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "todoMarkDone",
"description": null,
......@@ -24687,6 +24714,94 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "RemoveProjectFromSecurityDashboardInput",
"description": "Autogenerated input type of RemoveProjectFromSecurityDashboard",
"fields": null,
"inputFields": [
{
"name": "projectId",
"description": "ID of the project to remove from the Instance Security Dashboard",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "RemoveProjectFromSecurityDashboardPayload",
"description": "Autogenerated return type of RemoveProjectFromSecurityDashboard",
"fields": [
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "errors",
"description": "Reasons why the mutation failed.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "Repository",
......
......@@ -1180,6 +1180,15 @@ Autogenerated return type of RemoveAwardEmoji
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
## RemoveProjectFromSecurityDashboardPayload
Autogenerated return type of RemoveProjectFromSecurityDashboard
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
## Repository
| Name | Type | Description |
......
......@@ -19,6 +19,7 @@ module EE
mount_mutation ::Mutations::Vulnerabilities::Dismiss
mount_mutation ::Mutations::Boards::Lists::UpdateLimitMetrics
mount_mutation ::Mutations::InstanceSecurityDashboard::AddProject
mount_mutation ::Mutations::InstanceSecurityDashboard::RemoveProject
end
end
end
......
# frozen_string_literal: true
module Mutations
module InstanceSecurityDashboard
class RemoveProject < BaseMutation
graphql_name 'RemoveProjectFromSecurityDashboard'
authorize :read_instance_security_dashboard
argument :project_id, GraphQL::ID_TYPE,
required: true,
description: 'ID of the project to remove from the Instance Security Dashboard'
def resolve(project_id:)
dashboard = authorized_find!
raise_resource_not_available_error! unless dashboard.feature_available?(:security_dashboard)
result = remove_project(extract_project_id(project_id))
{
errors: result.zero? ? ['The project does not belong to your dashboard or you don\'t have permission to perform this action'] : []
}
end
private
def find_object(*args)
::InstanceSecurityDashboard.new(current_user)
end
def extract_project_id(gid)
return unless gid.present?
GitlabSchema.parse_gid(gid, expected_type: ::Project).model_id
end
def remove_project(project_id)
current_user
.users_security_dashboard_projects
.delete_by_project_id(project_id)
end
end
end
end
---
title: Add GraphQL mutation for removing projects from Instance Security Dashboard
merge_request: 30100
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
describe Mutations::InstanceSecurityDashboard::RemoveProject do
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
describe '#resolve' do
let_it_be(:project) { create(:project) }
let_it_be(:already_added_project) { create(:project) }
let_it_be(:user) { create(:user, security_dashboard_projects: [already_added_project]) }
let(:project_id) { GitlabSchema.id_from_object(project) }
before_all do
already_added_project.add_developer(user)
end
subject { mutation.resolve(project_id: project_id) }
context 'when user is not logged_in' do
let(:current_user) { nil }
it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when user is logged_in' do
let(:current_user) { user }
context 'when security_dashboard is not enabled' do
it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when security_dashboard is enabled' do
before do
stub_licensed_features(security_dashboard: true)
end
context 'when project is not configured in security dashboard' do
it { is_expected.to eq(errors: ['The project does not belong to your dashboard or you don\'t have permission to perform this action']) }
end
context 'when project is configured in security dashboard' do
let(:project_id) { GitlabSchema.id_from_object(already_added_project) }
it { is_expected.to eq(errors: []) }
end
end
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