Commit 19e245d5 authored by Sean Arnold's avatar Sean Arnold

Update mutation logic

- Stop using public_send
- Use ServiceResponse
- Fix spec styles
- Update docs
parent 74967bd0
...@@ -20,7 +20,7 @@ module Mutations ...@@ -20,7 +20,7 @@ module Mutations
private private
def find_alert(project_path:, iid:) def find_object(project_path:, iid:)
project = resolve_project(full_path: project_path) project = resolve_project(full_path: project_path)
return unless project return unless project
......
# frozen_string_literal: true
module Mutations
module AlertManagement
class ChangeAlertStatus < Base
graphql_name 'ChangeAlertStatus'
argument :status, Types::AlertManagement::StatusEnum,
required: true,
description: "The status to set the alert"
def resolve(args)
alert = find_alert(project_path: args[:project_path], iid: args[:iid])
if alert
service = ::AlertManagement::AlertService.new(alert)
service.set_status!(args[:status])
else
self.errors = Array('Alert could not be found')
end
{
alert: alert,
errors: errors
}
end
private
attr_accessor :errors
end
end
end
# frozen_string_literal: true
module Mutations
module AlertManagement
class UpdateAlertStatus < Base
graphql_name 'UpdateAlertStatus'
argument :status, Types::AlertManagement::StatusEnum,
required: true,
description: 'The status to set the alert'
authorize :read_alert_management_alerts
def resolve(args)
alert = authorized_find!(project_path: args[:project_path], iid: args[:iid])
if alert
result = update_status(alert, args[:status])
prepare_response(result)
else
{
alert: alert,
errors: ['Alert could not be found']
}
end
end
private
def update_status(alert, status)
service = ::AlertManagement::UpdateAlertStatusService.new(alert, status)
service.execute!
end
def prepare_response(result)
{
alert: result.payload[:alert],
errors: result.message.present? ? [result.message] : []
}
end
end
end
end
...@@ -7,7 +7,7 @@ module Types ...@@ -7,7 +7,7 @@ module Types
graphql_name 'Mutation' graphql_name 'Mutation'
mount_mutation Mutations::Admin::SidekiqQueues::DeleteJobs mount_mutation Mutations::Admin::SidekiqQueues::DeleteJobs
mount_mutation Mutations::AlertManagement::ChangeAlertStatus mount_mutation Mutations::AlertManagement::UpdateAlertStatus
mount_mutation Mutations::AwardEmojis::Add mount_mutation Mutations::AwardEmojis::Add
mount_mutation Mutations::AwardEmojis::Remove mount_mutation Mutations::AwardEmojis::Remove
mount_mutation Mutations::AwardEmojis::Toggle mount_mutation Mutations::AwardEmojis::Toggle
......
# frozen_string_literal: true
module AlertManagement
class AlertService
attr_reader :alert
def initialize(alert)
@alert = alert
end
def set_status!(status)
return unless AlertManagement::Alert.statuses.key?(status.to_s)
# rubocop:disable GitlabSecurity/PublicSend
alert.public_send("#{status}!")
# rubocop:enable GitlabSecurity/PublicSend
end
end
end
# frozen_string_literal: true
module AlertManagement
class UpdateAlertStatusService
def initialize(alert, status)
@alert = alert
@status = status
end
def execute!
return error_response('Invalid status') unless AlertManagement::Alert.statuses.key?(status.to_s)
alert.status = status
return ServiceResponse.success(payload: { alert: alert }) if alert.save
error_response
end
private
def error_response(message)
ServiceResponse.error(payload: { alert: alert }, message: message)
end
attr_reader :alert, :status
end
end
...@@ -653,51 +653,6 @@ type Branch { ...@@ -653,51 +653,6 @@ type Branch {
name: String! name: String!
} }
"""
Autogenerated input type of ChangeAlertStatus
"""
input ChangeAlertStatusInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
The iid of the alert to mutate
"""
iid: String!
"""
The project the alert to mutate is in
"""
projectPath: ID!
"""
The status to set the alert
"""
status: AlertManagementStatus!
}
"""
Autogenerated return type of ChangeAlertStatus
"""
type ChangeAlertStatusPayload {
"""
The alert after mutation
"""
alert: AlertManagementAlert
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Reasons why the mutation failed.
"""
errors: [String!]!
}
type Commit { type Commit {
""" """
Author of the commit Author of the commit
...@@ -6087,7 +6042,6 @@ type Mutation { ...@@ -6087,7 +6042,6 @@ type Mutation {
addProjectToSecurityDashboard(input: AddProjectToSecurityDashboardInput!): AddProjectToSecurityDashboardPayload addProjectToSecurityDashboard(input: AddProjectToSecurityDashboardInput!): AddProjectToSecurityDashboardPayload
adminSidekiqQueuesDeleteJobs(input: AdminSidekiqQueuesDeleteJobsInput!): AdminSidekiqQueuesDeleteJobsPayload adminSidekiqQueuesDeleteJobs(input: AdminSidekiqQueuesDeleteJobsInput!): AdminSidekiqQueuesDeleteJobsPayload
boardListUpdateLimitMetrics(input: BoardListUpdateLimitMetricsInput!): BoardListUpdateLimitMetricsPayload boardListUpdateLimitMetrics(input: BoardListUpdateLimitMetricsInput!): BoardListUpdateLimitMetricsPayload
changeAlertStatus(input: ChangeAlertStatusInput!): ChangeAlertStatusPayload
createBranch(input: CreateBranchInput!): CreateBranchPayload createBranch(input: CreateBranchInput!): CreateBranchPayload
createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload
createEpic(input: CreateEpicInput!): CreateEpicPayload createEpic(input: CreateEpicInput!): CreateEpicPayload
...@@ -6120,6 +6074,7 @@ type Mutation { ...@@ -6120,6 +6074,7 @@ type Mutation {
todoRestoreMany(input: TodoRestoreManyInput!): TodoRestoreManyPayload todoRestoreMany(input: TodoRestoreManyInput!): TodoRestoreManyPayload
todosMarkAllDone(input: TodosMarkAllDoneInput!): TodosMarkAllDonePayload todosMarkAllDone(input: TodosMarkAllDoneInput!): TodosMarkAllDonePayload
toggleAwardEmoji(input: ToggleAwardEmojiInput!): ToggleAwardEmojiPayload toggleAwardEmoji(input: ToggleAwardEmojiInput!): ToggleAwardEmojiPayload
updateAlertStatus(input: UpdateAlertStatusInput!): UpdateAlertStatusPayload
updateEpic(input: UpdateEpicInput!): UpdateEpicPayload updateEpic(input: UpdateEpicInput!): UpdateEpicPayload
""" """
...@@ -9775,6 +9730,51 @@ enum TypeEnum { ...@@ -9775,6 +9730,51 @@ enum TypeEnum {
project project
} }
"""
Autogenerated input type of UpdateAlertStatus
"""
input UpdateAlertStatusInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
The iid of the alert to mutate
"""
iid: String!
"""
The project the alert to mutate is in
"""
projectPath: ID!
"""
The status to set the alert
"""
status: AlertManagementStatus!
}
"""
Autogenerated return type of UpdateAlertStatus
"""
type UpdateAlertStatusPayload {
"""
The alert after mutation
"""
alert: AlertManagementAlert
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Reasons why the mutation failed.
"""
errors: [String!]!
}
input UpdateDiffImagePositionInput { input UpdateDiffImagePositionInput {
""" """
Total height of the image Total height of the image
......
...@@ -1888,136 +1888,6 @@ ...@@ -1888,136 +1888,6 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "INPUT_OBJECT",
"name": "ChangeAlertStatusInput",
"description": "Autogenerated input type of ChangeAlertStatus",
"fields": null,
"inputFields": [
{
"name": "projectPath",
"description": "The project the alert to mutate is in",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "iid",
"description": "The iid of the alert to mutate",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "status",
"description": "The status to set the alert",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "AlertManagementStatus",
"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": "ChangeAlertStatusPayload",
"description": "Autogenerated return type of ChangeAlertStatus",
"fields": [
{
"name": "alert",
"description": "The alert after mutation",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "AlertManagementAlert",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"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", "kind": "OBJECT",
"name": "Commit", "name": "Commit",
...@@ -17395,33 +17265,6 @@ ...@@ -17395,33 +17265,6 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "changeAlertStatus",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "ChangeAlertStatusInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "ChangeAlertStatusPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "createBranch", "name": "createBranch",
"description": null, "description": null,
...@@ -18286,6 +18129,33 @@ ...@@ -18286,6 +18129,33 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "updateAlertStatus",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "UpdateAlertStatusInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "UpdateAlertStatusPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "updateEpic", "name": "updateEpic",
"description": null, "description": null,
...@@ -29405,6 +29275,136 @@ ...@@ -29405,6 +29275,136 @@
], ],
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "INPUT_OBJECT",
"name": "UpdateAlertStatusInput",
"description": "Autogenerated input type of UpdateAlertStatus",
"fields": null,
"inputFields": [
{
"name": "projectPath",
"description": "The project the alert to mutate is in",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "iid",
"description": "The iid of the alert to mutate",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "status",
"description": "The status to set the alert",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "AlertManagementStatus",
"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": "UpdateAlertStatusPayload",
"description": "Autogenerated return type of UpdateAlertStatus",
"fields": [
{
"name": "alert",
"description": "The alert after mutation",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "AlertManagementAlert",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"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": "INPUT_OBJECT", "kind": "INPUT_OBJECT",
"name": "UpdateDiffImagePositionInput", "name": "UpdateDiffImagePositionInput",
......
...@@ -140,16 +140,6 @@ Autogenerated return type of BoardListUpdateLimitMetrics ...@@ -140,16 +140,6 @@ Autogenerated return type of BoardListUpdateLimitMetrics
| `commit` | Commit | Commit for the branch | | `commit` | Commit | Commit for the branch |
| `name` | String! | Name of the branch | | `name` | String! | Name of the branch |
## ChangeAlertStatusPayload
Autogenerated return type of ChangeAlertStatus
| Name | Type | Description |
| --- | ---- | ---------- |
| `alert` | AlertManagementAlert | The alert after mutation |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
## Commit ## Commit
| Name | Type | Description | | Name | Type | Description |
...@@ -1525,6 +1515,16 @@ Represents a directory ...@@ -1525,6 +1515,16 @@ Represents a directory
| `type` | EntryType! | Type of tree entry | | `type` | EntryType! | Type of tree entry |
| `webUrl` | String | Web URL for the tree entry (directory) | | `webUrl` | String | Web URL for the tree entry (directory) |
## UpdateAlertStatusPayload
Autogenerated return type of UpdateAlertStatus
| Name | Type | Description |
| --- | ---- | ---------- |
| `alert` | AlertManagementAlert | The alert after mutation |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
## UpdateEpicPayload ## UpdateEpicPayload
Autogenerated return type of UpdateEpic Autogenerated return type of UpdateEpic
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
require 'spec_helper' require 'spec_helper'
describe Mutations::AlertManagement::ChangeAlertStatus do describe Mutations::AlertManagement::UpdateAlertStatus do
let_it_be(:current_user) { create(:user) } let_it_be(:current_user) { create(:user) }
let_it_be(:alert) { create(:alert_management_alert) } let_it_be(:alert) { create(:alert_management_alert, status: 'triggered') }
let(:project) { alert.project } let(:project) { alert.project }
let(:new_status) { 'acknowledged' } let(:new_status) { 'acknowledged' }
let(:args) { { status: new_status, project_path: project.full_path, iid: alert.iid } } let(:args) { { status: new_status, project_path: project.full_path, iid: alert.iid } }
...@@ -17,19 +17,13 @@ describe Mutations::AlertManagement::ChangeAlertStatus do ...@@ -17,19 +17,13 @@ describe Mutations::AlertManagement::ChangeAlertStatus do
project.add_developer(current_user) project.add_developer(current_user)
end end
it 'does not change the status' do it 'changes the status' do
expect { resolve }.to change { alert.reload.status }.from(alert.status).to(new_status) expect { resolve }.to change { alert.reload.status }.from(alert.status).to(new_status)
end end
end end
context 'user has no access' do it 'raises an error if the resource is not accessible to the user' do
it 'does not change the status' do expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
expect { resolve }.not_to change { alert.reload.status }
end
it 'sets the error' do
expect(resolve.dig(:errors)).not_to be_empty
end
end end
end end
......
...@@ -2,26 +2,27 @@ ...@@ -2,26 +2,27 @@
require 'spec_helper' require 'spec_helper'
describe AlertManagement::AlertService do describe AlertManagement::UpdateAlertStatusService do
let_it_be(:alert) { create(:alert_management_alert) } let_it_be(:alert) { create(:alert_management_alert, status: 'triggered') }
let(:instance) { described_class.new(alert) }
describe '#set_status!' do describe '#execute!' do
subject(:set_status) { instance.set_status!(new_status) } subject(:execute) { described_class.new(alert, new_status).execute! }
let(:new_status) { 'acknowledged' } let(:new_status) { 'acknowledged' }
it 'updates the status' do it 'updates the status' do
expect { set_status }.to change { alert.status }.to(new_status) expect { execute }.to change { alert.status }.to(new_status)
end end
context 'with unknown status' do context 'with unknown status' do
let(:new_status) { 'random_status' } let(:new_status) { 'random_status' }
it { is_expected.to be_nil } it 'returns an error' do
expect(execute.status).to eq(:error)
end
it 'does not update the status' do it 'does not update the status' do
expect { set_status }.not_to change { alert.status } expect { execute }.not_to change { alert.status }
end 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