hz-dynamic-table: Column level permissions
hz-dynamic-table doesn't have any way to dynamically determine whether or not to display a column. For example, in openstack dashboard, we may want to display a column only in certain policies pass check, if certain settings are enabled, or services are enabled. In addition, a generic allowed function can just be set on the column config. This patch adds this ability as a reusable service. The reusable service will make it possible for horizon to easily check common sets of permissions on a variety of objects including the hz-dynamic-table columns (in this patch). Child patches demonstrate its use on the images table. Change-Id: I9f92b69d86d830387a83c28ec5829fb3c43fc4a6 Partially-Implements: blueprint angularize-images-table Co-Authored-By: Matt Borland <matt.borland@hpe.com>
This commit is contained in:
parent
5401d9245a
commit
65f0f74390
158
horizon/static/framework/conf/permissions.service.js
Normal file
158
horizon/static/framework/conf/permissions.service.js
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular
|
||||||
|
.module('horizon.framework.conf')
|
||||||
|
.service('horizon.framework.conf.permissions.service', Permissions);
|
||||||
|
|
||||||
|
Permissions.$inject = ['$q'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc service
|
||||||
|
* @name horizon.framework.conf.permissions
|
||||||
|
* @module horizon.framework.conf
|
||||||
|
*
|
||||||
|
* This service provides a common set of a promise based permission checking that
|
||||||
|
* can be applied to various entities in horizon. In the most basic case,
|
||||||
|
* this code executes the allowed() function (if it exists) on
|
||||||
|
* items passed in and returns the promise which will either resolve
|
||||||
|
* if the item should be allowed or reject if it should not be allowed.
|
||||||
|
* An example of an item passed in might be a hz-dynamic-table column spec.
|
||||||
|
* See that code for an example of permissionService in use.
|
||||||
|
*
|
||||||
|
* Horizon is technically a set of application agnostic widgets and utilities
|
||||||
|
* that can be used for various applications. The OpenStack Dashboard is
|
||||||
|
* an implementation that uses these widgets. Many of these widgets, such
|
||||||
|
* as hz-dynamic-table may need to be displayed based on a variety of permissions
|
||||||
|
* that are application specific and that are more simply expressed in a declarative
|
||||||
|
* matter rather than functional code such as the allowed function. This service
|
||||||
|
* provides this capability by allowing applications to decorate this service and
|
||||||
|
* override the extendedPermissions function.
|
||||||
|
*
|
||||||
|
* In the openstack dashboard additional checks beyond the simple allowed() function
|
||||||
|
* are added to this service in the app.core.conf permissionsDecorator,
|
||||||
|
* including policies, services and settings.
|
||||||
|
*/
|
||||||
|
function Permissions($q) {
|
||||||
|
var service = {
|
||||||
|
checkAllowed: checkAllowed,
|
||||||
|
checkAll: checkAll,
|
||||||
|
extendedPermissions: extendedPermissions
|
||||||
|
};
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this input configItem has an allowed function, this will execute it and return
|
||||||
|
* the promise. Otherwise it will return a resolved promise.
|
||||||
|
*/
|
||||||
|
function checkAllowed(configItem) {
|
||||||
|
if (angular.isFunction(configItem.allowed)) {
|
||||||
|
return configItem.allowed();
|
||||||
|
} else {
|
||||||
|
return $q.when(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On the given configItem, this will get configItem.allowed and get each
|
||||||
|
* additional property matching a permission defined in extended permissions.
|
||||||
|
* All of the promises will then be run using $q.all. If all promises resolve
|
||||||
|
* then this will resolve. Otherwise, this will reject.
|
||||||
|
*
|
||||||
|
* When the input to any given permission is an array, each element will be
|
||||||
|
* treated as a distinct permission and a single promise resolver will be invoked for
|
||||||
|
* each input element.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* In openstack dashboard, each of the policies in the below array will result in a distinct
|
||||||
|
* policy check and all of the policies must pass in order for this to permit (resolve) the
|
||||||
|
* permissions check.
|
||||||
|
*
|
||||||
|
* configItem.policies = [{ rules: [["identity", "identity:get_project"]] }, { <rule 2>}]
|
||||||
|
*/
|
||||||
|
function checkAll(configItem) {
|
||||||
|
var promises = [];
|
||||||
|
promises = promises.concat(getConfigurationPromises(configItem));
|
||||||
|
promises.push(checkAllowed(configItem));
|
||||||
|
return $q.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This defines all additional permissions that can be defined on the input configItem
|
||||||
|
* of checkAll. This is a function that returns an object definition where
|
||||||
|
* each property on the object is the name of a permission that can be set on
|
||||||
|
* the configItem in order have permission to access / use whatever is being requested.
|
||||||
|
* The value of each property should be a promise that can resolve a single instance of that
|
||||||
|
* permission. When the input to any given permission is an array, each element will be
|
||||||
|
* treated as a distinct input and a single promise resolver will be invoked for
|
||||||
|
* each input element.
|
||||||
|
*
|
||||||
|
* Since this is part of the horizon framework, it defaults to returning an empty object.
|
||||||
|
* However, individual applications can decorate this service and override this
|
||||||
|
* function to provide common permissions for their application.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* Openstack Dashboard may set permissions for required policies, services, or settings
|
||||||
|
* (amongst other items). To do this, the service would be decorated like the following:
|
||||||
|
*
|
||||||
|
function decorator($delegate, policy, serviceCatalog, settings) {
|
||||||
|
var permissionsService = $delegate;
|
||||||
|
|
||||||
|
permissionsService.extendedPermissions = extendedPermissions;
|
||||||
|
|
||||||
|
function extendedPermissions() {
|
||||||
|
return {
|
||||||
|
policies: policy.ifAllowed,
|
||||||
|
services: serviceCatalog.ifTypeEnabled,
|
||||||
|
settings: settings.ifEnabled
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return $delegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
function extendedPermissions() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConfigurationPromises(configItem) {
|
||||||
|
|
||||||
|
var promises = [];
|
||||||
|
|
||||||
|
angular.forEach(service.extendedPermissions, checkPermissions);
|
||||||
|
|
||||||
|
function checkPermissions(permissionResolver, permissionName) {
|
||||||
|
var permissionInput = configItem[permissionName];
|
||||||
|
if (angular.isArray(permissionInput)) {
|
||||||
|
angular.forEach(permissionInput, function addPermissionCheck(singlePermissionInput) {
|
||||||
|
promises.push(permissionResolver(singlePermissionInput));
|
||||||
|
});
|
||||||
|
} else if (angular.isDefined(permissionInput)) {
|
||||||
|
promises.push(permissionResolver(permissionInput));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return promises;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
})();
|
119
horizon/static/framework/conf/permissions.service.spec.js
Normal file
119
horizon/static/framework/conf/permissions.service.spec.js
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('permissions service', function() {
|
||||||
|
var service;
|
||||||
|
|
||||||
|
beforeEach(module('horizon.framework.conf'));
|
||||||
|
beforeEach(inject(function($injector) {
|
||||||
|
service = $injector.get('horizon.framework.conf.permissions.service');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("is defined", function() {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("checkAllowed", function() {
|
||||||
|
|
||||||
|
it("returns rejected promise returned by configItem.allowed", inject(function($q, $timeout) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
deferred.reject();
|
||||||
|
var item = {allowed: function() { return deferred.promise; }};
|
||||||
|
service.checkAllowed(item).then(fail, pass);
|
||||||
|
$timeout.flush();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("returns resolved promise returned by configItem.allowed", inject(function($q, $timeout) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
deferred.resolve({});
|
||||||
|
var item = {allowed: function() { return deferred.promise; }};
|
||||||
|
service.checkAllowed(item).then(pass, fail);
|
||||||
|
$timeout.flush();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("returns resolved promise when no configItem.allowed", inject(function($q, $timeout) {
|
||||||
|
var item = {};
|
||||||
|
service.checkAllowed(item).then(pass, fail);
|
||||||
|
$timeout.flush();
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("checkAll", function() {
|
||||||
|
describe("with extended permissions", function() {
|
||||||
|
beforeEach(inject(function($q) {
|
||||||
|
var resolver = function() { return $q.defer().promise; };
|
||||||
|
service.extendedPermissions = { perm1: resolver };
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("with promise array, adds checks for permissions", inject(function($q) {
|
||||||
|
var input = {perm1: [$q.defer().promise]};
|
||||||
|
service.checkAll(input).then(verifyResult);
|
||||||
|
function verifyResult(result) {
|
||||||
|
expect(angular.isArray(result)).toBe(true);
|
||||||
|
expect(result.length).toBe(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("with promise, adds checks for permissions", inject(function($q) {
|
||||||
|
var input = {perm1: $q.defer().promise};
|
||||||
|
service.checkAll(input).then(verifyResult);
|
||||||
|
function verifyResult(result) {
|
||||||
|
expect(angular.isArray(result)).toBe(true);
|
||||||
|
expect(result.length).toBe(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("with no promise, adds checks for permissions", inject(function($q) {
|
||||||
|
var input = {unlisted: $q.defer().promise};
|
||||||
|
service.checkAll(input).then(verifyResult);
|
||||||
|
function verifyResult(result) {
|
||||||
|
expect(angular.isArray(result)).toBe(true);
|
||||||
|
expect(result.length).toBe(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("without extended permissions it returns no promises", inject(function($q) {
|
||||||
|
var retval = service.checkAll({perm1: [$q.defer().promise]});
|
||||||
|
retval.then(verifyResult);
|
||||||
|
function verifyResult(result) {
|
||||||
|
expect(angular.isArray(result)).toBe(true);
|
||||||
|
expect(result.length).toBe(0);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("extendedPermissions", function() {
|
||||||
|
it("defaults to returning no permissions", function() {
|
||||||
|
expect(service.extendedPermissions()).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function pass() {
|
||||||
|
expect(true).toBe(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fail() {
|
||||||
|
expect(true).toBe(false);
|
||||||
|
}
|
||||||
|
})();
|
@ -13,14 +13,17 @@
|
|||||||
* License for the specific language governing permissions and limitations
|
* License for the specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
(function() {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular
|
angular
|
||||||
.module('horizon.framework.widgets.table')
|
.module('horizon.framework.widgets.table')
|
||||||
.directive('hzDynamicTable', hzDynamicTable);
|
.directive('hzDynamicTable', hzDynamicTable);
|
||||||
|
|
||||||
hzDynamicTable.$inject = ['horizon.framework.widgets.basePath'];
|
hzDynamicTable.$inject = [
|
||||||
|
'horizon.framework.widgets.basePath',
|
||||||
|
'horizon.framework.conf.permissions.service'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc directive
|
* @ngdoc directive
|
||||||
@ -52,8 +55,20 @@
|
|||||||
* not provided, the default message is used.
|
* not provided, the default message is used.
|
||||||
* columns {Array} of objects to describe each column. Each object
|
* columns {Array} of objects to describe each column. Each object
|
||||||
* requires: 'id', 'title', 'priority' (responsive priority when table resized)
|
* requires: 'id', 'title', 'priority' (responsive priority when table resized)
|
||||||
* optional: 'sortDefault', 'filters' (to apply to the column cells),
|
* optional: 'sortDefault',
|
||||||
* 'template' (see hz-cell directive for details)
|
* 'filters' (to apply to the column cells),
|
||||||
|
* 'template' (see hz-cell directive for details),
|
||||||
|
* 'allowed' (a promise that must resolve in order for the column to be viewed),
|
||||||
|
*
|
||||||
|
* This directive provides an extension point for applications to decorate additional declarative
|
||||||
|
* column level permissions that must be fulfilled in order for the column to be viewed. For
|
||||||
|
* example, openstack dashboard adds the following optional declarative permissions:
|
||||||
|
* 'services' (OpenStack services that must be enabled in the current region),
|
||||||
|
* 'settings' (horizon settings that must be enabled)
|
||||||
|
* 'policies' (policy rules that must be allowed)
|
||||||
|
*
|
||||||
|
* This is accomplished by decorating the 'horizon.framework.conf.permissions' service.
|
||||||
|
* See that service for more information.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
*
|
*
|
||||||
@ -66,6 +81,7 @@
|
|||||||
* {id: 'b', title: 'B', priority: 2},
|
* {id: 'b', title: 'B', priority: 2},
|
||||||
* {id: 'c', title: 'C', priority: 1, sortDefault: true},
|
* {id: 'c', title: 'C', priority: 1, sortDefault: true},
|
||||||
* {id: 'd', title: 'D', priority: 2, filters: [myFilter, 'yesno']}
|
* {id: 'd', title: 'D', priority: 2, filters: [myFilter, 'yesno']}
|
||||||
|
* {id: 'e', title: 'E', allowed: allowedPromiseFunction}
|
||||||
* ]
|
* ]
|
||||||
* };
|
* };
|
||||||
* ```
|
* ```
|
||||||
@ -86,7 +102,7 @@
|
|||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function hzDynamicTable(basePath) {
|
function hzDynamicTable(basePath, permissionsService) {
|
||||||
|
|
||||||
// <r1chardj0n3s>: there are some configuration items which are on the directive,
|
// <r1chardj0n3s>: there are some configuration items which are on the directive,
|
||||||
// and some on the "config" attribute of the directive. Those latter configuration
|
// and some on the "config" attribute of the directive. Those latter configuration
|
||||||
@ -114,6 +130,8 @@
|
|||||||
return directive;
|
return directive;
|
||||||
|
|
||||||
function preLink(scope) {
|
function preLink(scope) {
|
||||||
|
//Isolate config changes we do here from propagating out.
|
||||||
|
scope.config = angular.copy(scope.config);
|
||||||
scope.items = [];
|
scope.items = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +143,30 @@
|
|||||||
if (angular.isUndefined(scope.config.expand)) {
|
if (angular.isUndefined(scope.config.expand)) {
|
||||||
scope.config.expand = true;
|
scope.config.expand = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setColumnPermitted(scope.config.columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setColumnPermitted(columns) {
|
||||||
|
|
||||||
|
angular.forEach(columns, checkPermissions);
|
||||||
|
|
||||||
|
function checkPermissions(column) {
|
||||||
|
if (column.permitted === true || column.permitted === false) {
|
||||||
|
// No need to check again
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
permissionsService.checkAll(column).then(allow, disallow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function allow() {
|
||||||
|
column.permitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function disallow() {
|
||||||
|
column.permitted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
class="rsp-p{$ column.priority $}"
|
class="rsp-p{$ column.priority $}"
|
||||||
st-sort="{$ column.id $}"
|
st-sort="{$ column.id $}"
|
||||||
ng-attr-st-sort-default="{$ column.sortDefault $}"
|
ng-attr-st-sort-default="{$ column.sortDefault $}"
|
||||||
translate>
|
translate
|
||||||
|
ng-if="column.permitted">
|
||||||
{$ column.title $}
|
{$ column.title $}
|
||||||
</th>
|
</th>
|
||||||
<th ng-if="itemActions"></th>
|
<th ng-if="itemActions"></th>
|
||||||
@ -69,7 +70,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td ng-repeat="column in config.columns"
|
<td ng-repeat="column in config.columns"
|
||||||
class="rsp-p{$ column.priority $}">
|
class="rsp-p{$ column.priority $}"
|
||||||
|
ng-if="column.permitted">
|
||||||
<hz-cell table="table" column="column" item="item"></hz-cell>
|
<hz-cell table="table" column="column" item="item"></hz-cell>
|
||||||
</td>
|
</td>
|
||||||
<td ng-if="itemActions" class="actions_column">
|
<td ng-if="itemActions" class="actions_column">
|
||||||
|
138
openstack_dashboard/static/app/core/conf/conf.module.js
Normal file
138
openstack_dashboard/static/app/core/conf/conf.module.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/**
|
||||||
|
* (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License. You may obtain
|
||||||
|
* a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc overview
|
||||||
|
* @ngname horizon.app.core.conf
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Provides features that support app configuration.
|
||||||
|
*/
|
||||||
|
angular
|
||||||
|
.module('horizon.app.core.conf', ['horizon.framework.conf'])
|
||||||
|
.config(permissionsDecorator);
|
||||||
|
|
||||||
|
permissionsDecorator.$inject = [
|
||||||
|
'$provide'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name permissionsDecorator
|
||||||
|
* @param {Object} $provide
|
||||||
|
* @description
|
||||||
|
* This decorates the horizon.framework.conf.permissions service to
|
||||||
|
* support declarative level permissions based on openstack_dashboard requirements.
|
||||||
|
* This adds the following declarative permissions:
|
||||||
|
* 'services' (OpenStack services that must be enabled in the current region),
|
||||||
|
* 'settings' (OpenStack Dashboard settings that must be enabled)
|
||||||
|
* 'policies' (policy rules that must be allowed)
|
||||||
|
*
|
||||||
|
* For example, these may all be used with the registry service and table column registrations.
|
||||||
|
* They are passed through to hz-dynamic-table which asks the permissions service to check
|
||||||
|
* the column's permissions before displaying each column. Below is a pseudo example where you
|
||||||
|
* want to show the instance compute host only if the user is an admin. So you'd create a policy
|
||||||
|
* rule for checking if the user is an admin and add that check here. Or you'd want to only
|
||||||
|
* show the volume column if Cinder (the volume service) is enabled.
|
||||||
|
*
|
||||||
|
* registry.getResourceType('OS::Nova::Server')
|
||||||
|
.tableColumns
|
||||||
|
.append({
|
||||||
|
id: 'host',
|
||||||
|
priority: 1,
|
||||||
|
policies: [{rules: [['compute', 'compute:is_admin']]}]
|
||||||
|
})
|
||||||
|
.append({
|
||||||
|
id: 'volumes',
|
||||||
|
priority: 2,
|
||||||
|
services: "volume"
|
||||||
|
})
|
||||||
|
*
|
||||||
|
* 'policies' may be set to a single object or an array of rules objects.
|
||||||
|
*
|
||||||
|
* All of the following are examples:
|
||||||
|
*
|
||||||
|
* policies = { rules: [["identity", "identity:get_project"]] }
|
||||||
|
* policies = [{ rules: [["identity", "identity:get_project"]] }, { <rule 2>}]
|
||||||
|
*
|
||||||
|
* 'services' may by set to a single service type or an array of service types.
|
||||||
|
* This may be done inline or may come from an object in scope.
|
||||||
|
*
|
||||||
|
* All of the following are valid examples:
|
||||||
|
*
|
||||||
|
* services="network"
|
||||||
|
* services=["network"]
|
||||||
|
* services=["network", "metering"]
|
||||||
|
*
|
||||||
|
* 'settings' Additional info. In local_settings.py allows you to specify settings such as:
|
||||||
|
*
|
||||||
|
* OPENSTACK_HYPERVISOR_FEATURES = {
|
||||||
|
* 'can_set_mount_point': True,
|
||||||
|
* 'can_set_password': False,
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* To access a specific setting, use a simplified path where a . (dot)
|
||||||
|
* separates elements in the path. So in the above example, the paths
|
||||||
|
* would be:
|
||||||
|
*
|
||||||
|
* OPENSTACK_HYPERVISOR_FEATURES.can_set_mount_point
|
||||||
|
* OPENSTACK_HYPERVISOR_FEATURES.can_set_password
|
||||||
|
*
|
||||||
|
* The `settings` attribute may be set to a single setting path
|
||||||
|
* or an array of setting paths. All of the following are examples:
|
||||||
|
*
|
||||||
|
* settings="SETTING_GROUP.my_setting_1"
|
||||||
|
* settings=["SETTING_GROUP.my_setting_1"]
|
||||||
|
* settings=["SETTING_GROUP.my_setting_1", "SETTING_GROUP.my_setting_2"]
|
||||||
|
*
|
||||||
|
* The desired setting must be listed in one of the two following locations
|
||||||
|
* in settings.py or local_settings.py in order for it to be available
|
||||||
|
* to the client side for evaluation. If it is not, it will always evaluate
|
||||||
|
* to false.
|
||||||
|
*
|
||||||
|
* REST_API_REQUIRED_SETTINGS
|
||||||
|
* REST_API_REQUIRED_SETTINGS
|
||||||
|
*
|
||||||
|
* This directive currently only supports settings that are set to
|
||||||
|
* true or false. So currently, you only need to provide the path to
|
||||||
|
* the setting. Future enhancements should allow for alternatively providing
|
||||||
|
* an object or array of objects with the path and expected value:
|
||||||
|
* {path:"SOME_setting_1", expected:"1.0"}.
|
||||||
|
*/
|
||||||
|
function permissionsDecorator($provide) {
|
||||||
|
$provide.decorator('horizon.framework.conf.permissions.service',
|
||||||
|
['$delegate',
|
||||||
|
'horizon.app.core.openstack-service-api.policy',
|
||||||
|
'horizon.app.core.openstack-service-api.serviceCatalog',
|
||||||
|
'horizon.app.core.openstack-service-api.settings',
|
||||||
|
decorator]);
|
||||||
|
|
||||||
|
function decorator($delegate, policy, serviceCatalog, settings) {
|
||||||
|
var permissionsService = $delegate;
|
||||||
|
|
||||||
|
permissionsService.extendedPermissions = {
|
||||||
|
policies: policy.ifAllowed,
|
||||||
|
services: serviceCatalog.ifTypeEnabled,
|
||||||
|
settings: settings.ifEnabled
|
||||||
|
};
|
||||||
|
|
||||||
|
return $delegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
@ -31,6 +31,7 @@
|
|||||||
*/
|
*/
|
||||||
angular
|
angular
|
||||||
.module('horizon.app.core', [
|
.module('horizon.app.core', [
|
||||||
|
'horizon.app.core.conf',
|
||||||
'horizon.app.core.cloud-services',
|
'horizon.app.core.cloud-services',
|
||||||
'horizon.app.core.images',
|
'horizon.app.core.images',
|
||||||
'horizon.app.core.metadata',
|
'horizon.app.core.metadata',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user