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
5e148d4e
Commit
5e148d4e
authored
Dec 06, 2017
by
Felipe Artur
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
EE-BACKPORT group boards
parent
e5a9b9a1
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
601 additions
and
248 deletions
+601
-248
app/finders/labels_finder.rb
app/finders/labels_finder.rb
+17
-2
app/policies/group_policy.rb
app/policies/group_policy.rb
+7
-1
doc/api/boards.md
doc/api/boards.md
+183
-17
lib/api/api.rb
lib/api/api.rb
+2
-2
lib/api/boards.rb
lib/api/boards.rb
+32
-52
lib/api/boards_responses.rb
lib/api/boards_responses.rb
+50
-0
lib/api/entities.rb
lib/api/entities.rb
+2
-0
lib/api/helpers.rb
lib/api/helpers.rb
+12
-3
lib/api/labels.rb
lib/api/labels.rb
+2
-2
lib/api/v3/labels.rb
lib/api/v3/labels.rb
+1
-1
spec/finders/labels_finder_spec.rb
spec/finders/labels_finder_spec.rb
+10
-0
spec/fixtures/api/schemas/public_api/v4/board.json
spec/fixtures/api/schemas/public_api/v4/board.json
+86
-0
spec/fixtures/api/schemas/public_api/v4/boards.json
spec/fixtures/api/schemas/public_api/v4/boards.json
+4
-0
spec/fixtures/api/schemas/public_api/v4/user/basic.json
spec/fixtures/api/schemas/public_api/v4/user/basic.json
+1
-1
spec/requests/api/boards_spec.rb
spec/requests/api/boards_spec.rb
+12
-167
spec/support/api/boards_shared_examples.rb
spec/support/api/boards_shared_examples.rb
+180
-0
No files found.
app/finders/labels_finder.rb
View file @
5e148d4e
class
LabelsFinder
<
UnionFinder
include
Gitlab
::
Utils
::
StrongMemoize
def
initialize
(
current_user
,
params
=
{})
@current_user
=
current_user
@params
=
params
...
...
@@ -32,6 +34,8 @@ class LabelsFinder < UnionFinder
label_ids
<<
project
.
labels
end
end
elsif
only_group_labels?
label_ids
<<
Label
.
where
(
group_id:
group
.
id
)
else
label_ids
<<
Label
.
where
(
group_id:
projects
.
group_ids
)
label_ids
<<
Label
.
where
(
project_id:
projects
.
select
(
:id
))
...
...
@@ -51,6 +55,13 @@ class LabelsFinder < UnionFinder
items
.
where
(
title:
title
)
end
def
group
strong_memoize
(
:group
)
do
group
=
Group
.
find
(
params
[
:group_id
])
authorized_to_read_labels?
(
group
)
&&
group
end
end
def
group?
params
[
:group_id
].
present?
end
...
...
@@ -63,6 +74,10 @@ class LabelsFinder < UnionFinder
params
[
:project_ids
].
present?
end
def
only_group_labels?
params
[
:only_group_labels
]
end
def
title
params
[
:title
]
||
params
[
:name
]
end
...
...
@@ -96,9 +111,9 @@ class LabelsFinder < UnionFinder
@projects
end
def
authorized_to_read_labels?
(
projec
t
)
def
authorized_to_read_labels?
(
label_paren
t
)
return
true
if
skip_authorization
Ability
.
allowed?
(
current_user
,
:read_label
,
projec
t
)
Ability
.
allowed?
(
current_user
,
:read_label
,
label_paren
t
)
end
end
app/policies/group_policy.rb
View file @
5e148d4e
...
...
@@ -28,12 +28,18 @@ class GroupPolicy < BasePolicy
with_options
scope: :subject
,
score:
0
condition
(
:request_access_enabled
)
{
@subject
.
request_access_enabled
}
rule
{
public_group
}
.
enable
:read_group
rule
{
public_group
}.
policy
do
enable
:read_group
enable
:read_list
enable
:read_label
end
rule
{
logged_in_viewable
}.
enable
:read_group
rule
{
guest
}.
policy
do
enable
:read_group
enable
:upload_file
enable
:read_label
end
rule
{
admin
}
.
enable
:read_group
...
...
doc/api/boards.md
View file @
5e148d4e
...
...
@@ -15,10 +15,10 @@ GET /projects/:id/boards
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes
| The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`id`
| integer/string | yes
| The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
```
bash
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v4/projects/
:id
/boards
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v4/projects/
5
/boards
```
Example response:
...
...
@@ -27,6 +27,19 @@ Example response:
[
{
"id"
:
1
,
"project"
:
{
"id"
:
5
,
"name"
:
"Diaspora Project Site"
,
"name_with_namespace"
:
"Diaspora / Diaspora Project Site"
,
"path"
:
"diaspora-project-site"
,
"path_with_namespace"
:
"diaspora/diaspora-project-site"
,
"http_url_to_repo"
:
"http://example.com/diaspora/diaspora-project-site.git"
,
"web_url"
:
"http://example.com/diaspora/diaspora-project-site"
},
"milestone"
:
{
"id"
:
12
"title"
:
"10.0"
},
"lists"
:
[
{
"id"
:
1
,
...
...
@@ -60,6 +73,159 @@ Example response:
]
```
## Single board
Get a single board.
```
GET /projects/:id/boards/:board_id
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`board_id`
| integer | yes | The ID of a board |
```
bash
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v4/projects/5/boards/1
```
Example response:
```
json
{
"id"
:
1
,
"name:"
:
"project issue board"
,
"project"
:
{
"id"
:
5
,
"name"
:
"Diaspora Project Site"
,
"name_with_namespace"
:
"Diaspora / Diaspora Project Site"
,
"path"
:
"diaspora-project-site"
,
"path_with_namespace"
:
"diaspora/diaspora-project-site"
,
"http_url_to_repo"
:
"http://example.com/diaspora/diaspora-project-site.git"
,
"web_url"
:
"http://example.com/diaspora/diaspora-project-site"
},
"milestone"
:
{
"id"
:
12
"title"
:
"10.0"
},
"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
}
]
}
```
## Create a board (EES-Only)
Creates a board.
```
POST /projects/:id/boards
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`name`
| string | yes | The name of the new board |
```
bash
curl
--request
POST
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v4/projects/5/boards?name
=
newboard
```
Example response:
```
json
{
"id"
:
1
,
"project"
:
{
"id"
:
5
,
"name"
:
"Diaspora Project Site"
,
"name_with_namespace"
:
"Diaspora / Diaspora Project Site"
,
"path"
:
"diaspora-project-site"
,
"path_with_namespace"
:
"diaspora/diaspora-project-site"
,
"http_url_to_repo"
:
"http://example.com/diaspora/diaspora-project-site.git"
,
"web_url"
:
"http://example.com/diaspora/diaspora-project-site"
},
"name"
:
"newboard"
,
"milestone"
:
{
"id"
:
12
"title"
:
"10.0"
},
"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
}
]
}
```
## Delete a board (EES-Only)
Deletes a board.
```
DELETE /projects/:id/boards/:board_id
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`board_id`
| integer | yes | The ID of a board |
```
bash
curl
--request
DELETE
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v4/projects/5/boards/1
```
## List board lists
Get a list of the board's lists.
...
...
@@ -71,8 +237,8 @@ GET /projects/:id/boards/:board_id/lists
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes
| The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`board_id`
| integer | yes
| The ID of a board |
|
`id`
| integer/string | yes
| The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`board_id`
| integer | yes
| The ID of a board |
```
bash
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v4/projects/5/boards/1/lists
...
...
@@ -122,9 +288,9 @@ GET /projects/:id/boards/:board_id/lists/:list_id
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes
| The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`board_id`
| integer | yes
| The ID of a board |
|
`list_id`
| integer | yes
| The ID of a board's list |
|
`id`
| integer/string | yes
| The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`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/v4/projects/5/boards/1/lists/1
...
...
@@ -154,9 +320,9 @@ POST /projects/:id/boards/:board_id/lists
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`board_id`
| integer | yes
| The ID of a board |
|
`label_id`
| integer
| yes | The ID of a label |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`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/v4/projects/5/boards/1/lists?label_id
=
5
...
...
@@ -186,10 +352,10 @@ PUT /projects/:id/boards/:board_id/lists/:list_id
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`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 |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`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/v4/projects/5/boards/1/lists/1?position
=
2
...
...
@@ -219,9 +385,9 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`board_id`
| integer | yes
| The ID of a board |
|
`list_id`
| integer | yes | The ID of a board's list |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`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/v4/projects/5/boards/1/lists/1
...
...
lib/api/api.rb
View file @
5e148d4e
...
...
@@ -119,6 +119,7 @@ module API
mount
::
API
::
Features
mount
::
API
::
Files
mount
::
API
::
Groups
mount
::
API
::
GroupMilestones
mount
::
API
::
Internal
mount
::
API
::
Issues
mount
::
API
::
Jobs
...
...
@@ -129,8 +130,6 @@ module API
mount
::
API
::
Members
mount
::
API
::
MergeRequestDiffs
mount
::
API
::
MergeRequests
mount
::
API
::
ProjectMilestones
mount
::
API
::
GroupMilestones
mount
::
API
::
Namespaces
mount
::
API
::
Notes
mount
::
API
::
NotificationSettings
...
...
@@ -139,6 +138,7 @@ module API
mount
::
API
::
PipelineSchedules
mount
::
API
::
ProjectHooks
mount
::
API
::
Projects
mount
::
API
::
ProjectMilestones
mount
::
API
::
ProjectSnippets
mount
::
API
::
ProtectedBranches
mount
::
API
::
Repositories
...
...
lib/api/boards.rb
View file @
5e148d4e
module
API
class
Boards
<
Grape
::
API
include
BoardsResponses
include
PaginationParams
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
::
PROJECT_ENDPOINT_REQUIREMENTS
do
desc
'Get all project boards'
do
detail
'This feature was introduced in 8.13'
success
Entities
::
Board
end
params
do
use
:pagination
end
get
':id/boards'
do
authorize!
(
:read_board
,
user_project
)
present
paginate
(
user_project
.
boards
),
with:
Entities
::
Board
segment
':id/boards'
do
desc
'Get all project boards'
do
detail
'This feature was introduced in 8.13'
success
Entities
::
Board
end
params
do
use
:pagination
end
get
'/'
do
authorize!
(
:read_board
,
user_project
)
present
paginate
(
board_parent
.
boards
),
with:
Entities
::
Board
end
desc
'Find a project board'
do
detail
'This feature was introduced in 10.4'
success
Entities
::
Board
end
get
'/:board_id'
do
present
board
,
with:
Entities
::
Board
end
end
params
do
requires
:board_id
,
type:
Integer
,
desc:
'The ID of a board'
end
segment
':id/boards/:board_id'
do
helpers
do
def
project_board
board
=
user_project
.
boards
.
first
if
params
[
:board_id
]
==
board
.
id
board
else
not_found!
(
'Board'
)
end
end
def
board_lists
project_board
.
lists
.
destroyable
end
end
desc
'Get the lists of a project board'
do
detail
'Does not include `done` list. This feature was introduced in 8.13'
success
Entities
::
List
...
...
@@ -72,22 +73,13 @@ module API
requires
:label_id
,
type:
Integer
,
desc:
'The ID of an existing label'
end
post
'/lists'
do
unless
available_labels
.
exists?
(
params
[
:label_id
])
unless
available_labels
_for
(
user_project
)
.
exists?
(
params
[
:label_id
])
render_api_error!
({
error:
'Label not found!'
},
400
)
end
authorize!
(
:admin_list
,
user_project
)
service
=
::
Boards
::
Lists
::
CreateService
.
new
(
user_project
,
current_user
,
{
label_id:
params
[
:label_id
]
})
list
=
service
.
execute
(
project_board
)
if
list
.
valid?
present
list
,
with:
Entities
::
List
else
render_validation_error!
(
list
)
end
create_list
end
desc
'Moves a board list to a new position'
do
...
...
@@ -99,18 +91,11 @@ module API
requires
:position
,
type:
Integer
,
desc:
'The position of the list'
end
put
'/lists/:list_id'
do
list
=
project_board
.
lists
.
movable
.
find
(
params
[
:list_id
])
list
=
board_lists
.
find
(
params
[
:list_id
])
authorize!
(
:admin_list
,
user_project
)
service
=
::
Boards
::
Lists
::
MoveService
.
new
(
user_project
,
current_user
,
{
position:
params
[
:position
]
})
if
service
.
execute
(
list
)
present
list
,
with:
Entities
::
List
else
render_api_error!
({
error:
"List could not be moved!"
},
400
)
end
move_list
(
list
)
end
desc
'Delete a board list'
do
...
...
@@ -124,12 +109,7 @@ module API
authorize!
(
:admin_list
,
user_project
)
list
=
board_lists
.
find
(
params
[
:list_id
])
destroy_conditionally!
(
list
)
do
|
list
|
service
=
::
Boards
::
Lists
::
DestroyService
.
new
(
user_project
,
current_user
)
unless
service
.
execute
(
list
)
render_api_error!
({
error:
'List could not be deleted!'
},
400
)
end
end
destroy_list
(
list
)
end
end
end
...
...
lib/api/boards_responses.rb
0 → 100644
View file @
5e148d4e
module
API
module
BoardsResponses
extend
ActiveSupport
::
Concern
included
do
helpers
do
def
board
board_parent
.
boards
.
find
(
params
[
:board_id
])
end
def
board_lists
board
.
lists
.
destroyable
end
def
create_list
create_list_service
=
::
Boards
::
Lists
::
CreateService
.
new
(
board_parent
,
current_user
,
{
label_id:
params
[
:label_id
]
})
list
=
create_list_service
.
execute
(
board
)
if
list
.
valid?
present
list
,
with:
Entities
::
List
else
render_validation_error!
(
list
)
end
end
def
move_list
(
list
)
move_list_service
=
::
Boards
::
Lists
::
MoveService
.
new
(
board_parent
,
current_user
,
{
position:
params
[
:position
].
to_i
})
if
move_list_service
.
execute
(
list
)
present
list
,
with:
Entities
::
List
else
render_api_error!
({
error:
"List could not be moved!"
},
400
)
end
end
def
destroy_list
(
list
)
destroy_conditionally!
(
list
)
do
|
list
|
service
=
::
Boards
::
Lists
::
DestroyService
.
new
(
board_parent
,
current_user
)
unless
service
.
execute
(
list
)
render_api_error!
({
error:
'List could not be deleted!'
},
400
)
end
end
end
end
end
end
end
lib/api/entities.rb
View file @
5e148d4e
...
...
@@ -791,6 +791,8 @@ module API
class
Board
<
Grape
::
Entity
expose
:id
expose
:project
,
using:
Entities
::
BasicProjectDetails
expose
:lists
,
using:
Entities
::
List
do
|
board
|
board
.
lists
.
destroyable
end
...
...
lib/api/helpers.rb
View file @
5e148d4e
...
...
@@ -74,8 +74,15 @@ module API
page
||
not_found!
(
'Wiki Page'
)
end
def
available_labels
@available_labels
||=
LabelsFinder
.
new
(
current_user
,
project_id:
user_project
.
id
).
execute
def
available_labels_for
(
label_parent
)
search_params
=
if
label_parent
.
is_a?
(
Project
)
{
project_id:
label_parent
.
id
}
else
{
group_id:
label_parent
.
id
,
only_group_labels:
true
}
end
LabelsFinder
.
new
(
current_user
,
search_params
).
execute
end
def
find_user
(
id
)
...
...
@@ -141,7 +148,9 @@ module API
end
def
find_project_label
(
id
)
label
=
available_labels
.
find_by_id
(
id
)
||
available_labels
.
find_by_title
(
id
)
labels
=
available_labels_for
(
user_project
)
label
=
labels
.
find_by_id
(
id
)
||
labels
.
find_by_title
(
id
)
label
||
not_found!
(
'Label'
)
end
...
...
lib/api/labels.rb
View file @
5e148d4e
...
...
@@ -15,7 +15,7 @@ module API
use
:pagination
end
get
':id/labels'
do
present
paginate
(
available_labels
),
with:
Entities
::
Label
,
current_user:
current_user
,
project:
user_project
present
paginate
(
available_labels
_for
(
user_project
)
),
with:
Entities
::
Label
,
current_user:
current_user
,
project:
user_project
end
desc
'Create a new label'
do
...
...
@@ -30,7 +30,7 @@ module API
post
':id/labels'
do
authorize!
:admin_label
,
user_project
label
=
available_labels
.
find_by
(
title:
params
[
:name
])
label
=
available_labels
_for
(
user_project
)
.
find_by
(
title:
params
[
:name
])
conflict!
(
'Label already exists'
)
if
label
priority
=
params
.
delete
(
:priority
)
...
...
lib/api/v3/labels.rb
View file @
5e148d4e
...
...
@@ -11,7 +11,7 @@ module API
success
::
API
::
Entities
::
Label
end
get
':id/labels'
do
present
available_labels
,
with:
::
API
::
Entities
::
Label
,
current_user:
current_user
,
project:
user_project
present
available_labels
_for
(
user_project
)
,
with:
::
API
::
Entities
::
Label
,
current_user:
current_user
,
project:
user_project
end
desc
'Delete an existing label'
do
...
...
spec/finders/labels_finder_spec.rb
View file @
5e148d4e
...
...
@@ -56,6 +56,16 @@ describe LabelsFinder do
expect
(
finder
.
execute
).
to
eq
[
group_label_2
,
group_label_1
,
project_label_5
]
end
context
'when only_group_labels is true'
do
it
'returns only group labels'
do
group_1
.
add_developer
(
user
)
finder
=
described_class
.
new
(
user
,
group_id:
group_1
.
id
,
only_group_labels:
true
)
expect
(
finder
.
execute
).
to
eq
[
group_label_2
,
group_label_1
]
end
end
end
context
'filtering by project_id'
do
...
...
spec/fixtures/api/schemas/public_api/v4/board.json
0 → 100644
View file @
5e148d4e
{
"type"
:
"object"
,
"required"
:
[
"id"
,
"project"
,
"lists"
],
"properties"
:
{
"id"
:
{
"type"
:
"integer"
},
"project"
:
{
"type"
:
[
"object"
,
"null"
],
"required"
:
[
"id"
,
"avatar_url"
,
"description"
,
"default_branch"
,
"tag_list"
,
"ssh_url_to_repo"
,
"http_url_to_repo"
,
"web_url"
,
"name"
,
"name_with_namespace"
,
"path"
,
"path_with_namespace"
,
"star_count"
,
"forks_count"
,
"created_at"
,
"last_activity_at"
],
"properties"
:
{
"id"
:
{
"type"
:
"integer"
},
"avatar_url"
:
{
"type"
:
[
"string"
,
"null"
]
},
"description"
:
{
"type"
:
[
"string"
,
"null"
]
},
"default_branch"
:
{
"type"
:
[
"string"
,
"null"
]
},
"tag_list"
:
{
"type"
:
"array"
},
"ssh_url_to_repo"
:
{
"type"
:
"string"
},
"http_url_to_repo"
:
{
"type"
:
"string"
},
"web_url"
:
{
"type"
:
"string"
},
"name"
:
{
"type"
:
"string"
},
"name_with_namespace"
:
{
"type"
:
"string"
},
"path"
:
{
"type"
:
"string"
},
"path_with_namespace"
:
{
"type"
:
"string"
},
"star_count"
:
{
"type"
:
"integer"
},
"forks_count"
:
{
"type"
:
"integer"
},
"created_at"
:
{
"type"
:
"date"
},
"last_activity_at"
:
{
"type"
:
"date"
}
},
"additionalProperties"
:
false
},
"lists"
:
{
"type"
:
"array"
,
"items"
:
{
"type"
:
"object"
,
"required"
:
[
"id"
,
"label"
,
"position"
],
"properties"
:
{
"id"
:
{
"type"
:
"integer"
},
"label"
:
{
"type"
:
[
"object"
,
"null"
],
"required"
:
[
"id"
,
"color"
,
"description"
,
"name"
],
"properties"
:
{
"id"
:
{
"type"
:
"integer"
},
"color"
:
{
"type"
:
"string"
,
"pattern"
:
"^#[0-9A-Fa-f]{3}{1,2}+$"
},
"description"
:
{
"type"
:
[
"string"
,
"null"
]
},
"name"
:
{
"type"
:
"string"
}
}
},
"position"
:
{
"type"
:
[
"integer"
,
"null"
]
}
},
"additionalProperties"
:
false
}
}
},
"additionalProperties"
:
true
}
spec/fixtures/api/schemas/public_api/v4/boards.json
0 → 100644
View file @
5e148d4e
{
"type"
:
"array"
,
"items"
:
{
"$ref"
:
"board.json"
}
}
spec/fixtures/api/schemas/public_api/v4/user/basic.json
View file @
5e148d4e
{
"type"
:
"object"
,
"type"
:
[
"object"
,
"null"
]
,
"required"
:
[
"id"
,
"state"
,
...
...
spec/requests/api/boards_spec.rb
View file @
5e148d4e
...
...
@@ -6,18 +6,18 @@ describe API::Boards do
set
(
:non_member
)
{
create
(
:user
)
}
set
(
:guest
)
{
create
(
:user
)
}
set
(
:admin
)
{
create
(
:user
,
:admin
)
}
set
(
:
project
)
{
create
(
:project
,
:public
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
set
(
:
board_parent
)
{
create
(
:project
,
:public
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
set
(
:dev_label
)
do
create
(
:label
,
title:
'Development'
,
color:
'#FFAABB'
,
project:
projec
t
)
create
(
:label
,
title:
'Development'
,
color:
'#FFAABB'
,
project:
board_paren
t
)
end
set
(
:test_label
)
do
create
(
:label
,
title:
'Testing'
,
color:
'#FFAACC'
,
project:
projec
t
)
create
(
:label
,
title:
'Testing'
,
color:
'#FFAACC'
,
project:
board_paren
t
)
end
set
(
:ux_label
)
do
create
(
:label
,
title:
'UX'
,
color:
'#FF0000'
,
project:
projec
t
)
create
(
:label
,
title:
'UX'
,
color:
'#FF0000'
,
project:
board_paren
t
)
end
set
(
:dev_list
)
do
...
...
@@ -28,180 +28,25 @@ describe API::Boards do
create
(
:list
,
label:
test_label
,
position:
2
)
end
set
(
:board
)
do
create
(
:board
,
project:
project
,
lists:
[
dev_list
,
test_list
])
end
before
do
project
.
add_reporter
(
user
)
project
.
add_guest
(
guest
)
end
set
(
:milestone
)
{
create
(
:milestone
,
project:
board_parent
)
}
set
(
:board_label
)
{
create
(
:label
,
project:
board_parent
)
}
set
(
:board
)
{
create
(
:board
,
project:
board_parent
,
lists:
[
dev_list
,
test_list
])
}
describe
"GET /projects/:id/boards"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
/boards"
}
it_behaves_like
'group and project boards'
,
"/projects/:id/boards"
context
"when unauthenticated"
do
it
"returns authentication error"
do
get
api
(
base_url
)
expect
(
response
).
to
have_gitlab_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_gitlab_http_status
(
200
)
expect
(
response
).
to
include_pagination_headers
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_gitlab_http_status
(
200
)
expect
(
response
).
to
include_pagination_headers
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_gitlab_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_gitlab_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_gitlab_http_status
(
404
)
end
end
describe
"POST /projects/:id/board/lists"
do
let
(
:base_url
)
{
"/projects/
#{
project
.
id
}
/boards/
#{
board
.
id
}
/lists"
}
describe
"POST /projects/:id/boards/lists"
do
let
(
:url
)
{
"/projects/
#{
board_parent
.
id
}
/boards/
#{
board
.
id
}
/lists"
}
it
'creates a new issue board list for group labels'
do
group
=
create
(
:group
)
group_label
=
create
(
:group_label
,
group:
group
)
projec
t
.
update
(
group:
group
)
board_paren
t
.
update
(
group:
group
)
post
api
(
base_
url
,
user
),
label_id:
group_label
.
id
post
api
(
url
,
user
),
label_id:
group_label
.
id
expect
(
response
).
to
have_gitlab_http_status
(
201
)
expect
(
json_response
[
'label'
][
'name'
]).
to
eq
(
group_label
.
title
)
expect
(
json_response
[
'position'
]).
to
eq
(
3
)
end
it
'creates a new issue board list for project labels'
do
post
api
(
base_url
,
user
),
label_id:
ux_label
.
id
expect
(
response
).
to
have_gitlab_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_gitlab_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_gitlab_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_gitlab_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_gitlab_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_gitlab_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_gitlab_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_gitlab_http_status
(
403
)
end
it
"returns 404 error if list id not found"
do
delete
api
(
"
#{
base_url
}
/44444"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
context
"when the user is project owner"
do
set
(
:owner
)
{
create
(
:user
)
}
before
do
project
.
update
(
namespace:
owner
.
namespace
)
end
it
"deletes the list if an admin requests it"
do
delete
api
(
"
#{
base_url
}
/
#{
dev_list
.
id
}
"
,
owner
)
expect
(
response
).
to
have_gitlab_http_status
(
204
)
end
it_behaves_like
'412 response'
do
let
(
:request
)
{
api
(
"
#{
base_url
}
/
#{
dev_list
.
id
}
"
,
owner
)
}
end
end
end
end
spec/support/api/boards_shared_examples.rb
0 → 100644
View file @
5e148d4e
shared_examples_for
'group and project boards'
do
|
route_definition
,
ee
=
false
|
let
(
:root_url
)
{
route_definition
.
gsub
(
":id"
,
board_parent
.
id
.
to_s
)
}
before
do
board_parent
.
add_reporter
(
user
)
board_parent
.
add_guest
(
guest
)
end
def
expect_schema_match_for
(
response
,
schema_file
,
ee
)
if
ee
expect
(
response
).
to
match_response_schema
(
schema_file
,
dir:
"ee"
)
else
expect
(
response
).
to
match_response_schema
(
schema_file
)
end
end
describe
"GET
#{
route_definition
}
"
do
context
"when unauthenticated"
do
it
"returns authentication error"
do
get
api
(
root_url
)
expect
(
response
).
to
have_gitlab_http_status
(
401
)
end
end
context
"when authenticated"
do
it
"returns the issue boards"
do
get
api
(
root_url
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
include_pagination_headers
expect_schema_match_for
(
response
,
'public_api/v4/boards'
,
ee
)
end
describe
"GET
#{
route_definition
}
/:board_id"
do
let
(
:url
)
{
"
#{
root_url
}
/
#{
board
.
id
}
"
}
it
'get a single board by id'
do
get
api
(
url
,
user
)
expect_schema_match_for
(
response
,
'public_api/v4/board'
,
ee
)
end
end
end
end
describe
"GET
#{
route_definition
}
/:board_id/lists"
do
let
(
:url
)
{
"
#{
root_url
}
/
#{
board
.
id
}
/lists"
}
it
'returns issue board lists'
do
get
api
(
url
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
include_pagination_headers
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
(
"
#{
root_url
}
/22343/lists"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
end
describe
"GET
#{
route_definition
}
/:board_id/lists/:list_id"
do
let
(
:url
)
{
"
#{
root_url
}
/
#{
board
.
id
}
/lists"
}
it
'returns a list'
do
get
api
(
"
#{
url
}
/
#{
dev_list
.
id
}
"
,
user
)
expect
(
response
).
to
have_gitlab_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
(
"
#{
url
}
/5324"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
end
describe
"POST
#{
route_definition
}
/lists"
do
let
(
:url
)
{
"
#{
root_url
}
/
#{
board
.
id
}
/lists"
}
it
'creates a new issue board list for labels'
do
post
api
(
url
,
user
),
label_id:
ux_label
.
id
expect
(
response
).
to
have_gitlab_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
(
url
,
user
),
label_id:
23423
expect
(
response
).
to
have_gitlab_http_status
(
400
)
end
it
'returns 403 for members with guest role'
do
put
api
(
"
#{
url
}
/
#{
test_list
.
id
}
"
,
guest
),
position:
1
expect
(
response
).
to
have_gitlab_http_status
(
403
)
end
end
describe
"PUT
#{
route_definition
}
/:board_id/lists/:list_id to update only position"
do
let
(
:url
)
{
"
#{
root_url
}
/
#{
board
.
id
}
/lists"
}
it
"updates a list"
do
put
api
(
"
#{
url
}
/
#{
test_list
.
id
}
"
,
user
),
position:
1
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
[
'position'
]).
to
eq
(
1
)
end
it
"returns 404 error if list id not found"
do
put
api
(
"
#{
url
}
/44444"
,
user
),
position:
1
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
it
"returns 403 for members with guest role"
do
put
api
(
"
#{
url
}
/
#{
test_list
.
id
}
"
,
guest
),
position:
1
expect
(
response
).
to
have_gitlab_http_status
(
403
)
end
end
describe
"DELETE
#{
route_definition
}
/lists/:list_id"
do
let
(
:url
)
{
"
#{
root_url
}
/
#{
board
.
id
}
/lists"
}
it
"rejects a non member from deleting a list"
do
delete
api
(
"
#{
url
}
/
#{
dev_list
.
id
}
"
,
non_member
)
expect
(
response
).
to
have_gitlab_http_status
(
403
)
end
it
"rejects a user with guest role from deleting a list"
do
delete
api
(
"
#{
url
}
/
#{
dev_list
.
id
}
"
,
guest
)
expect
(
response
).
to
have_gitlab_http_status
(
403
)
end
it
"returns 404 error if list id not found"
do
delete
api
(
"
#{
url
}
/44444"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
context
"when the user is parent owner"
do
set
(
:owner
)
{
create
(
:user
)
}
before
do
if
board_parent
.
try
(
:namespace
)
board_parent
.
update
(
namespace:
owner
.
namespace
)
else
board
.
parent
.
add_owner
(
owner
)
end
end
it
"deletes the list if an admin requests it"
do
delete
api
(
"
#{
url
}
/
#{
dev_list
.
id
}
"
,
owner
)
expect
(
response
).
to
have_gitlab_http_status
(
204
)
end
it_behaves_like
'412 response'
do
let
(
:request
)
{
api
(
"
#{
url
}
/
#{
dev_list
.
id
}
"
,
owner
)
}
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