Commit e1c44cbc authored by Giorgenes Gelatti's avatar Giorgenes Gelatti

Add _links to package api

- adds details api url to _links in package
- adds conditional destroy url if user has
  permission to destroy the package
parent 3eb67d94
---
title: Add _links object to package api response
merge_request: 20820
author:
type: added
......@@ -72,19 +72,32 @@ Example response:
"id": 1,
"name": "com/mycompany/my-app",
"version": "1.0-SNAPSHOT",
"package_type": "maven"
"package_type": "maven",
"_links": {
"details": "/namespace1/project1/-/packages/1",
"destroy": "/namespace1/project1/-/packages/1"
}
},
{
"id": 2,
"name": "@foo/bar",
"version": "1.0.3",
"package_type": "npm"
"package_type": "npm",
"_links": {
"details": "/namespace1/project1/-/packages/2",
"destroy": "/namespace1/project1/-/packages/2"
}
}
]
```
By default, the `GET` request will return 20 results, since the API is [paginated](README.md#pagination).
The `_links` object contains the following properties:
- `details`: URL to fetch details about the package.
- `destroy`: URL to destroy the package. Only available if the request user has permission to do so.
## Get a project package
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/9667) in GitLab 11.9.
......@@ -111,10 +124,19 @@ Example response:
"id": 1,
"name": "com/mycompany/my-app",
"version": "1.0-SNAPSHOT",
"package_type": "maven"
"package_type": "maven",
"_links": {
"details": "/namespace1/project1/-/packages/1",
"destroy": "/namespace1/project1/-/packages/1"
}
}
```
The `_links` object contains the following properties:
- `details`: URL to fetch details about the package.
- `destroy`: URL to destroy the package. Only available if the request user has permission to do so.
## List package files
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/9305) in GitLab 11.8.
......
......@@ -38,7 +38,7 @@ module API
package = ::Packages::PackageFinder
.new(user_project, params[:package_id]).execute
present package, with: EE::API::Entities::Package
present package, with: EE::API::Entities::Package, user: current_user
end
desc 'Remove a package' do
......
......@@ -8,6 +8,10 @@ module EE
->(obj, opts) { Ability.allowed?(opts[:user], "read_#{attr}".to_sym, yield(obj)) }
end
def can_destroy(attr, &block)
->(obj, opts) { Ability.allowed?(opts[:user], "destroy_#{attr}".to_sym, yield(obj)) }
end
def expose_restricted(attr, &block)
expose attr, if: can_read(attr, &block)
end
......@@ -847,10 +851,23 @@ module EE
end
class Package < Grape::Entity
include ::API::Helpers::RelatedResourcesHelpers
extend EntityHelpers
expose :id
expose :name
expose :version
expose :package_type
expose :_links do
expose :details do |package|
expose_url api_v4_projects_packages_path(package_id: package.id, id: package.project_id)
end
expose :destroy, if: can_destroy(:package, &:project) do |package|
expose_url api_v4_projects_packages_path(package_id: package.id, id: package.project_id)
end
end
end
class PackageFile < Grape::Entity
......
{
"type": "object",
"required" : ["name", "version", "package_type"],
"properties" : {
"name": { "type": "string" },
"version": { "type": "string" },
"package_type": { "type": "string" }
"required": [
"name",
"version",
"package_type",
"_links"
],
"properties": {
"name": {
"type": "string"
},
"version": {
"type": "string"
},
"package_type": {
"type": "string"
},
"_links": {
"type": "object",
"required": [
"details"
],
"properties": {
"details": {
"type": "string"
}
}
}
}
}
......@@ -71,6 +71,24 @@ describe API::ProjectPackages do
end
describe 'GET /projects/:id/packages/:package_id' do
subject { get api(package_url, user) }
shared_examples 'no destroy url' do
it 'returns no destroy url' do
subject
expect(json_response['_links']).not_to include('destroy')
end
end
shared_examples 'destroy url' do
it 'returns destroy url' do
subject
expect(json_response['_links']['destroy']).to be_present
end
end
context 'packages feature enabled' do
before do
stub_licensed_features(packages: true)
......@@ -78,7 +96,7 @@ describe API::ProjectPackages do
context 'project is public' do
it 'returns 200 and the package information' do
get api(package_url, user)
subject
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/packages/package', dir: 'ee')
......@@ -95,6 +113,8 @@ describe API::ProjectPackages do
expect(response).to have_gitlab_http_status(404)
end
it_behaves_like 'no destroy url'
end
context 'project is private' do
......@@ -107,18 +127,32 @@ describe API::ProjectPackages do
end
it 'returns 404 for a user without access to the project' do
get api(package_url, user)
subject
expect(response).to have_gitlab_http_status(404)
end
it 'returns 200 and the package information' do
project.add_developer(user)
context 'user is a developer' do
before do
project.add_developer(user)
end
get api(package_url, user)
it 'returns 200 and the package information' do
subject
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/packages/package', dir: 'ee')
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/packages/package', dir: 'ee')
end
it_behaves_like 'no destroy url'
end
context 'user is a maintainer' do
before do
project.add_maintainer(user)
end
it_behaves_like 'destroy url'
end
end
end
......@@ -129,7 +163,7 @@ describe API::ProjectPackages do
end
it 'returns 403' do
get api(package_url, user)
subject
expect(response).to have_gitlab_http_status(403)
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