Commit a6bae002 authored by Takuya Noguchi's avatar Takuya Noguchi

Make all Project Issue Boards API available even in CE

This change moves all project issue boards API to EE to CE, but
filtering by milestons, assignees, and/or weights remains in EE.

This change includes specs for creating, updating, and deleting
project issue board APIs.
Signed-off-by: default avatarTakuya Noguchi <takninnovationresearch@gmail.com>
parent ee8e6fa5
---
title: Make all Project Issue Boards API available even in CE
merge_request: 46137
author: Takuya Noguchi
type: changed
...@@ -8,7 +8,6 @@ module EE ...@@ -8,7 +8,6 @@ module EE
prepended do prepended do
use ::Gitlab::Middleware::IpRestrictor use ::Gitlab::Middleware::IpRestrictor
mount ::EE::API::Boards
mount ::EE::API::GroupBoards mount ::EE::API::GroupBoards
mount ::API::AuditEvents mount ::API::AuditEvents
......
# frozen_string_literal: true
module EE
module API
class Boards < ::API::Base
include ::API::PaginationParams
include ::API::BoardsResponses
prepend EE::API::BoardsResponses # rubocop: disable Cop/InjectEnterpriseEditionModule
before { authenticate! }
helpers do
def board_parent
user_project
end
end
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
segment ':id/boards' do
desc 'Create a project board' do
detail 'This feature was introduced in 10.4'
success ::API::Entities::Board
end
params do
requires :name, type: String, desc: 'The board name'
end
post '/' do
authorize!(:admin_board, board_parent)
create_board
end
desc 'Update a project board' do
detail 'This feature was introduced in 11.0'
success ::API::Entities::Board
end
params do
use :update_params
end
put '/:board_id' do
authorize!(:admin_board, board_parent)
update_board
end
desc 'Delete a project board' do
detail 'This feature was introduced in 10.4'
success ::API::Entities::Board
end
delete '/:board_id' do
authorize!(:admin_board, board_parent)
delete_board
end
end
end
end
end
end
...@@ -7,35 +7,7 @@ module EE ...@@ -7,35 +7,7 @@ module EE
prepended do prepended do
helpers do helpers do
def create_board # Overrides API::BoardsResponses create_list_params
forbidden! unless board_parent.multiple_issue_boards_available?
response =
::Boards::CreateService.new(board_parent, current_user, { name: params[:name] }).execute
present response.payload, with: ::API::Entities::Board
end
def update_board
service = ::Boards::UpdateService.new(board_parent, current_user, declared_params(include_missing: false))
service.execute(board)
if board.valid?
present board, with: ::API::Entities::Board
else
bad_request!("Failed to save board #{board.errors.messages}")
end
end
def delete_board
forbidden! unless board_parent.multiple_issue_boards_available?
destroy_conditionally!(board) do |board|
service = ::Boards::DestroyService.new(board_parent, current_user)
service.execute(board)
end
end
def create_list_params def create_list_params
params.slice(:label_id, :milestone_id, :assignee_id) params.slice(:label_id, :milestone_id, :assignee_id)
end end
...@@ -73,6 +45,7 @@ module EE ...@@ -73,6 +45,7 @@ module EE
exactly_one_of :label_id, :milestone_id, :assignee_id exactly_one_of :label_id, :milestone_id, :assignee_id
end end
# Overrides API::BoardsResponses update_params
params :update_params do params :update_params do
optional :name, type: String, desc: 'The board name' optional :name, type: String, desc: 'The board name'
optional :assignee_id, type: Integer, desc: 'The ID of a user to associate with board' optional :assignee_id, type: Integer, desc: 'The ID of a user to associate with board'
......
...@@ -7,11 +7,10 @@ module EE ...@@ -7,11 +7,10 @@ module EE
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepended do prepended do
# Default filtering configuration
expose :name
expose :group, using: ::API::Entities::BasicGroupDetails expose :group, using: ::API::Entities::BasicGroupDetails
with_options if: ->(board, _) { board.resource_parent.feature_available?(:scoped_issue_board) } do with_options if: ->(board, _) { board.resource_parent.feature_available?(:scoped_issue_board) } do
# Default filtering configuration
expose :milestone do |board| expose :milestone do |board|
if board.milestone.is_a?(Milestone) if board.milestone.is_a?(Milestone)
::API::Entities::Milestone.represent(board.milestone) ::API::Entities::Milestone.represent(board.milestone)
......
...@@ -40,6 +40,43 @@ module API ...@@ -40,6 +40,43 @@ module API
authorize!(:read_board, user_project) authorize!(:read_board, user_project)
present board, with: Entities::Board present board, with: Entities::Board
end end
desc 'Create a project board' do
detail 'This feature was introduced in 10.4'
success Entities::Board
end
params do
requires :name, type: String, desc: 'The board name'
end
post '/' do
authorize!(:admin_board, board_parent)
create_board
end
desc 'Update a project board' do
detail 'This feature was introduced in 11.0'
success Entities::Board
end
params do
use :update_params
end
put '/:board_id' do
authorize!(:admin_board, board_parent)
update_board
end
desc 'Delete a project board' do
detail 'This feature was introduced in 10.4'
success Entities::Board
end
delete '/:board_id' do
authorize!(:admin_board, board_parent)
delete_board
end
end end
params do params do
......
...@@ -10,6 +10,35 @@ module API ...@@ -10,6 +10,35 @@ module API
board_parent.boards.find(params[:board_id]) board_parent.boards.find(params[:board_id])
end end
def create_board
forbidden! unless board_parent.multiple_issue_boards_available?
response =
::Boards::CreateService.new(board_parent, current_user, { name: params[:name] }).execute
present response.payload, with: Entities::Board
end
def update_board
service = ::Boards::UpdateService.new(board_parent, current_user, declared_params(include_missing: false))
service.execute(board)
if board.valid?
present board, with: Entities::Board
else
bad_request!("Failed to save board #{board.errors.messages}")
end
end
def delete_board
forbidden! unless board_parent.multiple_issue_boards_available?
destroy_conditionally!(board) do |board|
service = ::Boards::DestroyService.new(board_parent, current_user)
service.execute(board)
end
end
def board_lists def board_lists
board.destroyable_lists board.destroyable_lists
end end
...@@ -62,6 +91,12 @@ module API ...@@ -62,6 +91,12 @@ module API
params :list_creation_params do params :list_creation_params do
requires :label_id, type: Integer, desc: 'The ID of an existing label' requires :label_id, type: Integer, desc: 'The ID of an existing label'
end end
params :update_params do
# Configurable issue boards are not available in CE/EE Core.
# https://docs.gitlab.com/ee/user/project/issue_board.html#configurable-issue-boards
optional :name, type: String, desc: 'The board name'
end
end end
end end
end end
......
...@@ -4,6 +4,7 @@ module API ...@@ -4,6 +4,7 @@ module API
module Entities module Entities
class Board < Grape::Entity class Board < Grape::Entity
expose :id expose :id
expose :name
expose :project, using: Entities::BasicProjectDetails expose :project, using: Entities::BasicProjectDetails
expose :lists, using: Entities::List do |board| expose :lists, using: Entities::List do |board|
......
...@@ -35,7 +35,46 @@ RSpec.describe API::Boards do ...@@ -35,7 +35,46 @@ RSpec.describe API::Boards do
it_behaves_like 'group and project boards', "/projects/:id/boards" it_behaves_like 'group and project boards', "/projects/:id/boards"
describe "POST /projects/:id/boards/lists" do describe "POST /projects/:id/boards" do
let(:url) { "/projects/#{board_parent.id}/boards" }
it 'creates a new issue board' do
post api(url, user), params: { name: 'foo' }
expect(response).to have_gitlab_http_status(:created)
expect(json_response['name']).to eq('foo')
end
it 'fails to create a new board' do
post api(url, user), params: { some_name: 'foo' }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq('name is missing')
end
end
describe "PUT /projects/:id/boards/:board_id" do
let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}" }
it 'updates the issue board' do
put api(url, user), params: { name: 'changed board name' }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['name']).to eq('changed board name')
end
end
describe "DELETE /projects/:id/boards/:board_id" do
let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}" }
it 'delete the issue board' do
delete api(url, user)
expect(response).to have_gitlab_http_status(:no_content)
end
end
describe "POST /projects/:id/boards/:board_id/lists" do
let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}/lists" } let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}/lists" }
it 'creates a new issue board list for group labels' do it 'creates a new issue board list for group labels' do
...@@ -65,7 +104,7 @@ RSpec.describe API::Boards do ...@@ -65,7 +104,7 @@ RSpec.describe API::Boards do
end end
end end
describe "POST /groups/:id/boards/lists" do describe "POST /groups/:id/boards/:board_id/lists" do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:board_parent) { create(:group, parent: group ) } let_it_be(:board_parent) { create(:group, parent: group ) }
let(:url) { "/groups/#{board_parent.id}/boards/#{board.id}/lists" } let(:url) { "/groups/#{board_parent.id}/boards/#{board.id}/lists" }
......
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