Remove initScope from trunk delete.action.service
The initScope method is deprecated, the action service should be stateless. Also refactor to simplify delete action logic. Some code got carried over from the images panel, what we originally used as an example. But much of that code was doing checks useless for trunks. Trunks don't have complicated 'public' and 'shared' attributes controlling who can operate on them. A simple policy check will suffice. Co-Authored-By: Bence Romsics <bence.romsics@ericsson.com> Change-Id: I689a98697d997780af42eb31a4b5eeee2ddf9b0f Partially-Implements: blueprint neutron-trunk-ui Related-Bug: #1640049
This commit is contained in:
parent
ec299ff301
commit
7b207fbf89
@ -1,17 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017 Ericsson
|
* Copyright 2017 Ericsson
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* not use this file except in compliance with the License. You may obtain
|
* you may not use this file except in compliance with the License.
|
||||||
* a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* License for the specific language governing permissions and limitations
|
* See the License for the specific language governing permissions and
|
||||||
* under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
@ -19,105 +19,71 @@
|
|||||||
|
|
||||||
angular
|
angular
|
||||||
.module('horizon.app.core.trunks')
|
.module('horizon.app.core.trunks')
|
||||||
.factory(
|
.factory('horizon.app.core.trunks.actions.delete.service', deleteService);
|
||||||
'horizon.app.core.trunks.actions.delete.service',
|
|
||||||
deleteTrunkService
|
|
||||||
);
|
|
||||||
|
|
||||||
deleteTrunkService.$inject = [
|
deleteService.$inject = [
|
||||||
'$q',
|
'$q',
|
||||||
'horizon.app.core.openstack-service-api.neutron',
|
'horizon.app.core.openstack-service-api.neutron',
|
||||||
'horizon.app.core.openstack-service-api.userSession',
|
|
||||||
'horizon.app.core.openstack-service-api.policy',
|
'horizon.app.core.openstack-service-api.policy',
|
||||||
|
'horizon.app.core.trunks.resourceType',
|
||||||
'horizon.framework.util.actions.action-result.service',
|
'horizon.framework.util.actions.action-result.service',
|
||||||
'horizon.framework.util.i18n.gettext',
|
'horizon.framework.widgets.modal.deleteModalService'
|
||||||
'horizon.framework.util.q.extensions',
|
|
||||||
'horizon.framework.widgets.modal.deleteModalService',
|
|
||||||
'horizon.framework.widgets.toast.service',
|
|
||||||
'horizon.app.core.trunks.resourceType'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function deleteTrunkService(
|
function deleteService(
|
||||||
$q,
|
$q,
|
||||||
neutron,
|
neutron,
|
||||||
userSessionService,
|
|
||||||
policy,
|
policy,
|
||||||
|
resourceType,
|
||||||
actionResultService,
|
actionResultService,
|
||||||
gettext,
|
deleteModal
|
||||||
$qExtensions,
|
|
||||||
deleteModal,
|
|
||||||
toast,
|
|
||||||
trunkResourceType
|
|
||||||
) {
|
) {
|
||||||
var scope, context, deleteTrunkPromise;
|
|
||||||
|
|
||||||
var service = {
|
var service = {
|
||||||
initScope: initScope,
|
|
||||||
allowed: allowed,
|
allowed: allowed,
|
||||||
perform: perform
|
perform: perform
|
||||||
};
|
};
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
||||||
function initScope(newScope) {
|
////////////
|
||||||
scope = newScope;
|
|
||||||
context = {};
|
function allowed() {
|
||||||
deleteTrunkPromise = policy.ifAllowed(
|
return policy.ifAllowed(
|
||||||
{rules: [['trunk', 'delete_trunk']]});
|
{rules: [
|
||||||
|
['network', 'delete_trunk']
|
||||||
|
]}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function perform(items) {
|
function perform(items, scope) {
|
||||||
var Trunks = angular.isArray(items) ? items : [items];
|
var trunks = angular.isArray(items) ? items : [items];
|
||||||
context.labels = labelize(Trunks.length);
|
|
||||||
context.deleteEntity = neutron.deleteTrunk;
|
|
||||||
return $qExtensions.allSettled(Trunks.map(checkPermission))
|
|
||||||
.then(afterCheck);
|
|
||||||
}
|
|
||||||
|
|
||||||
function allowed(trunk) {
|
return openModal().then(onComplete);
|
||||||
if (trunk) {
|
|
||||||
return $q.all([
|
|
||||||
deleteTrunkPromise,
|
|
||||||
userSessionService.isCurrentProject(trunk.project_id)
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
return deleteTrunkPromise;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkPermission(trunk) {
|
function openModal() {
|
||||||
return {promise: allowed(trunk), context: trunk};
|
return deleteModal.open(
|
||||||
}
|
|
||||||
|
|
||||||
function afterCheck(result) {
|
|
||||||
var outcome = $q.reject();
|
|
||||||
if (result.fail.length > 0) {
|
|
||||||
var msg = interpolate(
|
|
||||||
gettext("You are not allowed to delete trunks: %s"),
|
|
||||||
[result.fail.map(function (x) {return x.context.name;}).join(", ")]);
|
|
||||||
toast.add('error', msg, result.fail);
|
|
||||||
outcome = $q.reject(result.fail);
|
|
||||||
}
|
|
||||||
if (result.pass.length > 0) {
|
|
||||||
outcome = deleteModal.open(
|
|
||||||
scope,
|
scope,
|
||||||
result.pass.map(function (x) {return x.context;}),
|
trunks,
|
||||||
context)
|
{
|
||||||
.then(createResult);
|
labels: labelize(trunks.length),
|
||||||
|
deleteEntity: neutron.deleteTrunk
|
||||||
}
|
}
|
||||||
return outcome;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createResult(deleteModalResult) {
|
function onComplete(result) {
|
||||||
var actionResult = actionResultService.getActionResult();
|
var actionResult = actionResultService.getActionResult();
|
||||||
deleteModalResult.pass.forEach(function markDeleted(item) {
|
|
||||||
actionResult.deleted(trunkResourceType, item.context.id);
|
result.pass.forEach(function markDeleted(item) {
|
||||||
|
actionResult.deleted(resourceType, item.context.id);
|
||||||
});
|
});
|
||||||
deleteModalResult.fail.forEach(function markFailed(item) {
|
result.fail.forEach(function markFailed(item) {
|
||||||
actionResult.failed(trunkResourceType, item.context.id);
|
actionResult.failed(resourceType, item.context.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
return actionResult.result;
|
return actionResult.result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function labelize(count) {
|
function labelize(count) {
|
||||||
return {
|
return {
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017 Ericsson
|
* Copyright 2017 Ericsson
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* not use this file except in compliance with the License. You may obtain
|
* you may not use this file except in compliance with the License.
|
||||||
* a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* License for the specific language governing permissions and limitations
|
* See the License for the specific language governing permissions and
|
||||||
* under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
@ -40,21 +40,17 @@
|
|||||||
return {
|
return {
|
||||||
success: function(callback) {
|
success: function(callback) {
|
||||||
callback({allowed: true});
|
callback({allowed: true});
|
||||||
|
},
|
||||||
|
failure: function(callback) {
|
||||||
|
callback({allowed: false});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var userSession = {
|
|
||||||
isCurrentProject: function() {
|
|
||||||
deferred.resolve();
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var deferred, service, $scope, deferredModal;
|
var deferred, service, $scope, deferredModal;
|
||||||
|
|
||||||
///////////////////////
|
////////////
|
||||||
|
|
||||||
beforeEach(module('horizon.app.core'));
|
beforeEach(module('horizon.app.core'));
|
||||||
beforeEach(module('horizon.app.core.trunks'));
|
beforeEach(module('horizon.app.core.trunks'));
|
||||||
@ -67,9 +63,7 @@
|
|||||||
beforeEach(module('horizon.app.core.openstack-service-api', function($provide) {
|
beforeEach(module('horizon.app.core.openstack-service-api', function($provide) {
|
||||||
$provide.value('horizon.app.core.openstack-service-api.neutron', neutronAPI);
|
$provide.value('horizon.app.core.openstack-service-api.neutron', neutronAPI);
|
||||||
$provide.value('horizon.app.core.openstack-service-api.policy', policyAPI);
|
$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(policyAPI, 'ifAllowed').and.callThrough();
|
||||||
spyOn(userSession, 'isCurrentProject').and.callThrough();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(inject(function($injector, _$rootScope_, $q) {
|
beforeEach(inject(function($injector, _$rootScope_, $q) {
|
||||||
@ -101,31 +95,11 @@
|
|||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
spyOn(deleteModalService, 'open').and.callThrough();
|
spyOn(deleteModalService, 'open').and.callThrough();
|
||||||
service.initScope($scope, labelize);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function labelize(count) {
|
|
||||||
return {
|
|
||||||
title: ngettext('title', 'titles', count),
|
|
||||||
message: ngettext('message', 'messages', count),
|
|
||||||
submit: ngettext('submit', 'submits', count),
|
|
||||||
success: ngettext('success', 'successes', count),
|
|
||||||
error: ngettext('error', 'errors', count)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////
|
|
||||||
|
|
||||||
it('should open the delete modal and show correct singular labels', testSingleLabels);
|
|
||||||
it('should open the delete modal and show correct labels, one object', testSingleObject);
|
|
||||||
it('should open the delete modal and show correct plural labels', testpluralLabels);
|
|
||||||
it('should open the delete modal with correct entities', testEntities);
|
|
||||||
it('should only delete trunks that are valid', testValids);
|
|
||||||
it('should fail if this project is not owner', testOwner);
|
|
||||||
it('should pass in a function that deletes a trunk', testNeutron);
|
|
||||||
|
|
||||||
////////////
|
////////////
|
||||||
|
|
||||||
|
it('should open the delete modal and show correct labels, one object',
|
||||||
function testSingleObject() {
|
function testSingleObject() {
|
||||||
var trunks = generateTrunk(1);
|
var trunks = generateTrunk(1);
|
||||||
service.perform(trunks[0]);
|
service.perform(trunks[0]);
|
||||||
@ -137,7 +111,9 @@
|
|||||||
expect(label.toLowerCase()).toContain('trunk');
|
expect(label.toLowerCase()).toContain('trunk');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should open the delete modal and show correct singular labels',
|
||||||
function testSingleLabels() {
|
function testSingleLabels() {
|
||||||
var trunks = generateTrunk(1);
|
var trunks = generateTrunk(1);
|
||||||
service.perform(trunks);
|
service.perform(trunks);
|
||||||
@ -149,7 +125,9 @@
|
|||||||
expect(label.toLowerCase()).toContain('trunk');
|
expect(label.toLowerCase()).toContain('trunk');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should open the delete modal and show correct plural labels',
|
||||||
function testpluralLabels() {
|
function testpluralLabels() {
|
||||||
var trunks = generateTrunk(2);
|
var trunks = generateTrunk(2);
|
||||||
service.perform(trunks);
|
service.perform(trunks);
|
||||||
@ -161,7 +139,9 @@
|
|||||||
expect(label.toLowerCase()).toContain('trunks');
|
expect(label.toLowerCase()).toContain('trunks');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should open the delete modal with correct entities',
|
||||||
function testEntities() {
|
function testEntities() {
|
||||||
var count = 3;
|
var count = 3;
|
||||||
var trunks = generateTrunk(count);
|
var trunks = generateTrunk(count);
|
||||||
@ -172,7 +152,9 @@
|
|||||||
expect(deleteModalService.open).toHaveBeenCalled();
|
expect(deleteModalService.open).toHaveBeenCalled();
|
||||||
expect(entities.length).toEqual(count);
|
expect(entities.length).toEqual(count);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should only delete trunks that are valid',
|
||||||
function testValids() {
|
function testValids() {
|
||||||
var count = 2;
|
var count = 2;
|
||||||
var trunks = generateTrunk(count);
|
var trunks = generateTrunk(count);
|
||||||
@ -185,16 +167,9 @@
|
|||||||
expect(entities[0].name).toEqual('trunk0');
|
expect(entities[0].name).toEqual('trunk0');
|
||||||
expect(entities[1].name).toEqual('trunk1');
|
expect(entities[1].name).toEqual('trunk1');
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function testOwner() {
|
it('should pass in a function that deletes a trunk',
|
||||||
var trunks = generateTrunk(1);
|
|
||||||
deferred.reject();
|
|
||||||
service.perform(trunks);
|
|
||||||
$scope.$apply();
|
|
||||||
|
|
||||||
expect(deleteModalService.open).not.toHaveBeenCalled();
|
|
||||||
}
|
|
||||||
|
|
||||||
function testNeutron() {
|
function testNeutron() {
|
||||||
spyOn(neutronAPI, 'deleteTrunk');
|
spyOn(neutronAPI, 'deleteTrunk');
|
||||||
var count = 1;
|
var count = 1;
|
||||||
@ -208,6 +183,7 @@
|
|||||||
deleteFunction(trunk.id);
|
deleteFunction(trunk.id);
|
||||||
expect(neutronAPI.deleteTrunk).toHaveBeenCalledWith(trunk.id);
|
expect(neutronAPI.deleteTrunk).toHaveBeenCalledWith(trunk.id);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
}); // end of delete modal
|
}); // end of delete modal
|
||||||
|
|
||||||
@ -221,17 +197,11 @@
|
|||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
spyOn(resolver, 'success');
|
spyOn(resolver, 'success');
|
||||||
spyOn(resolver, 'error');
|
spyOn(resolver, 'error');
|
||||||
service.initScope($scope);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
////////////
|
////////////
|
||||||
|
|
||||||
it('should use default policy if batch action', testBatch);
|
it('should use default policy if batch action',
|
||||||
it('allows delete if trunk can be deleted', testValid);
|
|
||||||
it('disallows delete if trunk is not owned by user', testOwner);
|
|
||||||
|
|
||||||
////////////
|
|
||||||
|
|
||||||
function testBatch() {
|
function testBatch() {
|
||||||
service.allowed();
|
service.allowed();
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
@ -239,21 +209,24 @@
|
|||||||
expect(resolver.success).not.toHaveBeenCalled();
|
expect(resolver.success).not.toHaveBeenCalled();
|
||||||
expect(resolver.error).not.toHaveBeenCalled();
|
expect(resolver.error).not.toHaveBeenCalled();
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('allows delete if trunk can be deleted',
|
||||||
function testValid() {
|
function testValid() {
|
||||||
var trunk = generateTrunk(1)[0];
|
service.allowed().success(resolver.success);
|
||||||
service.allowed(trunk).then(resolver.success, resolver.error);
|
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
expect(resolver.success).toHaveBeenCalled();
|
expect(resolver.success).toHaveBeenCalled();
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('disallows delete if trunk is not owned by user',
|
||||||
function testOwner() {
|
function testOwner() {
|
||||||
var trunk = generateTrunk(1)[0];
|
|
||||||
deferred.reject();
|
deferred.reject();
|
||||||
service.allowed(trunk).then(resolver.success, resolver.error);
|
service.allowed().failure(resolver.error);
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
expect(resolver.error).toHaveBeenCalled();
|
expect(resolver.error).toHaveBeenCalled();
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
}); // end of allow method
|
}); // end of allow method
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user