Skip to content

Commit

Permalink
Implements space_application_supporter role for viewing app droplets
Browse files Browse the repository at this point in the history
`GET /v3/apps/:guid/droplets/current`
`GET /v3/apps/:guid/relationships/current_droplet`

Github issue: #2209

Co-authored-by: Belinda Liu <bliu@pivotal.io>
Co-authored-by: Matthew Kocher <mkocher@pivotal.io>
  • Loading branch information
belinda-liu and mkocher committed May 10, 2021
1 parent 69f0420 commit 0dcb9ab
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 116 deletions.
4 changes: 2 additions & 2 deletions app/controllers/v3/apps_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def assign_current_droplet

def current_droplet_relationship
app, space, org = AppFetcher.new.fetch(hashed_params[:guid])
app_not_found! unless app && permission_queryer.can_read_from_space?(space.guid, org.guid)
app_not_found! unless app && permission_queryer.untrusted_can_read_from_space?(space.guid, org.guid)
droplet = DropletModel.where(guid: app.droplet_guid).eager(:space, space: :organization).first

droplet_not_found! unless droplet
Expand All @@ -323,7 +323,7 @@ def current_droplet_relationship

def current_droplet
app, space, org = AppFetcher.new.fetch(hashed_params[:guid])
app_not_found! unless app && permission_queryer.can_read_from_space?(space.guid, org.guid)
app_not_found! unless app && permission_queryer.untrusted_can_read_from_space?(space.guid, org.guid)
droplet = DropletModel.where(guid: app.droplet_guid).eager(:space, space: :organization).first

droplet_not_found! unless droplet
Expand Down
117 changes: 50 additions & 67 deletions spec/request/apps_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2491,57 +2491,43 @@
end

describe 'GET /v3/apps/:guid/relationships/current_droplet' do
let(:api_call) { lambda { |user_headers| get "/v3/apps/#{droplet_model.app_guid}/relationships/current_droplet", nil, user_headers } }
let(:app_model) { VCAP::CloudController::AppModel.make(space_guid: space.guid) }
let(:guid) { droplet_model.guid }
let(:package_model) { VCAP::CloudController::PackageModel.make(app_guid: app_model.guid) }
let!(:droplet_model) do
VCAP::CloudController::DropletModel.make(
state: VCAP::CloudController::DropletModel::STAGED_STATE,
app_guid: app_model.guid,
package_guid: package_model.guid,
buildpack_receipt_buildpack: 'http://buildpack.git.url.com',
error_description: 'example error',
execution_metadata: 'some-data',
droplet_hash: 'shalalala',
sha256_checksum: 'droplet-sha256-checksum',
process_types: { 'web' => 'start-command' },
)
let!(:droplet_model) { VCAP::CloudController::DropletModel.make(app_guid: app_model.guid) }
let(:expected_response) do
{
'data' => {
'guid' => droplet_model.guid
},
'links' => {
'self' => { 'href' => "#{link_prefix}/v3/apps/#{droplet_model.app_guid}/relationships/current_droplet" },
'related' => { 'href' => "#{link_prefix}/v3/apps/#{droplet_model.app_guid}/droplets/current" }
}
}
end

let(:expected_codes_and_responses) do
h = Hash.new(code: 200, response_object: expected_response)
h['no_role'] = { code: 404 }
h['org_billing_manager'] = { code: 404 }
h['org_auditor'] = { code: 404 }
h
end
let(:app_guid) { droplet_model.app_guid }

before do
space.organization.add_user(user)
space.add_developer(user)
droplet_model.buildpack_lifecycle_data.update(buildpacks: ['http://buildpack.git.url.com'], stack: 'stack-name')
app_model.droplet_guid = droplet_model.guid
app_model.save
end

it 'gets the current droplet relationship' do
get "/v3/apps/#{app_model.guid}/relationships/current_droplet", nil, user_header

parsed_response = MultiJson.load(last_response.body)

expect(last_response.status).to eq(200)
expect(parsed_response).to be_a_response_like({
'data' => {
'guid' => droplet_model.guid
},
'links' => {
'self' => { 'href' => "#{link_prefix}/v3/apps/#{app_guid}/relationships/current_droplet" },
'related' => { 'href' => "#{link_prefix}/v3/apps/#{app_guid}/droplets/current" }
}
})
end
it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS + ['space_application_supporter']
end

describe 'GET /v3/apps/:guid/droplets/current' do
let(:api_call) { lambda { |user_headers| get "/v3/apps/#{droplet_model.app_guid}/droplets/current", nil, user_headers } }
let(:app_model) { VCAP::CloudController::AppModel.make(space_guid: space.guid) }
let(:guid) { droplet_model.guid }
let(:package_model) { VCAP::CloudController::PackageModel.make(app_guid: app_model.guid) }
let!(:droplet_model) do
VCAP::CloudController::DropletModel.make(
state: VCAP::CloudController::DropletModel::STAGED_STATE,
app_guid: app_model.guid,
package_guid: package_model.guid,
buildpack_receipt_buildpack: 'http://buildpack.git.url.com',
Expand All @@ -2552,33 +2538,17 @@
process_types: { 'web' => 'start-command' },
)
end
let(:app_guid) { droplet_model.app_guid }

before do
space.organization.add_user(user)
space.add_developer(user)
droplet_model.buildpack_lifecycle_data.update(buildpacks: ['http://buildpack.git.url.com'], stack: 'stack-name')
app_model.droplet_guid = droplet_model.guid
app_model.save
end

it 'gets the current droplet' do
get "/v3/apps/#{app_model.guid}/droplets/current", nil, user_header

parsed_response = MultiJson.load(last_response.body)

expect(last_response.status).to eq(200)
expect(parsed_response).to be_a_response_like({
let(:expected_response) do
{
'guid' => droplet_model.guid,
'state' => VCAP::CloudController::DropletModel::STAGED_STATE,
'error' => 'example error',
'lifecycle' => {
'type' => 'buildpack',
'data' => {}
'type' => 'buildpack',
'data' => {}
},
'checksum' => { 'type' => 'sha256', 'value' => 'droplet-sha256-checksum' },
'buildpacks' => [{ 'name' => 'http://buildpack.git.url.com', 'detect_output' => nil, 'buildpack_name' => nil,
'version' => nil }],
'buildpacks' => [{ 'name' => 'http://buildpack.git.url.com', 'detect_output' => nil, 'buildpack_name' => nil, 'version' => nil }],
'stack' => 'stack-name',
'execution_metadata' => 'some-data',
'process_types' => { 'web' => 'start-command' },
Expand All @@ -2587,19 +2557,32 @@
'updated_at' => iso8601,
'relationships' => { 'app' => { 'data' => { 'guid' => app_model.guid } } },
'links' => {
'self' => { 'href' => "#{link_prefix}/v3/droplets/#{guid}" },
'package' => { 'href' => "#{link_prefix}/v3/packages/#{package_model.guid}" },
'app' => { 'href' => "#{link_prefix}/v3/apps/#{app_guid}" },
'download' => { 'href' => "#{link_prefix}/v3/droplets/#{guid}/download" },
'assign_current_droplet' => { 'href' => "#{link_prefix}/v3/apps/#{app_guid}/relationships/current_droplet",
'method' => 'PATCH' },
'self' => { 'href' => "#{link_prefix}/v3/droplets/#{droplet_model.guid}" },
'package' => { 'href' => "#{link_prefix}/v3/packages/#{package_model.guid}" },
'app' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}" },
'download' => { 'href' => "#{link_prefix}/v3/droplets/#{droplet_model.guid}/download" },
'assign_current_droplet' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/relationships/current_droplet", 'method' => 'PATCH' },
},
'metadata' => {
'labels' => {},
'annotations' => {}
},
})
'labels' => {},
'annotations' => {}
},
}
end
let(:expected_codes_and_responses) do
h = Hash.new(code: 200, response_object: expected_response)
h['no_role'] = { code: 404 }
h['org_billing_manager'] = { code: 404 }
h['org_auditor'] = { code: 404 }
h
end
before do
droplet_model.buildpack_lifecycle_data.update(buildpacks: ['http://buildpack.git.url.com'], stack: 'stack-name')
app_model.droplet_guid = droplet_model.guid
app_model.save
end

it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS + ['space_application_supporter']
end

describe 'PATCH /v3/apps/:guid/relationships/current_droplet' do
Expand Down
47 changes: 0 additions & 47 deletions spec/unit/controllers/v3/apps_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2432,53 +2432,6 @@
expect(response.body).to include('ResourceNotFound')
end
end

context 'permissions' do
context 'when the user does not have the read scope' do
before do
set_current_user(VCAP::CloudController::User.make, scopes: [])
end

it 'returns a 403 NotAuthorized error' do
get :current_droplet_relationship, params: { guid: app_model.guid }

expect(response.status).to eq(403)
expect(response.body).to include('NotAuthorized')
end
end

context 'when the user can not read the space' do
let(:space) { droplet.space }
let(:org) { space.organization }

before do
disallow_user_read_access(user, space: space)
end

it 'returns a 404 not found' do
get :current_droplet_relationship, params: { guid: app_model.guid }

expect(response.status).to eq(404)
expect(response.body).to include('ResourceNotFound')
end
end

context 'when the user can read but not update the application' do
let(:space) { droplet.space }
let(:org) { space.organization }

before do
allow_user_read_access_for(user, spaces: [space])
disallow_user_write_access(user, space: space)
end

it 'returns a 200 OK' do
get :current_droplet_relationship, params: { guid: app_model.guid }

expect(response.status).to eq(200)
end
end
end
end

describe 'DeleteAppErrorTranslatorJob' do
Expand Down

0 comments on commit 0dcb9ab

Please sign in to comment.