Name

sn_entitlement.RoleTypeInferer

Description

RoleTypeInferer

Script

var RoleTypeInferer = Class.create();
RoleTypeInferer.prototype = {
  TEXT_FULFILLER: 'fulfiller',
  TEXT_BUSINESS_STAKEHOLDER: 'business_stakeholder',
  TEXT_APPROVER: 'approver',
  TEXT_TIMECARD_USER: 'time_card_user',
  TEXT_REQUESTOR: 'requester',
  TEXT_ADMIN: 'admin',
  TEXT_NONE: 'none',
  TEXT_USER: 'user',
  TEXT_CONF_HIGH: 'h',
  TEXT_CONF_MED: 'm',
  TEXT_CONF_LOW: 'l',
  TEXT_CONF_NO: 'no',

  TABLE_TYPE_TASK: 'te',
  TABLE_TYPE_NON_TASK: 'nt',

  ACL_NOOP: 'n',
  ACL_UNRESTRICTED: 'u',
  ACL_RESTRICTED: 'r',
  ACL_USER_RESTRICTED: 'ur',
  ACL_APPROVER_RESTRICTED: 'a',
  ACL_UNKNOWN: 'ukn',

  initialize: function() {
      // TODO FIX cross referenced constants
      this.ACL_TASK_EXTENTION_NO_CONDITION = this.ACL_UNRESTRICTED + this.TABLE_TYPE_TASK;
      this.ACL_NON_TASK_EXTENTION_NO_CONDITION = this.ACL_UNRESTRICTED + this.TABLE_TYPE_NON_TASK;
      this.ACL_TASK_EXTENTION_WITH_CONDITION = this.ACL_RESTRICTED + this.TABLE_TYPE_TASK;
      this.ACL_NON_TASK_EXTENTION_WITH_CONDITION = this.ACL_RESTRICTED + this.TABLE_TYPE_NON_TASK;
      this.ACL_TASK_EXTENTION_WITH_APPROVER_CONDITION = this.ACL_APPROVER_RESTRICTED + this.TABLE_TYPE_TASK;
      this.ACL_TASK_EXTENTION_WITH_UNKNOWN = this.ACL_UNKNOWN + this.TABLE_TYPE_TASK;
      this.ACL_NON_TASK_EXTENTION_WITH_UNKNOWN = this.ACL_UNKNOWN + this.TABLE_TYPE_NON_TASK;
      this.ACL_TASK_EXTENTION_WITH_NOOP = this.ACL_NOOP + this.TABLE_TYPE_TASK;
      this.ACL_NON_TASK_EXTENTION_WITH_NOOP = this.ACL_NOOP + this.TABLE_TYPE_NON_TASK;
      this.ACL_NON_TASK_EXTENTION_WITH_APPROVER_CONDITION = this.ACL_APPROVER_RESTRICTED + this.TABLE_TYPE_NON_TASK;
      this.ACL_TASK_EXTENTION_WITH_USER_CONDITION = this.ACL_USER_RESTRICTED + this.TABLE_TYPE_TASK;
      this.ACL_NON_TASK_EXTENTION_WITH_USER_CONDITION = this.ACL_USER_RESTRICTED + this.TABLE_TYPE_NON_TASK;

      this.MESSAGES = {};
      this._loadMessages();

      this.ROLE_ORDER = {};
      this.ROLE_ORDER[this.TEXT_NONE] = 0;
      this.ROLE_ORDER[this.TEXT_TIMECARD_USER] = 10;
      this.ROLE_ORDER[this.TEXT_REQUESTOR] = 20;
      this.ROLE_ORDER[this.TEXT_APPROVER] = 30;
      this.ROLE_ORDER[this.TEXT_BUSINESS_STAKEHOLDER] = 40;
      this.ROLE_ORDER[this.TEXT_FULFILLER] = 50;
      this.ROLE_ORDER[this.TEXT_ADMIN] = 80;

      this.CONFIDENCE_ORDER = {};
      this.CONFIDENCE_ORDER[this.TEXT_CONF_NO] = 0;
      this.CONFIDENCE_ORDER[this.TEXT_CONF_LOW] = 10;
      this.CONFIDENCE_ORDER[this.TEXT_CONF_MED] = 20;
      this.CONFIDENCE_ORDER[this.TEXT_CONF_HIGH] = 30;
  },

  /**
   * getDefaultDetectedType
   * Return the defaul detected type object with role type as NONE
   * @returns {object} object { roleType, confidence, code, message }
   */
  getDefaultDetectedType: function() {
      return {
          'roleType': this.TEXT_NONE,
          'confidence': this.TEXT_CONF_NO,
          'code': null,
          'message': null
      };
  },

  /**
   * mergeDetectedTypes
   * Given two detected type objects, return the detected type which is highest in sort order
   * of role types and confidence
   * @param {object} detectedType
   * @param {object} inputDetectedType
   * @returns {object} object { roleType, confidence, code, message }
   */
  mergeDetectedTypes: function(detectedType, inputDetectedType) {
      var outputDetectedType = {
          'roleType': detectedType.roleType,
          'confidence': detectedType.confidence,
          'code': detectedType.code,
          'message': detectedType.message
      }
      outputDetectedType.roleType = [outputDetectedType.roleType, inputDetectedType.roleType].sort(this._sortRoleTypes.bind(this))[0];

      // if this is the same type, take the highest confidence
      if (outputDetectedType.roleType == inputDetectedType.roleType) {
          outputDetectedType.confidence = [outputDetectedType.confidence, inputDetectedType.confidence].sort(this._sortConfidence.bind(this))[0];
          if (outputDetectedType.confidence == inputDetectedType.confidence) {
              outputDetectedType.code = inputDetectedType.code;
              outputDetectedType.message = inputDetectedType.message;
          }
      }

      return outputDetectedType;
  },

  /**
   * fixTimeCardDetectedType
   * Return timecard specific role type if input role type is requestor
   * @param {object} detectedType
   * @returns {object} object { roleType, confidence, code, message }
   */
  fixTimeCardDetectedType: function(detectedType) {
      if (detectedType.roleType == this.TEXT_REQUESTOR) {
          return {
              'roleType': this.TEXT_TIMECARD_USER,
              'confidence': this.TEXT_CONF_HIGH,
              'code': detectedType.code,
              'message': detectedType.message
          }
      }
      return detectedType;
  },

  /**
   * getDetectedType
   * Based on ACL counts by table/acl types, determine role type with confidence level
   * @param {object} tableInfo Object containing metadata about table
   * @param {object} acls Aggregate ACL count object
   * @returns {object} object { roleType, confidence, code, message }
   */
  getDetectedType: function(tableInfo, acls) {
      var detectedType = {
          'roleType': null,
          'confidence': null,
          'message': null
      };

      if (tableInfo.isTaskExt == true) {
          //gs.info('predicting for a task table: ' + tableInfo.name);
          //gs.info(JSON.stringify(acls, null, " "));
          // task table rules
          if (acls.table[this.ACL_TASK_EXTENTION_WITH_USER_CONDITION].read > 0 &&
              acls.table[this.ACL_TASK_EXTENTION_NO_CONDITION].read == 0 &&
              acls.table[this.ACL_TASK_EXTENTION_WITH_CONDITION].read == 0) {
              // if you can only read your records, you are a requester
              detectedType.roleType = this.TEXT_REQUESTOR;
              detectedType.confidence = this.TEXT_CONF_MED;
              detectedType.code = 'personalread';
              detectedType.message = this._getMessage(detectedType.code);
          } else if ((acls.table[this.ACL_TASK_EXTENTION_NO_CONDITION].write > 0 ||
                      acls.table[this.ACL_TASK_EXTENTION_WITH_CONDITION].write > 0) &&
                     (acls.field[this.ACL_TASK_EXTENTION_NO_CONDITION].commentWrite > 0 ||
                      acls.field[this.ACL_TASK_EXTENTION_WITH_CONDITION].commentWrite > 0) &&
                      acls.field[this.ACL_TASK_EXTENTION_NO_CONDITION].write == 0 &&
                      acls.field[this.ACL_TASK_EXTENTION_WITH_CONDITION].write == 0
              ) {
              // write to comment fields only on a task extension
              detectedType.roleType = this.TEXT_BUSINESS_STAKEHOLDER;
              detectedType.confidence = this.TEXT_CONF_MED;
              detectedType.code = 'commentwritenotpersonal';
              detectedType.message = this._getMessage(detectedType.code);
          } else if (acls.table[this.ACL_TASK_EXTENTION_NO_CONDITION].write > 0) {
              // write to a task extension with no restriction and there is no user restriction to prevent users from only seeing their records
              detectedType.roleType = this.TEXT_FULFILLER;
              detectedType.confidence = this.TEXT_CONF_HIGH;
              detectedType.code = 'writenotpersonal';
              detectedType.message = this._getMessage(detectedType.code);
          } else if (acls.field[this.ACL_TASK_EXTENTION_NO_CONDITION].write > 0) {
              // write to a field on task extension with no restriction
              detectedType.roleType = this.TEXT_FULFILLER;
              detectedType.confidence = this.TEXT_CONF_MED;
              detectedType.code = 'fieldwrite';
              detectedType.message = this._getMessage(detectedType.code);
          } else if (acls.table[this.ACL_TASK_EXTENTION_WITH_CONDITION].write > 0) {
              // write to a non-task extension with no condition
              detectedType.roleType = this.TEXT_FULFILLER;
              detectedType.confidence = this.TEXT_CONF_MED;
              detectedType.code = 'condwrite';
              detectedType.message = this._getMessage(detectedType.code);
          } else if (acls.table[this.ACL_TASK_EXTENTION_NO_CONDITION].read > 0) {
              // read all records in a task extension
              detectedType.roleType = this.TEXT_BUSINESS_STAKEHOLDER;
              detectedType.confidence = this.TEXT_CONF_HIGH;
              detectedType.code = 'unrestread';
              detectedType.message = this._getMessage(detectedType.code);
          } else if (acls.table[this.ACL_TASK_EXTENTION_WITH_CONDITION].read > 0) {
              // read all records in a task extension
              detectedType.roleType = this.TEXT_BUSINESS_STAKEHOLDER;
              detectedType.confidence = this.TEXT_CONF_MED;
              detectedType.code = 'condread';
              detectedType.message = this._getMessage(detectedType.code);
          } else if (acls.table[this.ACL_TASK_EXTENTION_WITH_APPROVER_CONDITION].read > 0) {
              // found the approval rule
              detectedType.roleType = this.TEXT_APPROVER;
              detectedType.confidence = this.TEXT_CONF_HIGH; // this can't happen on accident
              detectedType.code = 'taskapprove';
              detectedType.message = this._getMessage(detectedType.code);
          } else {
              // there is something here, so must be a requestor
              detectedType.roleType = this.TEXT_REQUESTOR;
              detectedType.confidence = this.TEXT_CONF_LOW;
              detectedType.code = 'defaultreq';
              detectedType.message = this._getMessage(detectedType.code);
          }
      } else {
          // non-task table rules
          if (acls.table[this.ACL_NON_TASK_EXTENTION_NO_CONDITION].write > 0 &&
              acls.table[this.ACL_NON_TASK_EXTENTION_WITH_USER_CONDITION].read == 0 &&
              acls.table[this.ACL_NON_TASK_EXTENTION_WITH_CONDITION].read == 0) {
              // write to a non-task extension with no condition
              detectedType.roleType = this.TEXT_FULFILLER;
              detectedType.confidence = this.TEXT_CONF_MED;
              detectedType.code = 'unrestrictwritenontask';
              detectedType.message = this._getMessage(detectedType.code);
          } else if (acls.table[this.ACL_NON_TASK_EXTENTION_WITH_CONDITION].write > 0 &&
                      acls.table[this.ACL_NON_TASK_EXTENTION_WITH_USER_CONDITION].read == 0) {
              // write to a non-task extension with a non personalized condition based on gs.getUser
              detectedType.roleType = this.TEXT_FULFILLER;
              detectedType.confidence = this.TEXT_CONF_LOW;
              detectedType.code = 'condwritenontask';
              detectedType.message = this._getMessage(detectedType.code);
          } else if (acls.table[this.ACL_NON_TASK_EXTENTION_WITH_APPROVER_CONDITION].read > 0) {
              // there shouldn't be approvers on non-task, but check for it anyway
              detectedType.roleType = this.TEXT_APPROVER;
              detectedType.confidence = this.TEXT_CONF_LOW; // this can't happen on accident
              detectedType.code = 'nontaskapprove';
              detectedType.message = this._getMessage(detectedType.code);
          } else {
              // there is something here, so must be a requestor
              detectedType.roleType = this.TEXT_REQUESTOR;
              detectedType.confidence = this.TEXT_CONF_LOW;
              detectedType.code = 'defaultreq';
              detectedType.message = this._getMessage(detectedType.code);
          }
      }

      return detectedType;
  },

  _sortRoleTypes: function (first, second) {
      if (this.ROLE_ORDER[first] > this.ROLE_ORDER[second]) {
          return -1;
      }
      if (this.ROLE_ORDER[first] < this.ROLE_ORDER[second]) {
          return 1;
      }
      return 0;
  },

  _sortConfidence: function (first, second) {
      if (this.CONFIDENCE_ORDER[first] > this.CONFIDENCE_ORDER[second]) {
          return -1;
      }
      if (this.CONFIDENCE_ORDER[first] < this.CONFIDENCE_ORDER[second]) {
          return 1;
      }
      return 0;
  },

  _loadMessages: function () {
      this.MESSAGES['personalread'] = 'Personalized Read ACL found';
      this.MESSAGES['writenotpersonal'] = 'Unrestricted Table Write ACL found on Task Table w/ no Personalized Read ACL';
      this.MESSAGES['commentwritenotpersonal'] = 'Journaled write with no personalization';
      this.MESSAGES['fieldwrite'] = 'Unrestricted Field Write ACL found on Task Table w/ no Personalized Read ACL on Table';
      this.MESSAGES['condwrite'] = 'Conditional (not-personalized) write ACL found';
      this.MESSAGES['unrestread'] = 'Unrestricted read ACL found';
      this.MESSAGES['condread'] = 'Conditional read ACL found';
      this.MESSAGES['taskapprove'] = 'Approver ACLs found';
      this.MESSAGES['defaultreq'] = 'Unable to find a higher association';
      this.MESSAGES['unrestrictwritenontask'] = 'Unconditional write ACL found with no personalized read ACL';
      this.MESSAGES['condwritenontask'] = 'Conditional write ACL found with no personalized read ACL';
      this.MESSAGES['nontaskapprove'] = 'Approver ACLs found on non-task table';
  },


  _getMessage: function (code) {
      return this.MESSAGES[code];
  },

  type: 'RoleTypeInferer'
};

Sys ID

73e88a0e430121102aeb1ca57bb8f2b4

Offical Documentation

Official Docs: