Commit d879870c authored by Sarah Yasonik's avatar Sarah Yasonik Committed by Vitali Tatarintev

Revert "Do not include deleted integration is response"

This reverts commit 093d299c61ab1b880d63c5d859e3647b6861b4f6.
parent d978f9ab
# frozen_string_literal: true
module Mutations
module AlertManagement
module HttpIntegration
class Destroy < HttpIntegrationBase
graphql_name 'HttpIntegrationDestroy'
argument :id, Types::GlobalIDType[::AlertManagement::HttpIntegration],
required: true,
description: "The id of the integration to remove"
def resolve(id:)
integration = authorized_find!(id: id)
response ::AlertManagement::HttpIntegrations::DestroyService.new(
integration,
current_user
).execute
end
end
end
end
end
......@@ -7,7 +7,7 @@ module Mutations
field :integration,
Types::AlertManagement::HttpIntegrationType,
null: true,
description: "The updated HTTP integration"
description: "The HTTP integration"
authorize :admin_operations
......
......@@ -14,6 +14,7 @@ module Types
mount_mutation Mutations::AlertManagement::HttpIntegration::Create
mount_mutation Mutations::AlertManagement::HttpIntegration::Update
mount_mutation Mutations::AlertManagement::HttpIntegration::ResetToken
mount_mutation Mutations::AlertManagement::HttpIntegration::Destroy
mount_mutation Mutations::AlertManagement::PrometheusIntegration::Create
mount_mutation Mutations::AlertManagement::PrometheusIntegration::Update
mount_mutation Mutations::AlertManagement::PrometheusIntegration::ResetToken
......
# frozen_string_literal: true
module AlertManagement
module HttpIntegrations
class DestroyService
# @param integration [AlertManagement::HttpIntegration]
# @param current_user [User]
def initialize(integration, current_user)
@integration = integration
@current_user = current_user
end
def execute
return error_no_permissions unless allowed?
return error_multiple_integrations unless Feature.enabled?(:multiple_http_integrations, integration.project)
if integration.destroy
success
else
error(integration.errors.full_messages.to_sentence)
end
end
private
attr_reader :integration, :current_user
def allowed?
current_user&.can?(:admin_operations, integration)
end
def error(message)
ServiceResponse.error(message: message)
end
def success
ServiceResponse.success(payload: { integration: integration })
end
def error_no_permissions
error(_('You have insufficient permissions to remove this HTTP integration'))
end
def error_multiple_integrations
error(_('Removing integrations is not supported for this project'))
end
end
end
end
......@@ -9271,7 +9271,42 @@ type HttpIntegrationCreatePayload {
errors: [String!]!
"""
The updated HTTP integration
The HTTP integration
"""
integration: AlertManagementHttpIntegration
}
"""
Autogenerated input type of HttpIntegrationDestroy
"""
input HttpIntegrationDestroyInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
The id of the integration to remove
"""
id: AlertManagementHttpIntegrationID!
}
"""
Autogenerated return type of HttpIntegrationDestroy
"""
type HttpIntegrationDestroyPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Errors encountered during execution of the mutation.
"""
errors: [String!]!
"""
The HTTP integration
"""
integration: AlertManagementHttpIntegration
}
......@@ -9306,7 +9341,7 @@ type HttpIntegrationResetTokenPayload {
errors: [String!]!
"""
The updated HTTP integration
The HTTP integration
"""
integration: AlertManagementHttpIntegration
}
......@@ -9351,7 +9386,7 @@ type HttpIntegrationUpdatePayload {
errors: [String!]!
"""
The updated HTTP integration
The HTTP integration
"""
integration: AlertManagementHttpIntegration
}
......@@ -12950,6 +12985,7 @@ type Mutation {
epicSetSubscription(input: EpicSetSubscriptionInput!): EpicSetSubscriptionPayload
epicTreeReorder(input: EpicTreeReorderInput!): EpicTreeReorderPayload
httpIntegrationCreate(input: HttpIntegrationCreateInput!): HttpIntegrationCreatePayload
httpIntegrationDestroy(input: HttpIntegrationDestroyInput!): HttpIntegrationDestroyPayload
httpIntegrationResetToken(input: HttpIntegrationResetTokenInput!): HttpIntegrationResetTokenPayload
httpIntegrationUpdate(input: HttpIntegrationUpdateInput!): HttpIntegrationUpdatePayload
issueMove(input: IssueMoveInput!): IssueMovePayload
......
......@@ -25260,7 +25260,109 @@
},
{
"name": "integration",
"description": "The updated HTTP integration",
"description": "The HTTP integration",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "AlertManagementHttpIntegration",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "HttpIntegrationDestroyInput",
"description": "Autogenerated input type of HttpIntegrationDestroy",
"fields": null,
"inputFields": [
{
"name": "id",
"description": "The id of the integration to remove",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "AlertManagementHttpIntegrationID",
"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": "HttpIntegrationDestroyPayload",
"description": "Autogenerated return type of HttpIntegrationDestroy",
"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": "Errors encountered during execution of the mutation.",
"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
},
{
"name": "integration",
"description": "The HTTP integration",
"args": [
],
......@@ -25362,7 +25464,7 @@
},
{
"name": "integration",
"description": "The updated HTTP integration",
"description": "The HTTP integration",
"args": [
],
......@@ -25484,7 +25586,7 @@
},
{
"name": "integration",
"description": "The updated HTTP integration",
"description": "The HTTP integration",
"args": [
],
......@@ -36844,6 +36946,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "httpIntegrationDestroy",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "HttpIntegrationDestroyInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "HttpIntegrationDestroyPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "httpIntegrationResetToken",
"description": null,
......@@ -1335,7 +1335,17 @@ Autogenerated return type of HttpIntegrationCreate.
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `integration` | AlertManagementHttpIntegration | The updated HTTP integration |
| `integration` | AlertManagementHttpIntegration | The HTTP integration |
### HttpIntegrationDestroyPayload
Autogenerated return type of HttpIntegrationDestroy.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `integration` | AlertManagementHttpIntegration | The HTTP integration |
### HttpIntegrationResetTokenPayload
......@@ -1345,7 +1355,7 @@ Autogenerated return type of HttpIntegrationResetToken.
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `integration` | AlertManagementHttpIntegration | The updated HTTP integration |
| `integration` | AlertManagementHttpIntegration | The HTTP integration |
### HttpIntegrationUpdatePayload
......@@ -1355,7 +1365,7 @@ Autogenerated return type of HttpIntegrationUpdate.
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `integration` | AlertManagementHttpIntegration | The updated HTTP integration |
| `integration` | AlertManagementHttpIntegration | The HTTP integration |
### InstanceSecurityDashboard
......
......@@ -22375,6 +22375,9 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
msgid "Removing integrations is not supported for this project"
msgstr ""
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
......@@ -30668,6 +30671,9 @@ msgstr ""
msgid "You have insufficient permissions to create an HTTP integration for this project"
msgstr ""
msgid "You have insufficient permissions to remove this HTTP integration"
msgstr ""
msgid "You have insufficient permissions to update this HTTP integration"
msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::AlertManagement::HttpIntegration::Destroy do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let(:integration) { create(:alert_management_http_integration, project: project) }
let(:args) { { id: GitlabSchema.id_from_object(integration) } }
specify { expect(described_class).to require_graphql_authorizations(:admin_operations) }
describe '#resolve' do
subject(:resolve) { mutation_for(project, current_user).resolve(args) }
context 'user has access to project' do
before do
project.add_maintainer(current_user)
end
context 'when HttpIntegrations::DestroyService responds with success' do
it 'returns the integration with no errors' do
expect(resolve).to eq(
integration: integration,
errors: []
)
end
end
context 'when HttpIntegrations::DestroyService responds with an error' do
before do
allow_any_instance_of(::AlertManagement::HttpIntegrations::DestroyService)
.to receive(:execute)
.and_return(ServiceResponse.error(payload: { integration: nil }, message: 'An error has occurred'))
end
it 'returns errors' do
expect(resolve).to eq(
integration: nil,
errors: ['An error has occurred']
)
end
end
end
context 'when resource is not accessible to the user' do
it 'raises an error if the resource is not accessible to the user' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
private
def mutation_for(project, user)
described_class.new(object: project, context: { current_user: user }, field: nil)
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Removing an HTTP Integration' do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:integration) { create(:alert_management_http_integration, project: project) }
let(:mutation) do
variables = {
id: GitlabSchema.id_from_object(integration).to_s
}
graphql_mutation(:http_integration_destroy, variables) do
<<~QL
clientMutationId
errors
integration {
id
type
name
active
token
url
apiUrl
}
QL
end
end
let(:mutation_response) { graphql_mutation_response(:http_integration_destroy) }
before do
project.add_maintainer(user)
end
it 'removes the integration' do
post_graphql_mutation(mutation, current_user: user)
integration_response = mutation_response['integration']
expect(response).to have_gitlab_http_status(:success)
expect(integration_response['id']).to eq(GitlabSchema.id_from_object(integration).to_s)
expect(integration_response['type']).to eq('HTTP')
expect(integration_response['name']).to eq(integration.name)
expect(integration_response['active']).to eq(integration.active)
expect(integration_response['token']).to eq(integration.token)
expect(integration_response['url']).to eq(integration.url)
expect(integration_response['apiUrl']).to eq(nil)
expect { integration.reload }.to raise_error ActiveRecord::RecordNotFound
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe AlertManagement::HttpIntegrations::DestroyService do
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be(:project) { create(:project) }
let!(:integration) { create(:alert_management_http_integration, project: project) }
let(:current_user) { user_with_permissions }
let(:params) { {} }
let(:service) { described_class.new(integration, current_user) }
before_all do
project.add_maintainer(user_with_permissions)
end
describe '#execute' do
shared_examples 'error response' do |message|
it 'has an informative message' do
expect(response).to be_error
expect(response.message).to eq(message)
end
end
subject(:response) { service.execute }
context 'when the current_user is anonymous' do
let(:current_user) { nil }
it_behaves_like 'error response', 'You have insufficient permissions to remove this HTTP integration'
end
context 'when current_user does not have permission to create integrations' do
let(:current_user) { user_without_permissions }
it_behaves_like 'error response', 'You have insufficient permissions to remove this HTTP integration'
end
context 'when feature flag is not enabled' do
before do
stub_feature_flags(multiple_http_integrations: false)
end
it_behaves_like 'error response', 'Removing integrations is not supported for this project'
end
context 'when an error occurs during removal' do
before do
allow(integration).to receive(:destroy).and_return(false)
integration.errors.add(:name, 'cannot be removed')
end
it_behaves_like 'error response', 'Name cannot be removed'
end
it 'successfully returns the integration' do
expect(response).to be_success
integration_result = response.payload[:integration]
expect(integration_result).to be_a(::AlertManagement::HttpIntegration)
expect(integration_result.name).to eq(integration.name)
expect(integration_result.active).to eq(integration.active)
expect(integration_result.token).to eq(integration.token)
expect(integration_result.endpoint_identifier).to eq(integration.endpoint_identifier)
expect { integration.reload }.to raise_error ActiveRecord::RecordNotFound
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