@@ -65,6 +65,9 @@ var Acl = function (backend, logger, options){
6565 backend . getAsync = bluebird . promisify ( backend . get ) ;
6666 backend . cleanAsync = bluebird . promisify ( backend . clean ) ;
6767 backend . unionAsync = bluebird . promisify ( backend . union ) ;
68+ if ( backend . unions ) {
69+ backend . unionsAsync = bluebird . promisify ( backend . unions ) ;
70+ }
6871} ;
6972
7073/**
@@ -424,13 +427,17 @@ Acl.prototype.removePermissions = function(role, resources, permissions, cb){
424427*/
425428Acl . prototype . allowedPermissions = function ( userId , resources , cb ) {
426429 if ( ! userId )
427- return cb ( null , [ ] ) ;
430+ return cb ( null , { } ) ;
428431
429432 contract ( arguments )
430433 . params ( 'string|number' , 'string|array' , 'function' )
431434 . params ( 'string|number' , 'string|array' )
432435 . end ( ) ;
433436
437+ if ( this . backend . unionsAsync ) {
438+ return this . optimizedAllowedPermissions ( userId , resources , cb ) ;
439+ }
440+
434441 var _this = this ;
435442 resources = makeArray ( resources ) ;
436443
@@ -446,6 +453,55 @@ Acl.prototype.allowedPermissions = function(userId, resources, cb){
446453 } ) . nodeify ( cb ) ;
447454} ;
448455
456+ /**
457+ optimizedAllowedPermissions( userId, resources, function(err, obj) )
458+
459+ Returns all the allowable permissions a given user have to
460+ access the given resources.
461+
462+ It returns a map of resource name to a list of permissions for that resource.
463+
464+ This is the same as allowedPermissions, it just takes advantage of the unions
465+ function if available to reduce the number of backend queries.
466+
467+ @param {String|Number } User id.
468+ @param {String|Array } resource(s) to ask permissions for.
469+ @param {Function } Callback called when finished.
470+ */
471+ Acl . prototype . optimizedAllowedPermissions = function ( userId , resources , cb ) {
472+ if ( ! userId ) {
473+ return cb ( null , { } ) ;
474+ }
475+
476+ contract ( arguments )
477+ . params ( 'string|number' , 'string|array' , 'function|undefined' )
478+ . params ( 'string|number' , 'string|array' )
479+ . end ( ) ;
480+
481+ resources = makeArray ( resources ) ;
482+ var self = this ;
483+
484+ return this . _allUserRoles ( userId ) . then ( function ( roles ) {
485+ var buckets = resources . map ( allowsBucket ) ;
486+ if ( roles . length === 0 ) {
487+ var emptyResult = { } ;
488+ buckets . forEach ( function ( bucket ) {
489+ emptyResult [ bucket ] = [ ] ;
490+ } ) ;
491+ return bluebird . resolve ( emptyResult ) ;
492+ }
493+
494+ return self . backend . unionsAsync ( buckets , roles ) ;
495+ } ) . then ( function ( response ) {
496+ var result = { } ;
497+ Object . keys ( response ) . forEach ( function ( bucket ) {
498+ result [ keyFromAllowsBucket ( bucket ) ] = response [ bucket ] ;
499+ } ) ;
500+
501+ return result ;
502+ } ) . nodeify ( cb ) ;
503+ } ;
504+
449505/**
450506 isAllowed( userId, resource, permissions, function(err, allowed) )
451507
@@ -644,7 +700,7 @@ Acl.prototype.middleware = function(numPathComponents, userId, actions){
644700 } else if ( allowed === false ) {
645701 if ( acl . logger ) {
646702 acl . logger . debug ( 'Not allowed ' + _actions + ' on ' + resource + ' by user ' + _userId ) ;
647- acl . allowedPermissions ( _userId , resource , function ( err , obj ) {
703+ acl . allowedPermissions ( _userId , resource , function ( err , obj ) {
648704 acl . logger . debug ( 'Allowed permissions: ' + util . inspect ( obj ) ) ;
649705 } ) ;
650706 }
@@ -748,7 +804,7 @@ Acl.prototype._allRoles = function(roleNames, cb){
748804// Return all roles in the hierarchy including the given roles.
749805//
750806Acl . prototype . _allRoles = function ( roleNames ) {
751- var _this = this , roles ;
807+ var _this = this ;
752808
753809 return this . _rolesParents ( roleNames ) . then ( function ( parents ) {
754810 if ( parents . length > 0 ) {
@@ -761,6 +817,21 @@ Acl.prototype._allRoles = function(roleNames){
761817 } ) ;
762818} ;
763819
820+ //
821+ // Return all roles in the hierarchy of the given user.
822+ //
823+ Acl . prototype . _allUserRoles = function ( userId ) {
824+ var _this = this ;
825+
826+ return this . userRoles ( userId ) . then ( function ( roles ) {
827+ if ( roles && roles . length > 0 ) {
828+ return _this . _allRoles ( roles ) ;
829+ } else {
830+ return [ ] ;
831+ }
832+ } ) ;
833+ } ;
834+
764835//
765836// Returns an array with resources for the given roles.
766837//
@@ -848,10 +919,12 @@ function allowsBucket(role){
848919 return 'allows_' + role ;
849920}
850921
922+ function keyFromAllowsBucket ( str ) {
923+ return str . replace ( / ^ a l l o w s _ / , '' ) ;
924+ }
925+
851926
852927// -----------------------------------------------------------------------------------
853928
854929
855930exports = module . exports = Acl ;
856-
857-
0 commit comments