Commit 91dcf83b authored by Andy Soiron's avatar Andy Soiron

Merge branch '2256-add-organization-update-to-graphql' into 'master'

Add Organizations Update Mutation to GraphQL

See merge request gitlab-org/gitlab!69559
parents f7b25888 93757347
...@@ -38,15 +38,10 @@ module Mutations ...@@ -38,15 +38,10 @@ module Mutations
def resolve(args) def resolve(args)
group = authorized_find!(id: args[:group_id]) group = authorized_find!(id: args[:group_id])
raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless Feature.enabled?(:customer_relations, group) raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless Feature.enabled?(:customer_relations, group, default_enabled: :yaml)
result = ::CustomerRelations::Organizations::CreateService.new(group: group, current_user: current_user, params: args).execute result = ::CustomerRelations::Organizations::CreateService.new(group: group, current_user: current_user, params: args).execute
{ organization: result.payload, errors: result.errors }
if result.success?
{ organization: result.payload }
else
{ errors: result.errors }
end
end end
def find_object(id:) def find_object(id:)
......
# frozen_string_literal: true
module Mutations
module CustomerRelations
module Organizations
class Update < Mutations::BaseMutation
include ResolvesIds
graphql_name 'CustomerRelationsOrganizationUpdate'
authorize :admin_organization
field :organization,
Types::CustomerRelations::OrganizationType,
null: false,
description: 'Organization after the mutation.'
argument :id, ::Types::GlobalIDType[::CustomerRelations::Organization],
required: true,
description: 'Global ID of the organization.'
argument :name,
GraphQL::Types::String,
required: false,
description: 'Name of the organization.'
argument :default_rate,
GraphQL::Types::Float,
required: false,
description: 'Standard billing rate for the organization.'
argument :description,
GraphQL::Types::String,
required: false,
description: 'Description or notes for the organization.'
def resolve(args)
organization = ::Gitlab::Graphql::Lazy.force(GitlabSchema.object_from_id(args.delete(:id), expected_type: ::CustomerRelations::Organization))
raise_resource_not_available_error! unless organization
group = organization.group
raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless Feature.enabled?(:customer_relations, group, default_enabled: :yaml)
authorize!(group)
result = ::CustomerRelations::Organizations::UpdateService.new(group: group, current_user: current_user, params: args).execute(organization)
{ organization: result.payload, errors: result.errors }
end
end
end
end
end
...@@ -35,6 +35,7 @@ module Types ...@@ -35,6 +35,7 @@ module Types
mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji
mount_mutation Mutations::CustomEmoji::Destroy, feature_flag: :custom_emoji mount_mutation Mutations::CustomEmoji::Destroy, feature_flag: :custom_emoji
mount_mutation Mutations::CustomerRelations::Organizations::Create mount_mutation Mutations::CustomerRelations::Organizations::Create
mount_mutation Mutations::CustomerRelations::Organizations::Update
mount_mutation Mutations::Discussions::ToggleResolve mount_mutation Mutations::Discussions::ToggleResolve
mount_mutation Mutations::DependencyProxy::ImageTtlGroupPolicy::Update mount_mutation Mutations::DependencyProxy::ImageTtlGroupPolicy::Update
mount_mutation Mutations::Environments::CanaryIngress::Update mount_mutation Mutations::Environments::CanaryIngress::Update
......
# frozen_string_literal: true
module CustomerRelations
module Organizations
class BaseService < ::BaseGroupService
private
def allowed?
current_user&.can?(:admin_organization, group)
end
def error(message)
ServiceResponse.error(message: message)
end
end
end
end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module CustomerRelations module CustomerRelations
module Organizations module Organizations
class CreateService < ::BaseGroupService class CreateService < BaseService
# returns the created organization # returns the created organization
def execute def execute
return error_no_permissions unless allowed? return error_no_permissions unless allowed?
...@@ -18,14 +18,6 @@ module CustomerRelations ...@@ -18,14 +18,6 @@ module CustomerRelations
private private
def allowed?
current_user&.can?(:admin_organization, group)
end
def error(message)
ServiceResponse.error(message: message)
end
def error_no_permissions def error_no_permissions
error('You have insufficient permissions to create an organization for this group') error('You have insufficient permissions to create an organization for this group')
end end
......
# frozen_string_literal: true
module CustomerRelations
module Organizations
class UpdateService < BaseService
def execute(organization)
return error_no_permissions unless allowed?
return error_updating(organization) unless organization.update(params)
ServiceResponse.success(payload: organization)
end
private
def error_no_permissions
error('You have insufficient permissions to update an organization for this group')
end
def error_updating(organization)
error(organization&.errors&.full_messages || 'Failed to update organization')
end
end
end
end
...@@ -1430,6 +1430,28 @@ Input type: `CustomerRelationsOrganizationCreateInput` ...@@ -1430,6 +1430,28 @@ Input type: `CustomerRelationsOrganizationCreateInput`
| <a id="mutationcustomerrelationsorganizationcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationcustomerrelationsorganizationcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationcustomerrelationsorganizationcreateorganization"></a>`organization` | [`CustomerRelationsOrganization`](#customerrelationsorganization) | Organization after the mutation. | | <a id="mutationcustomerrelationsorganizationcreateorganization"></a>`organization` | [`CustomerRelationsOrganization`](#customerrelationsorganization) | Organization after the mutation. |
### `Mutation.customerRelationsOrganizationUpdate`
Input type: `CustomerRelationsOrganizationUpdateInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationcustomerrelationsorganizationupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcustomerrelationsorganizationupdatedefaultrate"></a>`defaultRate` | [`Float`](#float) | Standard billing rate for the organization. |
| <a id="mutationcustomerrelationsorganizationupdatedescription"></a>`description` | [`String`](#string) | Description or notes for the organization. |
| <a id="mutationcustomerrelationsorganizationupdateid"></a>`id` | [`CustomerRelationsOrganizationID!`](#customerrelationsorganizationid) | Global ID of the organization. |
| <a id="mutationcustomerrelationsorganizationupdatename"></a>`name` | [`String`](#string) | Name of the organization. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationcustomerrelationsorganizationupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcustomerrelationsorganizationupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationcustomerrelationsorganizationupdateorganization"></a>`organization` | [`CustomerRelationsOrganization!`](#customerrelationsorganization) | Organization after the mutation. |
### `Mutation.dastOnDemandScanCreate` ### `Mutation.dastOnDemandScanCreate`
Input type: `DastOnDemandScanCreateInput` Input type: `DastOnDemandScanCreateInput`
...@@ -16654,6 +16676,12 @@ A `CustomEmojiID` is a global ID. It is encoded as a string. ...@@ -16654,6 +16676,12 @@ A `CustomEmojiID` is a global ID. It is encoded as a string.
An example `CustomEmojiID` is: `"gid://gitlab/CustomEmoji/1"`. An example `CustomEmojiID` is: `"gid://gitlab/CustomEmoji/1"`.
### `CustomerRelationsOrganizationID`
A `CustomerRelationsOrganizationID` is a global ID. It is encoded as a string.
An example `CustomerRelationsOrganizationID` is: `"gid://gitlab/CustomerRelations::Organization/1"`.
### `DastProfileID` ### `DastProfileID`
A `DastProfileID` is a global ID. It is encoded as a string. A `DastProfileID` is a global ID. It is encoded as a string.
......
...@@ -5,8 +5,6 @@ require 'spec_helper' ...@@ -5,8 +5,6 @@ require 'spec_helper'
RSpec.describe Mutations::CustomerRelations::Organizations::Create do RSpec.describe Mutations::CustomerRelations::Organizations::Create do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let(:group) { create(:group) }
let(:valid_params) do let(:valid_params) do
attributes_for(:organization, attributes_for(:organization,
group: group, group: group,
...@@ -25,6 +23,8 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Create do ...@@ -25,6 +23,8 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Create do
end end
context 'when the user does not have permission' do context 'when the user does not have permission' do
let_it_be(:group) { create(:group) }
before do before do
group.add_guest(user) group.add_guest(user)
end end
...@@ -35,7 +35,9 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Create do ...@@ -35,7 +35,9 @@ RSpec.describe Mutations::CustomerRelations::Organizations::Create do
end end
context 'when the user has permission' do context 'when the user has permission' do
before do let_it_be(:group) { create(:group) }
before_all do
group.add_reporter(user) group.add_reporter(user)
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::CustomerRelations::Organizations::Update do
let_it_be(:user) { create(:user) }
let_it_be(:name) { 'GitLab' }
let_it_be(:default_rate) { 1000.to_f }
let_it_be(:description) { 'VIP' }
let(:organization) { create(:organization, group: group) }
let(:attributes) do
{
id: organization.to_global_id,
name: name,
default_rate: default_rate,
description: description
}
end
describe '#resolve' do
subject(:resolve_mutation) do
described_class.new(object: nil, context: { current_user: user }, field: nil).resolve(
attributes
)
end
context 'when the user does not have permission to update an organization' do
let_it_be(:group) { create(:group) }
before do
group.add_guest(user)
end
it 'raises an error' do
expect { resolve_mutation }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when the organization does not exist' do
let_it_be(:group) { create(:group) }
it 'raises an error' do
attributes[:id] = 'gid://gitlab/CustomerRelations::Organization/999'
expect { resolve_mutation }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when the user has permission to update an organization' do
let_it_be(:group) { create(:group) }
before_all do
group.add_reporter(user)
end
it 'updates the organization with correct values' do
expect(resolve_mutation[:organization]).to have_attributes(attributes)
end
context 'when the feature is disabled' do
before do
stub_feature_flags(customer_relations: false)
end
it 'raises an error' do
expect { resolve_mutation }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
end
specify { expect(described_class).to require_graphql_authorizations(:admin_organization) }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe CustomerRelations::Organizations::UpdateService do
let_it_be(:user) { create(:user) }
let(:organization) { create(:organization, name: 'Test', group: group) }
subject(:update) { described_class.new(group: group, current_user: user, params: params).execute(organization) }
describe '#execute' do
context 'when the user has no permission' do
let_it_be(:group) { create(:group) }
let(:params) { { name: 'GitLab' } }
it 'returns an error' do
response = update
expect(response).to be_error
expect(response.message).to eq('You have insufficient permissions to update an organization for this group')
end
end
context 'when user has permission' do
let_it_be(:group) { create(:group) }
before_all do
group.add_reporter(user)
end
context 'when name is changed' do
let(:params) { { name: 'GitLab' } }
it 'updates the organization' do
response = update
expect(response).to be_success
expect(response.payload.name).to eq('GitLab')
end
end
context 'when the organization is invalid' do
let(:params) { { name: nil } }
it 'returns an error' do
response = update
expect(response).to be_error
expect(response.message).to eq(["Name can't be blank"])
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