baja/obj/Permissions.js

/**
 * @copyright 2015 Tridium, Inc. All Rights Reserved.
 * @author Gareth Johnson
 */

/**
 * Defines {@link baja.Permissions}.
 * @module baja/obj/Permissions
 */
define([ "bajaScript/sys",
        "bajaScript/baja/obj/Simple",
        "bajaScript/baja/obj/objUtil" ], 
        function (baja, Simple, objUtil) {
  
  "use strict";
  
  var subclass = baja.subclass,
      callSuper = baja.callSuper,
      
      cacheDecode = objUtil.cacheDecode,
      cacheEncode = objUtil.cacheEncode;
  
  /**
   * Permissions for a given security domain.
   * 
   * This Constructor shouldn't be invoked directly. Please use the `make()` 
   * methods to create an instance of a `Permissions` Object. 
   *
   * @class
   * @alias baja.Permissions
   * @extends baja.Simple
   */
  var Permissions = function Permissions(mask) {
    callSuper(Permissions, this, arguments); 
    this.$mask = mask;
  };
  
  subclass(Permissions, Simple);
    
  var OPERATOR_READ = 0x0001,
      OPERATOR_WRITE = 0x0002,
      OPERATOR_INVOKE = 0x0004,
      ADMIN_READ = 0x0010,
      ADMIN_WRITE = 0x0020,
      ADMIN_INVOKE = 0x0040,
      permissionsAllMask = OPERATOR_READ | OPERATOR_WRITE | OPERATOR_INVOKE | ADMIN_READ | ADMIN_WRITE | ADMIN_INVOKE,
      permissionsCache = {},
      permissionsNone = new Permissions(0),
      permissionsAll = new Permissions(permissionsAllMask);
  
      permissionsCache[0] = permissionsNone;
      permissionsCache[permissionsAllMask] = permissionsAll;

  
  /**
   * Operator read mask.
   * @type {Number}
   */
  Permissions.OPERATOR_READ = OPERATOR_READ;
  
  /**
   * Operator write mask.
   * @type {Number}
   */
  Permissions.OPERATOR_WRITE = OPERATOR_WRITE;
  
  /**
   * Operator invoke mask.
   * @type {Number}
   */
  Permissions.OPERATOR_INVOKE = OPERATOR_INVOKE;
  
  /**
   * Admin read mask.
   * @type {Number}
   */
  Permissions.ADMIN_READ = ADMIN_READ;
  
  /**
   * Admin write mask.
   * @type {Number}
   */
  Permissions.ADMIN_WRITE = ADMIN_WRITE;
  
  /**
   * Admin invoke mask.
   * @type {Number}
   */
  Permissions.ADMIN_INVOKE = ADMIN_INVOKE;
  
  /**
   * No permissions.
   * @type {baja.Permissions}
   */
  Permissions.none = permissionsNone;
  
  /**
   * Default permissions instance (none).
   * @type {baja.Permissions}
   */
  Permissions.DEFAULT = permissionsNone;
  
  /**
   * All permissions.
   * @type {baja.Permissions}
   */
  Permissions.all = permissionsAll;
  
  
  /**
   * Make a permissions object.
   *
   * @param {String|Number} perm the permissions to decode.
   * @returns {baja.Permissions}
   */
  Permissions.prototype.make = function (perm) {
    var mask = 0,
        i,
        p;
        
    if (typeof perm === "string") {        
      for (i = 0; i < perm.length; ++i) {
        switch (perm.charAt(i)) {
          case "i": mask |= OPERATOR_INVOKE; break;
          case "r": mask |= OPERATOR_READ; break;
          case "w": mask |= OPERATOR_WRITE; break;
          case "I": mask |= ADMIN_INVOKE; break;
          case "R": mask |= ADMIN_READ; break;
          case "W": mask |= ADMIN_WRITE; break;
        }
      }
    } else {
      mask = perm;
    }
    
    // Get permissions from cache
    if (permissionsCache[mask]) {
      p = permissionsCache[mask];
    } else {
      p = permissionsCache[mask] = new Permissions(mask);
    }
    return p;
  };
  
  /**
   * Make a permissions object.
   *
   * @param {String|Number} perm the permissions to decode.
   * @returns {baja.Permissions}
   */
  Permissions.make = function (perm) {
    return Permissions.DEFAULT.make.apply(baja.Permissions.DEFAULT, arguments);
  };
  
  /**
   * Decode `Permissions` from a `String`.
   *
   * @method
   * @returns {baja.Permissions}
   */  
  Permissions.prototype.decodeFromString = cacheDecode(function (s) {
    return this.make(s);
  });
  
  /**
   * Encode `Permissions` to a `String`.
   *
   * @method
   * @returns {String}
   */  
  Permissions.prototype.encodeToString = cacheEncode(function () {
    var s = "";
    if (this.hasOperatorRead()) {
      s += "r";
    }
    if (this.hasOperatorWrite()) {
      s += "w";
    }
    if (this.hasOperatorInvoke()) {
      s += "i";
    }
    if (this.hasAdminRead()) {
      s += "R";
    }
    if (this.hasAdminWrite()) {
      s += "W";
    }
    if (this.hasAdminInvoke()) {
      s += "I";
    }
    return s;
  });
  
  /**
   * Return a `String` representation of the `Permissions`.
   *
   * @returns {String}
   */
  Permissions.prototype.toString = function () {
    return this.encodeToString();
  };
      
  /**
   * Is the operator read permission enabled?
   *
   * @returns {Boolean}
   */
  Permissions.prototype.hasOperatorRead = function () {
    return (this.$mask & OPERATOR_READ) !== 0;
  };
  
  /**
   * Is the operator write permission enabled?
   *
   * @returns {Boolean}
   */
  Permissions.prototype.hasOperatorWrite = function () {
    return (this.$mask & OPERATOR_WRITE) !== 0;
  };
  
  /**
   * Is the operator invoke permission enabled?
   *
   * @returns {Boolean}
   */
  Permissions.prototype.hasOperatorInvoke = function () {
    return (this.$mask & OPERATOR_INVOKE) !== 0;
  };
  
  /**
   * Is the admin read permission enabled?
   *
   * @returns {Boolean}
   */
  Permissions.prototype.hasAdminRead = function () {
    return (this.$mask & ADMIN_READ) !== 0;
  };
  
  /**
   * Is the admin write permission enabled?
   *
   * @returns {Boolean}
   */
  Permissions.prototype.hasAdminWrite = function () {
    return (this.$mask & ADMIN_WRITE) !== 0;
  };
  
  /**
   * Is the admin invoke permission enabled?
   *
   * @returns {Boolean}
   */
  Permissions.prototype.hasAdminInvoke = function () {
    return (this.$mask & ADMIN_INVOKE) !== 0;
  };
  
  /**
   * Return true if the specified permissions are enabled.
   *
   * @param {Number|baja.Permissions} mask
   * @returns {Boolean}
   */
  Permissions.prototype.has = function (mask) {
    if (mask && mask instanceof Permissions) {
      mask = mask.getMask();
    }
    return (this.$mask & mask) === mask;
  };

  /**
   * Return the mask for the permissions.
   *
   * @returns {Number}
   */
  Permissions.prototype.getMask = function () {
    return this.$mask;
  };

  /**
   * Create a new baja.Permissions from the bitwise OR of this baja.Permissions
   * instance and the specified baja.Permissions.
   *
   * @param {baja.Permissions} otherPermissions
   * @returns {baja.Permissions}
   */
  Permissions.prototype.or = function (otherPermissions) {
    return this.make(this.$mask | otherPermissions.$mask);
  };

  return Permissions;
});