@@ -65,6 +65,7 @@ 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+ backend . unionsAsync = bluebird . promisify ( backend . unions ) ;
6869} ;
6970
7071/**
@@ -424,13 +425,17 @@ Acl.prototype.removePermissions = function(role, resources, permissions, cb){
424425*/
425426Acl . prototype . allowedPermissions = function ( userId , resources , cb ) {
426427 if ( ! userId )
427- return cb ( null , [ ] ) ;
428+ return cb ( null , { } ) ;
428429
429430 contract ( arguments )
430431 . params ( 'string|number' , 'string|array' , 'function' )
431432 . params ( 'string|number' , 'string|array' )
432433 . end ( ) ;
433434
435+ if ( this . backend . unions ) {
436+ return this . optimizedAllowedPermissions ( userId , resources , cb ) ;
437+ }
438+
434439 var _this = this ;
435440 resources = makeArray ( resources ) ;
436441
@@ -446,6 +451,55 @@ Acl.prototype.allowedPermissions = function(userId, resources, cb){
446451 } ) . nodeify ( cb ) ;
447452} ;
448453
454+ /**
455+ optimizedAllowedPermissions( userId, resources, function(err, obj) )
456+
457+ Returns all the allowable permissions a given user have to
458+ access the given resources.
459+
460+ It returns a map of resource name to a list of permissions for that resource.
461+
462+ This is the same as allowedPermissions, it just takes advantage of the unions
463+ function if available to reduce the number of backend queries.
464+
465+ @param {String|Number } User id.
466+ @param {String|Array } resource(s) to ask permissions for.
467+ @param {Function } Callback called when finished.
468+ */
469+ Acl . prototype . optimizedAllowedPermissions = function ( userId , resources , cb ) {
470+ if ( ! userId ) {
471+ return cb ( null , { } ) ;
472+ }
473+
474+ contract ( arguments )
475+ . params ( 'string|number' , 'string|array' , 'function|undefined' )
476+ . params ( 'string|number' , 'string|array' )
477+ . end ( ) ;
478+
479+ resources = makeArray ( resources ) ;
480+ var self = this ;
481+
482+ return this . _allUserRoles ( userId ) . then ( function ( roles ) {
483+ var buckets = resources . map ( allowsBucket ) ;
484+ if ( roles . length === 0 ) {
485+ var emptyResult = { } ;
486+ buckets . forEach ( function ( bucket ) {
487+ emptyResult [ bucket ] = [ ] ;
488+ } ) ;
489+ return bluebird . resolve ( emptyResult ) ;
490+ }
491+
492+ return self . backend . unionsAsync ( buckets , roles ) ;
493+ } ) . then ( function ( response ) {
494+ var result = { } ;
495+ Object . keys ( response ) . forEach ( function ( bucket ) {
496+ result [ keyFromAllowsBucket ( bucket ) ] = response [ bucket ] ;
497+ } ) ;
498+
499+ return result ;
500+ } ) . nodeify ( cb ) ;
501+ } ;
502+
449503/**
450504 isAllowed( userId, resource, permissions, function(err, allowed) )
451505
@@ -644,7 +698,7 @@ Acl.prototype.middleware = function(numPathComponents, userId, actions){
644698 } else if ( allowed === false ) {
645699 if ( acl . logger ) {
646700 acl . logger . debug ( 'Not allowed ' + _actions + ' on ' + resource + ' by user ' + _userId ) ;
647- acl . allowedPermissions ( _userId , resource , function ( err , obj ) {
701+ acl . allowedPermissions ( _userId , resource , function ( err , obj ) {
648702 acl . logger . debug ( 'Allowed permissions: ' + util . inspect ( obj ) ) ;
649703 } ) ;
650704 }
@@ -748,7 +802,7 @@ Acl.prototype._allRoles = function(roleNames, cb){
748802// Return all roles in the hierarchy including the given roles.
749803//
750804Acl . prototype . _allRoles = function ( roleNames ) {
751- var _this = this , roles ;
805+ var _this = this ;
752806
753807 return this . _rolesParents ( roleNames ) . then ( function ( parents ) {
754808 if ( parents . length > 0 ) {
@@ -761,6 +815,21 @@ Acl.prototype._allRoles = function(roleNames){
761815 } ) ;
762816} ;
763817
818+ //
819+ // Return all roles in the hierarchy of the given user.
820+ //
821+ Acl . prototype . _allUserRoles = function ( userId ) {
822+ var _this = this ;
823+
824+ return this . userRoles ( userId ) . then ( function ( roles ) {
825+ if ( roles && roles . length > 0 ) {
826+ return _this . _allRoles ( roles ) ;
827+ } else {
828+ return [ ] ;
829+ }
830+ } ) ;
831+ } ;
832+
764833//
765834// Returns an array with resources for the given roles.
766835//
@@ -848,10 +917,12 @@ function allowsBucket(role){
848917 return 'allows_' + role ;
849918}
850919
920+ function keyFromAllowsBucket ( str ) {
921+ return str . replace ( / ^ a l l o w s _ / , '' ) ;
922+ }
923+
851924
852925// -----------------------------------------------------------------------------------
853926
854927
855928exports = module . exports = Acl ;
856-
857-
0 commit comments