ACLs , permisos a nivel de rutas, menu y componentes

This commit is contained in:
Dani Herrero 2017-05-25 11:48:10 +02:00
parent 3c54a222b9
commit 81f9de098d
10 changed files with 136 additions and 47 deletions

View File

@ -17,8 +17,10 @@
"params": { "params": {
"client": "card.client" "client": "card.client"
}, },
"menu": {
"description": "Datos básicos", "description": "Datos básicos",
"icon": "person" "icon": "person"
}
}, { }, {
"url": "/fiscal-data", "url": "/fiscal-data",
"state": "clientCard.fiscalData", "state": "clientCard.fiscalData",
@ -26,8 +28,10 @@
"params": { "params": {
"client": "card.client" "client": "card.client"
}, },
"menu": {
"description": "Datos fiscales", "description": "Datos fiscales",
"icon": "account_balance" "icon": "account_balance"
}
}, { }, {
"url": "/billing-data", "url": "/billing-data",
"state": "clientCard.billingData", "state": "clientCard.billingData",
@ -35,8 +39,10 @@
"params": { "params": {
"client": "card.client" "client": "card.client"
}, },
"menu": {
"description": "Datos facturación", "description": "Datos facturación",
"icon": "assignment" "icon": "assignment"
}
},{ },{
"url": "/addresses", "url": "/addresses",
"state": "clientCard.addresses", "state": "clientCard.addresses",
@ -49,8 +55,10 @@
"params": { "params": {
"client": "card.client" "client": "card.client"
}, },
"menu": {
"description": "Consignatarios", "description": "Consignatarios",
"icon": "local_shipping" "icon": "local_shipping"
}
}, { }, {
"url": "/create", "url": "/create",
"state": "clientCard.addresses.create", "state": "clientCard.addresses.create",
@ -66,8 +74,10 @@
"params": { "params": {
"client": "card.client" "client": "card.client"
}, },
"menu": {
"description": "Acceso web", "description": "Acceso web",
"icon": "language" "icon": "language"
}
},{ },{
"url": "/notes", "url": "/notes",
"state": "clientCard.notes", "state": "clientCard.notes",
@ -80,8 +90,11 @@
"params": { "params": {
"client": "card.client" "client": "card.client"
}, },
"menu": {
"description": "Notas", "description": "Notas",
"icon": "insert_drive_file" "icon": "insert_drive_file"
}
}, { }, {
"url": "/create", "url": "/create",
"state": "clientCard.notes.create", "state": "clientCard.notes.create",

View File

@ -10,7 +10,7 @@
<vn-vertical pad-large> <vn-vertical pad-large>
<vn-title>Datos básicos</vn-title> <vn-title>Datos básicos</vn-title>
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Nombre" field="$ctrl.client.name" vn-focus></vn-textfield> <vn-textfield vn-one label="Nombre" field="$ctrl.client.name" vn-focus vn-acl="prueba"></vn-textfield>
<vn-textfield vn-one label="NIF/CIF" field="$ctrl.client.fi"></vn-textfield> <vn-textfield vn-one label="NIF/CIF" field="$ctrl.client.fi"></vn-textfield>
<vn-textfield autofocus vn-one label="Razón social" field="$ctrl.client.socialName"></vn-textfield> <vn-textfield autofocus vn-one label="Razón social" field="$ctrl.client.socialName"></vn-textfield>
</vn-horizontal> </vn-horizontal>

View File

@ -2,7 +2,7 @@
<mg-ajax path="/client/api/Clients/{{edit.params.id}}/card" options="mgEdit" actions="card.client=edit.model;"></mg-ajax> <mg-ajax path="/client/api/Clients/{{edit.params.id}}/card" options="mgEdit" actions="card.client=edit.model;"></mg-ajax>
<vn-empty style="min-width: 18em; padding-left: 1em; padding-bottom: 1em;"> <vn-empty style="min-width: 18em; padding-left: 1em; padding-bottom: 1em;">
<vn-descriptor client="card.client" active="card.client.active" class="display-block" ></vn-descriptor> <vn-descriptor client="card.client" active="card.client.active" class="display-block" ></vn-descriptor>
<vn-left-menu items="card.items"></vn-left-menu> <vn-left-menu></vn-left-menu>
</vn-empty> </vn-empty>
<vn-auto> <vn-auto>
<vn-vertical style="max-width: 70em; margin: 0 auto;" ui-view></vn-vertical> <vn-vertical style="max-width: 70em; margin: 0 auto;" ui-view></vn-vertical>

View File

@ -6,22 +6,10 @@ export const NAME = 'vnClientCard';
export default class vnClientCard { export default class vnClientCard {
constructor() { constructor() {
this.client = null; this.client = null;
this.items = [];
this.init();
}
init() {
routes.client.routes.forEach(i => {
if (i.description)
this.items.push({
description: i.description,
icon: i.icon,
href: i.state
});
});
} }
} }
module.component(NAME, { module.component(NAME, {
template: require('./index.html'), template: require('./index.html'),
controllerAs: 'card', controllerAs: 'card',

View File

@ -0,0 +1,23 @@
import {module} from '../module';
function vnAcl(aclService, $compile) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
let acls = attrs.vnAcl.split(',');
let action = attrs.vnAclAction || 'disabled';
if (!aclService.aclPermission(acls)) {
if (action === 'disabled') {
let input = element[0].querySelector('input');
input.setAttribute("ng-disabled", "true");
$compile(input)(scope);
} else {
element.remove();
}
}
}
};
}
vnAcl.$inject = ['aclService', '$compile'];
module.directive('vnAcl', vnAcl);

View File

@ -2,3 +2,4 @@ import './id';
import './focus'; import './focus';
import './dialog'; import './dialog';
import './validation'; import './validation';
import './acl';

View File

@ -75,3 +75,29 @@ function interceptorConfig($httpProvider) {
$httpProvider.interceptors.push('vnAppInterceptor'); $httpProvider.interceptors.push('vnAppInterceptor');
} }
ngModule.config(interceptorConfig); ngModule.config(interceptorConfig);
function aclService() {
this.roles = window.Salix.acl.roles;
this.routeHasPermission = function(route) {
let hasPermission;
if (!route.acl)
hasPermission = true;
else if (!this.roles || !Object.keys(this.roles).length)
hasPermission = false;
else
hasPermission = this.aclPermission(route.acl);
return hasPermission;
};
this.aclPermission = function(aclCollection) {
let hasPermission = false;
let total = aclCollection.length;
for (let i = 0; i < total; i++) {
if (this.roles[aclCollection[i]]) {
hasPermission = true;
break;
}
}
return hasPermission;
};
}
ngModule.service('aclService', aclService);

View File

@ -1,9 +1,31 @@
import ngModule from '../../module'; import ngModule from '../../module';
import './style.css'; import './style.css';
export default class vnLeftMenu {
constructor(aclService, $state) {
this.aclService = aclService;
this.$state = $state;
this.items = [];
this.init();
}
init() {
let station = this.$state.current.data.station || 'default';
if (routes[station]) {
routes[station].routes.forEach(i => {
if (i.menu && this.aclService.routeHasPermission(i))
this.items.push({
description: i.menu.description,
icon: i.menu.icon,
href: i.state
});
});
}
}
}
vnLeftMenu.$inject = ['aclService', '$state'];
ngModule.component('vnLeftMenu', { ngModule.component('vnLeftMenu', {
template: require('./left-menu.html'), template: require('./left-menu.html'),
bindings: { controller: vnLeftMenu
items: '<'
}
}); });

View File

@ -11,9 +11,10 @@ function loader(moduleName) {
return load; return load;
} }
config.$inject = ['$stateProvider', '$urlRouterProvider']; config.$inject = ['$stateProvider', '$urlRouterProvider', 'aclServiceProvider'];
function config($stateProvider, $urlRouterProvider) { function config($stateProvider, $urlRouterProvider, aclServiceProvider) {
splitingRegister.registerGraph(deps); splitingRegister.registerGraph(deps);
let aclService = aclServiceProvider.$get();
function getParams(route) { function getParams(route) {
let params = ''; let params = '';
@ -34,16 +35,20 @@ function config($stateProvider, $urlRouterProvider) {
for (let file in routes) { for (let file in routes) {
let fileRoutes = routes[file].routes; let fileRoutes = routes[file].routes;
let moduleName = routes[file].module; let moduleName = routes[file].module;
fileRoutes.forEach(function(route) { fileRoutes.forEach(function(route) {
if (aclService.routeHasPermission(route)) {
$stateProvider.state(route.state, { $stateProvider.state(route.state, {
url: route.url, url: route.url,
abstract: route.abstract || false, abstract: route.abstract || false,
template: `<${route.component} ${getParams(route)}></${route.component}>`, template: `<${route.component} ${getParams(route)}></${route.component}>`,
resolve: { resolve: {
loader: loader(moduleName) loader: loader(moduleName)
},
data: {
station: file
} }
}); });
}
}); });
} }
} }

View File

@ -63,20 +63,31 @@ module.exports = function (app) {
"principalId": `${app.currentUser.id}`, "principalId": `${app.currentUser.id}`,
"principalType": "USER" "principalType": "USER"
}, },
"include": { "include": [{
"relation": "role", "relation": "role",
"scope": { "scope": {
"fields": ["name"] "fields": ["name"]
} }
},
{
"relation": "user",
"scope": {
"fields": ["id", "username"]
} }
}]
}; };
app.models.RoleMapping.belongsTo(app.models.User, {foreignKey: 'principalId', as: 'user'});
app.models.RoleMapping.find(query, function(err, roles){ app.models.RoleMapping.find(query, function(err, roles){
if(roles){ if(roles){
let acl = {}; let acl = {
userProfile: {},
roles: {}
};
acl.userProfile = roles[0].user();
Object.keys(roles).forEach(function(_, i){ Object.keys(roles).forEach(function(_, i){
if(roles[i].roleId){ if(roles[i].roleId){
let rol = roles[i].role(); let rol = roles[i].role();
acl[rol.name] = true; acl.roles[rol.name] = true;
} }
}); });
sendACL(res, acl); sendACL(res, acl);