Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Jérome Perrin
gitlab-ce
Commits
41d70ea3
Commit
41d70ea3
authored
Oct 03, 2016
by
Andre Guedes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added Issue Board API support
- Includes documentation and tests
parent
8ddb082f
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
577 additions
and
1 deletion
+577
-1
CHANGELOG
CHANGELOG
+1
-0
doc/api/boards.md
doc/api/boards.md
+251
-0
lib/api/api.rb
lib/api/api.rb
+1
-0
lib/api/boards.rb
lib/api/boards.rb
+115
-0
lib/api/entities.rb
lib/api/entities.rb
+17
-1
spec/requests/api/boards_spec.rb
spec/requests/api/boards_spec.rb
+192
-0
No files found.
CHANGELOG
View file @
41d70ea3
...
...
@@ -18,6 +18,7 @@ v 8.13.0 (unreleased)
- Expose expires_at field when sharing project on API
- Fix VueJS template tags being rendered in code comments
- Fix issue with page scrolling to top when closing or pinning sidebar (lukehowell)
- Add Issue Board API support (andrebsguedes)
- Allow the Koding integration to be configured through the API
- Added soft wrap button to repository file/blob editor
- Add word-wrap to issue title on issue and milestone boards (ClemMakesApps)
...
...
doc/api/boards.md
0 → 100644
View file @
41d70ea3
# Boards
Every API call to boards must be authenticated.
If a user is not a member of a project and the project is private, a
`GET`
request on that project will result to a
`404`
status code.
## Project Board
Lists Issue Boards in the given project.
```
GET /projects/:id/boards
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer | yes | The ID of a project |
```
bash
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v3/projects/:id/boards
```
Example response:
```
json
[
{
"id"
:
1
,
"lists"
:
[
{
"id"
:
1
,
"label"
:
{
"name"
:
"Testing"
,
"color"
:
"#F0AD4E"
,
"description"
:
null
},
"position"
:
1
},
{
"id"
:
2
,
"label"
:
{
"name"
:
"Ready"
,
"color"
:
"#FF0000"
,
"description"
:
null
},
"position"
:
2
},
{
"id"
:
3
,
"label"
:
{
"name"
:
"Production"
,
"color"
:
"#FF5F00"
,
"description"
:
null
},
"position"
:
3
}
]
}
]
```
## List board lists
Get a list of the board's lists.
Does not include
`backlog`
and
`done`
lists
```
GET /projects/:id/boards/:board_id/lists
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer | yes | The ID of a project |
|
`board_id`
| integer | yes | The ID of a board |
```
bash
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v3/projects/5/boards/1/lists
```
Example response:
```
json
[
{
"id"
:
1
,
"label"
:
{
"name"
:
"Testing"
,
"color"
:
"#F0AD4E"
,
"description"
:
null
},
"position"
:
1
},
{
"id"
:
2
,
"label"
:
{
"name"
:
"Ready"
,
"color"
:
"#FF0000"
,
"description"
:
null
},
"position"
:
2
},
{
"id"
:
3
,
"label"
:
{
"name"
:
"Production"
,
"color"
:
"#FF5F00"
,
"description"
:
null
},
"position"
:
3
}
]
```
## Single board list
Get a single board list.
```
GET /projects/:id/boards/:board_id/lists/:list_id
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer | yes | The ID of a project |
|
`board_id`
| integer | yes | The ID of a board |
|
`list_id`
| integer | yes | The ID of a board's list |
```
bash
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v3/projects/5/boards/1/lists/1
```
Example response:
```
json
{
"id"
:
1
,
"label"
:
{
"name"
:
"Testing"
,
"color"
:
"#F0AD4E"
,
"description"
:
null
},
"position"
:
1
}
```
## New board list
Creates a new Issue Board list.
If the operation is successful, a status code of
`200`
and the newly-created
list is returned. If an error occurs, an error number and a message explaining
the reason is returned.
```
POST /projects/:id/boards/:board_id/lists
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer | yes | The ID of a project |
|
`board_id`
| integer | yes | The ID of a board |
|
`label_id`
| integer | yes | The ID of a label |
```
bash
curl
--request
POST
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v3/projects/5/boards/1/lists?label_id
=
5
```
Example response:
```
json
{
"id"
:
1
,
"label"
:
{
"name"
:
"Testing"
,
"color"
:
"#F0AD4E"
,
"description"
:
null
},
"position"
:
1
}
```
## Edit board list
Updates an existing Issue Board list. This call is used to change list position.
If the operation is successful, a code of
`200`
and the updated board list is
returned. If an error occurs, an error number and a message explaining the
reason is returned.
```
PUT /projects/:id/boards/:board_id/lists/:list_id
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer | yes | The ID of a project |
|
`board_id`
| integer | yes | The ID of a board |
|
`list_id`
| integer | yes | The ID of a board's list |
|
`position`
| integer | yes | The position of the list |
```
bash
curl
--request
PUT
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v3/projects/5/boards/1/lists/1?position
=
2
```
Example response:
```
json
{
"id"
:
1
,
"label"
:
{
"name"
:
"Testing"
,
"color"
:
"#F0AD4E"
,
"description"
:
null
},
"position"
:
1
}
```
## Delete a board list
Only for admins and project owners. Soft deletes the board list in question.
If the operation is successful, a status code
`200`
is returned. In case you cannot
destroy this board list, or it is not present, code
`404`
is given.
```
DELETE /projects/:id/boards/:board_id/lists/:list_id
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer | yes | The ID of a project |
|
`board_id`
| integer | yes | The ID of a board |
|
`list_id`
| integer | yes | The ID of a board's list |
```
bash
curl
--request
DELETE
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v3/projects/5/boards/1/lists/1
```
Example response:
```
json
{
"id"
:
1
,
"label"
:
{
"name"
:
"Testing"
,
"color"
:
"#F0AD4E"
,
"description"
:
null
},
"position"
:
1
}
```
lib/api/api.rb
View file @
41d70ea3
...
...
@@ -43,6 +43,7 @@ module API
mount
::
API
::
Groups
mount
::
API
::
Internal
mount
::
API
::
Issues
mount
::
API
::
Boards
mount
::
API
::
Keys
mount
::
API
::
Labels
mount
::
API
::
LicenseTemplates
...
...
lib/api/boards.rb
0 → 100644
View file @
41d70ea3
module
API
# Boards API
class
Boards
<
Grape
::
API
before
{
authenticate!
}
resource
:projects
do
# Get the project board
get
':id/boards'
do
authorize!
(
:read_board
,
user_project
)
present
[
user_project
.
board
],
with:
Entities
::
Board
end
segment
':id/boards/:board_id'
do
helpers
do
def
project_board
board
=
user_project
.
board
if
params
[
:board_id
].
to_i
==
board
.
id
board
else
not_found!
(
'Board'
)
end
end
def
board_lists
project_board
.
lists
.
destroyable
end
end
# Get the lists of a project board
# Does not include `backlog` and `done` lists
get
'/lists'
do
authorize!
(
:read_board
,
user_project
)
present
board_lists
,
with:
Entities
::
List
end
# Get a list of a project board
get
'/lists/:list_id'
do
authorize!
(
:read_board
,
user_project
)
present
board_lists
.
find
(
params
[
:list_id
]),
with:
Entities
::
List
end
# Create a new board list
#
# Parameters:
# id (required) - The ID of a project
# label_id (required) - The ID of an existing label
# Example Request:
# POST /projects/:id/boards/:board_id/lists
post
'/lists'
do
required_attributes!
[
:label_id
]
unless
user_project
.
labels
.
exists?
(
params
[
:label_id
])
render_api_error!
({
error:
"Label not found!"
},
400
)
end
authorize!
(
:admin_list
,
user_project
)
list
=
::
Boards
::
Lists
::
CreateService
.
new
(
user_project
,
current_user
,
{
label_id:
params
[
:label_id
]
}).
execute
if
list
.
valid?
present
list
,
with:
Entities
::
List
else
render_validation_error!
(
list
)
end
end
# Moves a board list to a new position
#
# Parameters:
# id (required) - The ID of a project
# board_id (required) - The ID of a board
# position (required) - The position of the list
# Example Request:
# PUT /projects/:id/boards/:board_id/lists/:list_id
put
'/lists/:list_id'
do
list
=
project_board
.
lists
.
movable
.
find
(
params
[
:list_id
])
authorize!
(
:admin_list
,
user_project
)
moved
=
::
Boards
::
Lists
::
MoveService
.
new
(
user_project
,
current_user
,
{
position:
params
[
:position
].
to_i
}).
execute
(
list
)
if
moved
present
list
,
with:
Entities
::
List
else
render_api_error!
({
error:
"List could not be moved!"
},
400
)
end
end
# Delete a board list
#
# Parameters:
# id (required) - The ID of a project
# board_id (required) - The ID of a board
# list_id (required) - The ID of a board list
# Example Request:
# DELETE /projects/:id/boards/:board_id/lists/:list_id
delete
"/lists/:list_id"
do
list
=
board_lists
.
find_by
(
id:
params
[
:list_id
])
authorize!
(
:admin_list
,
user_project
)
if
list
destroyed_list
=
::
Boards
::
Lists
::
DestroyService
.
new
(
user_project
,
current_user
).
execute
(
list
)
present
destroyed_list
,
with:
Entities
::
List
else
not_found!
(
'List'
)
end
end
end
end
end
end
lib/api/entities.rb
View file @
41d70ea3
...
...
@@ -432,8 +432,11 @@ module API
end
end
class
Label
<
Grape
::
Entity
class
Label
Basic
<
Grape
::
Entity
expose
:name
,
:color
,
:description
end
class
Label
<
LabelBasic
expose
:open_issues_count
,
:closed_issues_count
,
:open_merge_requests_count
expose
:subscribed
do
|
label
,
options
|
...
...
@@ -441,6 +444,19 @@ module API
end
end
class
List
<
Grape
::
Entity
expose
:id
expose
:label
,
using:
Entities
::
LabelBasic
expose
:position
end
class
Board
<
Grape
::
Entity
expose
:id
expose
:lists
,
using:
Entities
::
List
do
|
board
|
board
.
lists
.
destroyable
end
end
class
Compare
<
Grape
::
Entity
expose
:commit
,
using:
Entities
::
RepoCommit
do
|
compare
,
options
|
Commit
.
decorate
(
compare
.
commits
,
nil
).
last
...
...
spec/requests/api/boards_spec.rb
0 → 100644
View file @
41d70ea3
require
'spec_helper'
describe
API
::
API
,
api:
true
do
include
ApiHelpers
let
(
:user
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:non_member
)
{
create
(
:user
)
}
let
(
:guest
)
{
create
(
:user
)
}
let
(
:admin
)
{
create
(
:user
,
:admin
)
}
let!
(
:project
)
{
create
(
:project
,
:public
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let!
(
:dev_label
)
do
create
(
:label
,
title:
'Development'
,
color:
'#FFAABB'
,
project:
project
)
end
let!
(
:test_label
)
do
create
(
:label
,
title:
'Testing'
,
color:
'#FFAACC'
,
project:
project
)
end
let!
(
:ux_label
)
do
create
(
:label
,
title:
'UX'
,
color:
'#FF0000'
,
project:
project
)
end
let!
(
:dev_list
)
do
create
(
:list
,
label:
dev_label
,
position:
1
)
end
let!
(
:test_list
)
do
create
(
:list
,
label:
test_label
,
position:
2
)
end
let!
(
:board
)
do
create
(
:board
,
project:
project
,
lists:
[
dev_list
,
test_list
])
end
before
do
project
.
team
<<
[
user
,
:reporter
]
project
.
team
<<
[
guest
,
:guest
]
end
describe
"GET /projects/:id/boards"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
/boards"
}
context
"when unauthenticated"
do
it
"returns authentication error"
do
get
api
(
base_url
)
expect
(
response
).
to
have_http_status
(
401
)
end
end
context
"when authenticated"
do
it
"returns the project issue board"
do
get
api
(
base_url
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
1
)
expect
(
json_response
.
first
[
'id'
]).
to
eq
(
board
.
id
)
expect
(
json_response
.
first
[
'lists'
]).
to
be_an
Array
expect
(
json_response
.
first
[
'lists'
].
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'lists'
].
last
).
to
have_key
(
'position'
)
end
end
end
describe
"GET /projects/:id/boards/:board_id/lists"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
/boards/
#{
board
.
id
}
/lists"
}
it
'returns issue board lists'
do
get
api
(
base_url
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
length
).
to
eq
(
2
)
expect
(
json_response
.
first
[
'label'
][
'name'
]).
to
eq
(
dev_label
.
title
)
end
it
'returns 404 if board not found'
do
get
api
(
"/projects/
#{
project
.
id
}
/boards/22343/lists"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
"GET /projects/:id/boards/:board_id/lists/:list_id"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
/boards/
#{
board
.
id
}
/lists"
}
it
'returns a list'
do
get
api
(
"
#{
base_url
}
/
#{
dev_list
.
id
}
"
,
user
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'id'
]).
to
eq
(
dev_list
.
id
)
expect
(
json_response
[
'label'
][
'name'
]).
to
eq
(
dev_label
.
title
)
expect
(
json_response
[
'position'
]).
to
eq
(
1
)
end
it
'returns 404 if list not found'
do
get
api
(
"
#{
base_url
}
/5324"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
end
describe
"POST /projects/:id/board/lists"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
/boards/
#{
board
.
id
}
/lists"
}
it
'creates a new issue board list'
do
post
api
(
base_url
,
user
),
label_id:
ux_label
.
id
expect
(
response
).
to
have_http_status
(
201
)
expect
(
json_response
[
'label'
][
'name'
]).
to
eq
(
ux_label
.
title
)
expect
(
json_response
[
'position'
]).
to
eq
(
3
)
end
it
'returns 400 when creating a new list if label_id is invalid'
do
post
api
(
base_url
,
user
),
label_id:
23423
expect
(
response
).
to
have_http_status
(
400
)
end
it
"returns 403 for project members with guest role"
do
put
api
(
"
#{
base_url
}
/
#{
test_list
.
id
}
"
,
guest
),
position:
1
expect
(
response
).
to
have_http_status
(
403
)
end
end
describe
"PUT /projects/:id/boards/:board_id/lists/:list_id to update only position"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
/boards/
#{
board
.
id
}
/lists"
}
it
"updates a list"
do
put
api
(
"
#{
base_url
}
/
#{
test_list
.
id
}
"
,
user
),
position:
1
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'position'
]).
to
eq
(
1
)
end
it
"returns 404 error if list id not found"
do
put
api
(
"
#{
base_url
}
/44444"
,
user
),
position:
1
expect
(
response
).
to
have_http_status
(
404
)
end
it
"returns 403 for project members with guest role"
do
put
api
(
"
#{
base_url
}
/
#{
test_list
.
id
}
"
,
guest
),
position:
1
expect
(
response
).
to
have_http_status
(
403
)
end
end
describe
"DELETE /projects/:id/board/lists/:list_id"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
/boards/
#{
board
.
id
}
/lists"
}
it
"rejects a non member from deleting a list"
do
delete
api
(
"
#{
base_url
}
/
#{
dev_list
.
id
}
"
,
non_member
)
expect
(
response
).
to
have_http_status
(
403
)
end
it
"rejects a user with guest role from deleting a list"
do
delete
api
(
"
#{
base_url
}
/
#{
dev_list
.
id
}
"
,
guest
)
expect
(
response
).
to
have_http_status
(
403
)
end
it
"returns 404 error if list id not found"
do
delete
api
(
"
#{
base_url
}
/44444"
,
user
)
expect
(
response
).
to
have_http_status
(
404
)
end
context
"when the user is project owner"
do
let
(
:owner
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:project
,
namespace:
owner
.
namespace
)
}
it
"deletes the list if an admin requests it"
do
delete
api
(
"
#{
base_url
}
/
#{
dev_list
.
id
}
"
,
owner
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'position'
]).
to
eq
(
1
)
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment