built.io
Version:
SDK for Built.io Backend
482 lines (464 loc) • 15 kB
JavaScript
/*
TO DO
// make constant strings
// can do
*/
var R = require('ramda');
var utility = require('./utilities/utility');
var instanceMethodBuilder = require('./utilities/instanceMethodBuilder')();
var getData = R.prop('data');
var getOthers = R.compose(R.prop('others'),getData);
/**
* @class ACL
* @classdesc
* Access Control List (ACL) allows you to control who can access the content of your application.
* @description
* Use this to get an ACL instance which can then be passed to any method that accepts an ACL instance as argument.
* @param {object} data Plain JavaScript object specifying initial ACL.
* @example
* // Constructor with blank ACL
* var acl = Built.ACL();
* //Constructor with initial ACL
* var acl = Built.ACL({
* others:{
* read:true
* }
* })
* @return {ACL}
*/
var aclCons = module.exports = function(data) {
var newData = R.mixin({},data);
if (!data.users || !utility.isArray(data.users)) //setting blank array if nothing already exist
newData.users = [];
if (!data.roles || !utility.isArray(data.roles))
newData.roles = [];
if (!data.others || !utility.isObject(data.others))
newData.others = {};
if(!data.can || !utility.isArray(data.can))
newData.can = [];
var returnObj = {
toJSON:function(){
return data;
},
data: newData
}
return instanceMethodBuilder.build(module.exports,returnObj);
};
var setWithUid = R.curry(function(permision,type,uid,allowed,acl){
var newData = getClonedData(acl);
newData[type] = [].concat(acl.data[type]);
var perForUid = R.mixin({},R.find(R.propEq('uid',uid),getData(acl)[type]));
if(perForUid.uid){
newData[type] = removeItem(perForUid,newData[type]); // removes the item and returns new array
perForUid[permision] = allowed;
newData[type].push(perForUid);
}
else{
var newObj = {};
newObj['uid'] = uid;
newObj[permision] = allowed;
newData[type].push(newObj);
}
return aclCons(newData);
});
/**
* Checks whether the object can be deleted by anyone
* @function getPublicDeleteAccess
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.getPublicDeleteAccess();
* @return {Boolean}
*/
module.exports.getPublicDeleteAccess = function(acl) {
return !!getOthers(acl).delete;
}
instanceMethodBuilder.define('getPublicDeleteAccess',1);
/**
* Determines whether the object can be read by anyone
* @function getPublicReadAccess
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.getPublicReadAccess();
* @return {Boolean}
*/
module.exports.getPublicReadAccess = function(acl) {
return !!getOthers(acl).read;
}
instanceMethodBuilder.define('getPublicReadAccess',1);
/**
* Determines whether the object can be updated by anyone
* @function getPublicUpdateAccess
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.getPublicUpdateAccess();
* @return {Boolean}
*/
module.exports.getPublicUpdateAccess = function(acl) {
return !!getOthers(acl).update;
}
instanceMethodBuilder.define('getPublicUpdateAccess',1);
/**
* Determines whether the user with the given role is allowed to delete the object. Even if this returns false,
* the user may still be able to access it, if getPublicDeleteAccess() returns true, or if the user belongs to another role that has delete access.
* @function getRoleDeleteAccess
* @param {String} uid Role's uid
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.getRoleDeleteAccess('uid');
* @return {Boolean}
*/
module.exports.getRoleDeleteAccess = R.curry(function(uid,acl){
return findWithUid(uid,'roles',acl).delete;
});
instanceMethodBuilder.define('getRoleDeleteAccess',2);
/**
* Determines whether the user with the given role is allowed to read the object. Even if this returns false,
* the user may still be able to read it, if getPublicReadAccess() returns true, or if the user belongs to another role that has read access.
* @function getRoleReadAccess
* @param {String} uid Role's uid
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.getRoleReadAccess('uid');
* @return {Boolean}
*/
module.exports.getRoleReadAccess = R.curry(function(uid,acl){
return findWithUid(uid,'roles',acl).read;
});
instanceMethodBuilder.define('getRoleReadAccess',2);
/**
* Determines whether the user with the given role is allowed to update this object. Even if this returns false,
* the user may still be able to update it, if getPublicUpdateAccess() returns true, or if the user belongs to another role that has update access.
* @function getRoleUpdateAccess
* @param {String} uid Role's uid
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.getRoleUpdateAccess('uid');
* @return {Boolean}
*/
module.exports.getRoleUpdateAccess = R.curry(function(uid,acl){
return findWithUid(uid,'roles',acl).update;
})
instanceMethodBuilder.define('getRoleUpdateAccess',2);
/**
* Checks whether the user is allowed to delete the object. Even if this returns false,
* the user may still be able to delete it, if getPublicDeleteAccess() returns true, or if the user belongs to a role that has delete access.
* @function getUserDeleteAccess
* @param {String} uid Role's uid
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.getUserDeleteAccess('uid');
* @return {Boolean}
*/
module.exports.getUserDeleteAccess = R.curry(function(uid,acl){
return findWithUid(uid,'users',acl).delete;
})
instanceMethodBuilder.define('getUserDeleteAccess',2);
/**
* Determines whether the user is allowed to read the object. Even if this returns false,
* the user may still be able to read it, if getPublicReadAccess() returns true, or if the user belongs to a role that has read access.
* @function getUserReadAccess
* @memberof ACL
* @param {String} uid Application User's uid
* @instance
* @example
* var acl = Built.ACL();
* var boolean = acl.getUserReadAccess('uid');
* @return {Boolean}
*/
module.exports.getUserReadAccess = R.curry(function(uid,acl){
return findWithUid(uid,'users',acl).read;
})
instanceMethodBuilder.define('getUserReadAccess',2);
/**
* Determines whether the user is allowed to update this object. Even if this returns false,
* the user may still be able to update it, if getPublicUpdateAccess() returns true, or if the user belongs to a role that has update access.
* @function getUserUpdateAccess
* @param {String} uid Application User's uid
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.getUserUpdateAccess('uid');
* @return {Boolean}
*/
module.exports.getUserUpdateAccess = R.curry(function(uid,acl){
return findWithUid(uid,'users',acl).update;
})
instanceMethodBuilder.define('getUserUpdateAccess',2);
/**
* Determines whether the ACL is disabled or not
* @function isDisabled
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.isDisabled();
* @return {Boolean}
*/
module.exports.isDisabled = function(acl){
return !!getData(acl).disable;
}
instanceMethodBuilder.define('isDisabled',1);
/**
* Sets whether users' falling into 'others' category are allowed to delete this object or not
* @function setPublicDeleteAccess
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setPublicDeleteAccess(true);
* @return {ACL}
*/
module.exports.setPublicDeleteAccess = R.curry(function(allowed,acl){
var newData = getClonedData(acl);
newData.others = R.mixin({},acl.data.others);
newData.others['delete'] = allowed; //Others won't be undefined as we have handled it in constructor
return aclCons(newData);
});
instanceMethodBuilder.define('setPublicDeleteAccess',2);
/**
* Sets whether users' falling into 'others' category are allowed to update this object or not
* @function setPublicUpdateAccess
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setPublicUpdateAccess(true);
* @return {ACL}
*/
module.exports.setPublicUpdateAccess = R.curry(function(allowed,acl){
var newData = getClonedData(acl);
newData.others = R.mixin({},acl.data.others);
newData.others['update'] = allowed; //Others won't be undefined as we have handled it in constructor
return aclCons(newData);
});
instanceMethodBuilder.define('setPublicUpdateAccess',2);
/**
* Sets whether users' falling into 'others' category are allowed to read access or not
* @function setPublicReadAccess
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setPublicReadAccess(true);
* @return {ACL}
*/
module.exports.setPublicReadAccess = R.curry(function(allowed,acl){
var newData = getClonedData(acl);
newData.others = R.mixin({},acl.data.others);
newData.others['read'] = allowed; //Others won't be undefined as we have handled it in constructor
return aclCons(newData);
});
instanceMethodBuilder.define('setPublicReadAccess',2);
/**
* Delete permission will be assigned/unassigned to the role whose uid is provided
* @function setRoleDeleteAccess
* @param {String} uid Uid of role
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setRoleDeleteAccess('uid',true);
* @return {ACL}
*/
module.exports.setRoleDeleteAccess = setWithUid('delete','roles');
instanceMethodBuilder.define('setRoleDeleteAccess',3);
/**
* Update permission will be assigned/unassigned to the role whose uid is provided
* @function setRoleUpdateAccess
* @param {String} uid Uid of role
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setRoleUpdateAccess('uid',true);
* @return {ACL}
*/
module.exports.setRoleUpdateAccess = setWithUid('update','roles');
instanceMethodBuilder.define('setRoleUpdateAccess',3);
/**
* Read permission will be assigned/unassigned to the role whose uid is provided
* @function setRoleReadAccess
* @param {String} uid Uid of role
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setRoleReadAccess('uid',true);
* @return {ACL}
*/
module.exports.setRoleReadAccess = setWithUid('read','roles');
instanceMethodBuilder.define('setRoleReadAccess',3);
/**
* Delete permission will be assigned/unassigned to the user whose uid is provided
* @function setUserDeleteAcces
* @param {String} uid Uid of user
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setUserDeleteAccess('uid',true);
* @return {ACL}
*/
module.exports.setUserDeleteAccess = setWithUid('delete','users');
instanceMethodBuilder.define('setUserDeleteAccess',3);
/**
* Update permission will be assigned/unassigned to the user whose uid is provided
* @function setUserUpdateAccess
* @param {String} uid Uid of user
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setUserUpdateAccess('uid',true);
* @return {ACL}
*/
module.exports.setUserUpdateAccess = setWithUid('update','users');
instanceMethodBuilder.define('setUserUpdateAccess',3);
/**
* Read permission will be assigned/unassigned to the user whose uid is provided
* @function setUserReadAccess
* @param {String} uid Uid of user
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setUserReadAccess('uid',true);
* @return {ACL}
*/
module.exports.setUserReadAccess = setWithUid('read','users');
instanceMethodBuilder.define('setUserReadAccess',3);
/**
* Delete permission will be assigned/unassigned to the anonymous users(non logged-in users).
* @function setAnonymousDeleteAccess
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setAnonymousDeleteAccess(true);
* @return {ACL}
*/
module.exports.setAnonymousDeleteAccess = module.exports.setUserDeleteAccess('anonymous');
instanceMethodBuilder.define('setAnonymousDeleteAccess',2);
/**
* Update permission will be assigned/unassigned to the anonymous users(non logged-in users).
* @function setAnonymousUpdateAccess
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setAnonymousUpdateAccess(true);
* @return {ACL}
*/
module.exports.setAnonymousUpdateAccess = module.exports.setUserUpdateAccess('anonymous');
instanceMethodBuilder.define('setAnonymousUpdateAccess',2);
/**
* Read permission will be assigned/unassigned to the anonymous users(non logged-in users).
* @function setAnonymousReadAccess
* @param {Boolean} allowed Access allowed or not (true|false)
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* acl = acl.setAnonymousReadAccess(true);
* @return {ACL}
*/
module.exports.setAnonymousReadAccess = module.exports.setUserReadAccess('anonymous');
instanceMethodBuilder.define('setAnonymousReadAccess',2);
/**
*Disables ACL.
*@function disable
*@instance
*@memberof ACL
*@example
*var acl = Built.ACL();
*acl = acl.disable();
*@return {ACL}
*/
module.exports.disable = function(acl){
var newData = R.mixin({},getData(acl));
newData['disable'] = true;
return aclCons(newData);
}
instanceMethodBuilder.define('disable',1);
/**
*Enables ACL
*@function enable
*@instance
*@memberof ACL
*@example
*var acl = Built.ACL();
*acl = acl.enable();
*@return {ACL}
*/
module.exports.enable = function(acl){
var newData = R.mixin({},getData(acl));
newData['disable'] = false;
return aclCons(newData);
}
instanceMethodBuilder.define('enable',1);
/**
* Tells whether the user has update access
* @function canUpdate
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.canUpdate();
* @return {Boolean}
*/
module.exports.canUpdate = function(acl){
return (getData(acl).can.indexOf('update') > -1);
}
instanceMethodBuilder.define('canUpdate',1);
/**
* Tells whether the user has delete access
* @function canDelete
* @instance
* @memberof ACL
* @example
* var acl = Built.ACL();
* var boolean = acl.canDelete();
* @return {Boolean}
*/
module.exports.canDelete = function(acl){
return (getData(acl).can.indexOf('delete') > -1);
}
instanceMethodBuilder.define('canDelete',1);
function getClonedData(acl){
return R.mixin({},getData(acl));
}
function findWithUid(uid,type,acl) {
return R.find(R.where({
uid: uid
}), acl.data[type]) || {};
}
function removeItem(item, list) {
var index = R.indexOf(item.uid, R.map(R.prop('uid'), list))
return R.remove(index, 1, list);
}