Commit d2c49407 authored by Ash McKenzie's avatar Ash McKenzie

Merge branch '35527-add-path-to-package' into 'master'

Add _links to package api

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