Allow users to update images created from other projects

Currently on the angular images panel, edit image/update metadata/delete image
actions are only available for images created from the current logged in project.

This patch removed that restriction and added the policy check for the actions.

Change-Id: I17761e27f0659799d5e55e24a6106c3c7a3e5459
Closes-bug: #1698963
This commit is contained in:
Ying Zuo 2017-06-23 21:37:26 -07:00
parent 19414ccb48
commit d8dea730d9
6 changed files with 34 additions and 69 deletions

View File

@ -22,7 +22,6 @@
deleteImageService.$inject = [
'$q',
'horizon.app.core.openstack-service-api.glance',
'horizon.app.core.openstack-service-api.userSession',
'horizon.app.core.openstack-service-api.policy',
'horizon.framework.util.actions.action-result.service',
'horizon.framework.util.i18n.gettext',
@ -45,7 +44,6 @@
function deleteImageService(
$q,
glance,
userSessionService,
policy,
actionResultService,
gettext,
@ -87,7 +85,7 @@
return $q.all([
notProtected(image),
deleteImagePromise,
userSessionService.isCurrentProject(image.owner),
policy.ifAllowed({ rules: [['image', 'delete_image']] }),
notDeleted(image)
]);
} else {

View File

@ -43,14 +43,7 @@
}
};
var userSession = {
isCurrentProject: function() {
deferred.resolve();
return deferred.promise;
}
};
var deferred, service, $scope, deferredModal;
var service, $scope, deferredModal;
///////////////////////
@ -65,15 +58,12 @@
beforeEach(module('horizon.app.core.openstack-service-api', function($provide) {
$provide.value('horizon.app.core.openstack-service-api.glance', glanceAPI);
$provide.value('horizon.app.core.openstack-service-api.policy', policyAPI);
$provide.value('horizon.app.core.openstack-service-api.userSession', userSession);
spyOn(policyAPI, 'ifAllowed').and.callThrough();
spyOn(userSession, 'isCurrentProject').and.callThrough();
}));
beforeEach(inject(function($injector, _$rootScope_, $q) {
$scope = _$rootScope_.$new();
service = $injector.get('horizon.app.core.images.actions.delete-image.service');
deferred = $q.defer();
deferredModal = $q.defer();
}));
@ -121,7 +111,6 @@
it('should open the delete modal and show correct labels', testpluralLabels);
it('should open the delete modal with correct entities', testEntities);
it('should only delete images that are valid', testValids);
it('should fail if this project is not owner', testOwner);
it('should fail if images is protected', testProtected);
it('should fail if status is deleted', testStatus);
it('should pass in a function that deletes an image', testGlance);
@ -188,15 +177,6 @@
expect(entities[1].name).toEqual('image2');
}
function testOwner() {
var images = generateImage(1);
deferred.reject();
service.perform(images);
$scope.$apply();
expect(deleteModalService.open).not.toHaveBeenCalled();
}
function testProtected() {
var images = generateImage(1);
images[0].protected = true;
@ -249,7 +229,6 @@
it('should use default policy if batch action', testBatch);
it('allows delete if image can be deleted', testValid);
it('disallows delete if image is protected', testProtected);
it('disallows delete if image is not owned by user', testOwner);
it('disallows delete if image status is deleted', testStatus);
////////////
@ -277,14 +256,6 @@
expect(resolver.error).toHaveBeenCalled();
}
function testOwner() {
var image = generateImage(1)[0];
deferred.reject();
service.allowed(image).then(resolver.success, resolver.error);
$scope.$apply();
expect(resolver.error).toHaveBeenCalled();
}
function testStatus() {
var image = generateImage(1)[0];
image.status = 'deleted';

View File

@ -29,7 +29,6 @@
'horizon.app.core.metadata.service',
'horizon.app.core.openstack-service-api.glance',
'horizon.app.core.openstack-service-api.policy',
'horizon.app.core.openstack-service-api.userSession',
'horizon.framework.util.actions.action-result.service',
'horizon.framework.util.q.extensions',
'horizon.framework.widgets.modal.wizard-modal.service',
@ -49,7 +48,6 @@
metadataService,
glance,
policy,
userSessionService,
actionResultService,
$qExtensions,
wizardModalService,
@ -84,7 +82,6 @@
function allowed(image) {
return $q.all([
modifyImagePolicyCheck,
userSessionService.isCurrentProject(image.owner),
isActive(image)
]);
}

View File

@ -114,14 +114,6 @@
expect(modalArgs.workflow).toBeDefined();
});
it('should not allow edit if image is not owned by user', function() {
deferred.reject();
var image = {owner: 'doesnt_matter', status: 'active'};
var allowed = service.allowed(image);
permissionShouldFail(allowed);
$scope.$apply();
});
it('should not allow edit if image status is not active', function() {
var image = {owner: 'project', status: 'not_active'};
var allowed = service.allowed(image);

View File

@ -23,7 +23,7 @@
updateMetadataService.$inject = [
'$q',
'horizon.app.core.metadata.modal.service',
'horizon.app.core.openstack-service-api.userSession',
'horizon.app.core.openstack-service-api.policy',
'horizon.framework.util.actions.action-result.service',
'horizon.framework.util.q.extensions',
'horizon.app.core.images.resourceType'
@ -35,7 +35,7 @@
*
* @param {Object} $q
* @param {Object} metadataModalService
* @param {Object} userSessionService
* @param {Object} policy
* @param {Object} $qExtensions
* @Description
* Brings up the Update Metadata for image modal.
@ -47,7 +47,7 @@
function updateMetadataService(
$q,
metadataModalService,
userSessionService,
policy,
actionResultService,
$qExtensions,
imageResourceType
@ -77,7 +77,10 @@
}
function allowed(image) {
return $q.all([userSessionService.isCurrentProject(image.owner), isActive(image)]);
return $q.all([
policy.ifAllowed({rules: [['image', 'modify_metadef_object']]}),
isActive(image)
]);
}
function isActive(image) {

View File

@ -17,19 +17,22 @@
'use strict';
describe('horizon.app.core.images.actions.update-metadata.service', function() {
var deferred, service, $scope;
var userSession = {
isCurrentProject: function() {
deferred.resolve();
return deferred.promise;
}
};
var service, $scope;
var metadataModalMock = {
open: function () {}
};
var policyAPI = {
ifAllowed: function() {
return {
success: function(callback) {
callback({allowed: false});
}
};
}
};
///////////////////////
beforeEach(module('horizon.framework'));
@ -38,14 +41,9 @@
$provide.value('horizon.app.core.metadata.modal.service', metadataModalMock);
}));
beforeEach(module('horizon.app.core.openstack-service-api', function($provide) {
$provide.value('horizon.app.core.openstack-service-api.userSession', userSession);
}));
beforeEach(inject(function($injector, _$rootScope_, $q) {
beforeEach(inject(function($injector, _$rootScope_) {
$scope = _$rootScope_.$new();
service = $injector.get('horizon.app.core.images.actions.update-metadata.service');
deferred = $q.defer();
}));
it('should open the modal with correct message', function() {
@ -66,19 +64,25 @@
});
describe('Update Metadata', function() {
function policyIfAllowed() {
return {
then: function(callback) {
callback({allowed: true});
}
};
}
beforeEach(inject(function ($injector) {
policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy');
spyOn(policyAPI, 'ifAllowed').and.callFake(policyIfAllowed);
}));
it('should allow Update Metadata if image can be deleted', function() {
var image = {owner: 'project', status: 'active'};
permissionShouldPass(service.allowed(image));
$scope.$apply();
});
it('should not allow Update Metadata if service call is rejected', function() {
var image = {owner: 'doesnt_matter', status: 'active'};
deferred.reject();
permissionShouldFail(service.allowed(image));
$scope.$apply();
});
it('should not allow Update Metadata if image status is not active', function() {
var image = {owner: 'project', status: 'not_active'};
permissionShouldFail(service.allowed(image));