Commit 29fd9b7b authored by Nick Thomas's avatar Nick Thomas

Merge branch 'issue_321770-add_graphql_mutation' into 'master'

Allow to update epic boards lists with GraphQL

See merge request gitlab-org/gitlab!58782
parents a41f5609 b7fa6599
# frozen_string_literal: true
module Mutations
module Boards
module Lists
class BaseUpdate < BaseMutation
argument :position, GraphQL::INT_TYPE,
required: false,
description: 'Position of list within the board.'
argument :collapsed, GraphQL::BOOLEAN_TYPE,
required: false,
description: 'Indicates if the list is collapsed for this user.'
def resolve(list: nil, **args)
if list.nil? || !can_read_list?(list)
raise_resource_not_available_error!
end
update_result = update_list(list, args)
{
list: update_result[:list],
errors: list.errors.full_messages
}
end
private
def update_list(list, args)
raise NotImplementedError
end
def can_read_list?(list)
raise NotImplementedError
end
end
end
end
end
......@@ -3,7 +3,7 @@
module Mutations
module Boards
module Lists
class Update < BaseMutation
class Update < BaseUpdate
graphql_name 'UpdateBoardList'
argument :list_id, Types::GlobalIDType[List],
......@@ -11,29 +11,11 @@ module Mutations
loads: Types::BoardListType,
description: 'Global ID of the list.'
argument :position, GraphQL::INT_TYPE,
required: false,
description: 'Position of list within the board.'
argument :collapsed, GraphQL::BOOLEAN_TYPE,
required: false,
description: 'Indicates if the list is collapsed for this user.'
field :list,
Types::BoardListType,
null: true,
description: 'Mutated list.'
def resolve(list: nil, **args)
raise_resource_not_available_error! unless can_read_list?(list)
update_result = update_list(list, args)
{
list: update_result[:list],
errors: list.errors.full_messages
}
end
private
def update_list(list, args)
......@@ -42,8 +24,6 @@ module Mutations
end
def can_read_list?(list)
return false unless list.present?
Ability.allowed?(current_user, :read_issue_board_list, list.board)
end
end
......
......@@ -6777,6 +6777,16 @@ Autogenerated return type of UpdateContainerExpirationPolicy.
| `containerExpirationPolicy` | [`ContainerExpirationPolicy`](#containerexpirationpolicy) | The container expiration policy after mutation. |
| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `UpdateEpicBoardListPayload`
Autogenerated return type of UpdateEpicBoardList.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| `errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| `list` | [`EpicList`](#epiclist) | Mutated epic list. |
### `UpdateEpicPayload`
Autogenerated return type of UpdateEpic.
......
......@@ -43,6 +43,7 @@ module EE
mount_mutation ::Mutations::Boards::EpicBoards::EpicMoveList
mount_mutation ::Mutations::Boards::EpicBoards::Update
mount_mutation ::Mutations::Boards::EpicLists::Create
mount_mutation ::Mutations::Boards::EpicLists::Update
mount_mutation ::Mutations::Boards::Lists::UpdateLimitMetrics
mount_mutation ::Mutations::InstanceSecurityDashboard::AddProject
mount_mutation ::Mutations::InstanceSecurityDashboard::RemoveProject
......
# frozen_string_literal: true
module Mutations
module Boards
module EpicLists
class Update < ::Mutations::Boards::Lists::BaseUpdate
graphql_name 'UpdateEpicBoardList'
argument :list_id, Types::GlobalIDType[::Boards::EpicList],
required: true,
loads: Types::Boards::EpicListType,
description: 'Global ID of the epic list.'
field :list,
Types::Boards::EpicListType,
null: true,
description: 'Mutated epic list.'
private
def update_list(list, args)
service = ::Boards::EpicLists::UpdateService.new(list.board, current_user, args)
service.execute(list)
end
def can_read_list?(list)
Ability.allowed?(current_user, :read_epic_board_list, list.board)
end
end
end
end
end
---
title: Add GraphQL mutation that allows to update epic boards lists
merge_request: 58782
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Boards::EpicLists::Update do
let_it_be(:group) { create(:group, :private) }
let_it_be(:board) { create(:epic_board, group: group) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:list) { create(:epic_list, epic_board: board, position: 0) }
let_it_be(:list2) { create(:epic_list, epic_board: board) }
before do
stub_licensed_features(epics: true)
end
context 'on epic boards' do
it_behaves_like 'update board list mutation'
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Update of an existing epic board list' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:board) { create(:epic_board, group: group) }
let_it_be(:list) { create(:epic_list, epic_board: board, position: 0) }
let_it_be(:list2) { create(:epic_list, epic_board: board) }
let_it_be(:input) { { list_id: list.to_global_id.to_s, position: 1, collapsed: true } }
let(:mutation) { graphql_mutation(:update_epic_board_list, input) }
let(:mutation_response) { graphql_mutation_response(:update_epic_board_list) }
before do
stub_licensed_features(epics: true)
end
it_behaves_like 'a GraphQL request to update board list'
end
......@@ -3,54 +3,14 @@
require 'spec_helper'
RSpec.describe Mutations::Boards::Lists::Update do
let_it_be(:group) { create(:group, :private) }
let_it_be(:board) { create(:board, group: group) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:list) { create(:list, board: board, position: 0) }
let_it_be(:list2) { create(:list, board: board) }
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
let(:list_update_params) { { position: 1, collapsed: true } }
before_all do
group.add_reporter(reporter)
group.add_guest(guest)
list.update_preferences_for(reporter, collapsed: false)
end
subject { mutation.resolve(list: list, **list_update_params) }
describe '#resolve' do
context 'with permission to admin board lists' do
let(:current_user) { reporter }
it 'updates the list position and collapsed state as expected' do
subject
reloaded_list = list.reload
expect(reloaded_list.position).to eq(1)
expect(reloaded_list.collapsed?(current_user)).to eq(true)
end
end
context 'with permission to read board lists' do
let(:current_user) { guest }
it 'updates the list collapsed state but not the list position' do
subject
reloaded_list = list.reload
expect(reloaded_list.position).to eq(0)
expect(reloaded_list.collapsed?(current_user)).to eq(true)
end
end
context 'without permission to read board lists' do
let(:current_user) { create(:user) }
it 'raises Resource Not Found error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'on group issue boards' do
let_it_be(:group) { create(:group, :private) }
let_it_be(:board) { create(:board, group: group) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:list) { create(:list, board: board, position: 0) }
let_it_be(:list2) { create(:list, board: board) }
it_behaves_like 'update board list mutation'
end
end
......@@ -14,43 +14,5 @@ RSpec.describe 'Update of an existing board list' do
let(:mutation) { graphql_mutation(:update_board_list, input) }
let(:mutation_response) { graphql_mutation_response(:update_board_list) }
context 'the user is not allowed to read board lists' do
it_behaves_like 'a mutation that returns a top-level access error'
end
before do
list.update_preferences_for(current_user, collapsed: false)
end
context 'when user has permissions to admin board lists' do
before do
group.add_reporter(current_user)
end
it 'updates the list position and collapsed state' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['list']).to include(
'position' => 1,
'collapsed' => true
)
end
end
context 'when user has permissions to read board lists' do
before do
group.add_guest(current_user)
end
it 'updates the list collapsed state but not the list position' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['list']).to include(
'position' => 0,
'collapsed' => true
)
end
end
it_behaves_like 'a GraphQL request to update board list'
end
# frozen_string_literal: true
RSpec.shared_examples 'update board list mutation' do
describe '#resolve' do
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
let(:list_update_params) { { position: 1, collapsed: true } }
subject { mutation.resolve(list: list, **list_update_params) }
before_all do
group.add_reporter(reporter)
group.add_guest(guest)
list.update_preferences_for(reporter, collapsed: false)
end
context 'with permission to admin board lists' do
let(:current_user) { reporter }
it 'updates the list position and collapsed state as expected' do
subject
reloaded_list = list.reload
expect(reloaded_list.position).to eq(1)
expect(reloaded_list.collapsed?(current_user)).to eq(true)
end
end
context 'with permission to read board lists' do
let(:current_user) { guest }
it 'updates the list collapsed state but not the list position' do
subject
reloaded_list = list.reload
expect(reloaded_list.position).to eq(0)
expect(reloaded_list.collapsed?(current_user)).to eq(true)
end
end
context 'without permission to read board lists' do
let(:current_user) { create(:user) }
it 'raises Resource Not Found error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
end
# frozen_string_literal: true
RSpec.shared_examples 'a GraphQL request to update board list' do
context 'the user is not allowed to read board lists' do
it_behaves_like 'a mutation that returns a top-level access error'
end
before do
list.update_preferences_for(current_user, collapsed: false)
end
context 'when user has permissions to admin board lists' do
before do
group.add_reporter(current_user)
end
it 'updates the list position and collapsed state' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['list']).to include(
'position' => 1,
'collapsed' => true
)
end
end
context 'when user has permissions to read board lists' do
before do
group.add_guest(current_user)
end
it 'updates the list collapsed state but not the list position' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['list']).to include(
'position' => 0,
'collapsed' => true
)
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