Name

global.ChangeCommon

Description

Common class for methods used within Change Request classes

Script

var ChangeCommon = Class.create();

ChangeCommon.LOG_PROPERTY = "com.snc.change_management.core.log";
ChangeCommon.MATCH_ALL_PROPERTY = "com.snc.change_management.process.match.all";
ChangeCommon.READ_REPLICA_CATEGORY_CHANGE_MANAGEMENT_HISTORICAL_QUERIES = "Change management - historical queries";

ChangeCommon.prototype = {
  initialize: function() {},

  type: "ChangeCommon"
};

ChangeCommon.DATE_ELEMENT_TYPE = {
  "glide_date_time": true,
  "glide_date": true,
  "due_date": true,
  "date": true,
  "datetime": true
};

ChangeCommon.assign = function(target, varArgs) {
  if (target == null)
      throw new TypeError("Cannot convert undefined or null to object");

  var to = Object(target);

  for (var index = 1; index < arguments.length; index++) {
      var nextSource = arguments[index];

      if (nextSource != null)
          for (var nextKey in nextSource)
              if (Object.prototype.hasOwnProperty.call(nextSource, nextKey))
                  to[nextKey] = nextSource[nextKey];
  }
  return to;
};

ChangeCommon.matchAll = function() {
  return gs.getProperty(ChangeCommon.MATCH_ALL_PROPERTY, "true") + "" !== "true" ? "IR_AND_OR_QUERY" : "IR_AND_QUERY";
};

ChangeCommon.toJS = function(_gr, excludes, includeCanWrite) {
  var obj = {};

  if (!_gr || typeof _gr === "undefined" || !_gr.canRead())
      return obj;

  excludes = excludes || {
      sys_scope: true,
      sys_replace_on_upgrade: true,
      sys_policy: true,
      sys_package: true,
      sys_customer_update: true,
      sys_update_name: true
  };

  if (includeCanWrite)
      obj._canWrite = _gr.canWrite();

  var elements = _gr.getElements();
  var jsArr = Array.isArray(elements);

  // Scoped vs Global calls to getElements returns different objects
  var elementsLength = jsArr ? elements.length : elements.size();
  for (var i = 0; i < elementsLength; i++) {
      var element = jsArr ? elements[i] : elements.get(i);
      var elementName = element.getName() + "";
      if (!element.canRead() || !elementName || excludes[elementName])
          continue;

      var fieldType = element.getED().getInternalType() + "";
      var fieldValue = element.toString();
      if (fieldType === "boolean")
          fieldValue = fieldValue === "true" ? true : false;
      else if (fieldType === "integer" || fieldType === "decimal")
          fieldValue = !fieldValue ? fieldValue : fieldValue - 0;

      obj[elementName] = {
          "display_value": element.getDisplayValue(),
          "value": fieldValue
      };
      if (includeCanWrite)
          obj[elementName]._canWrite = element.canWrite();

      // Augment object for date types
      if (ChangeCommon.DATE_ELEMENT_TYPE[fieldType]) {
          var gdt = new GlideDateTime();
          gdt.setValue(element.toString());
          obj[elementName].display_value_internal = gdt.getDisplayValueInternal();
      }
  }

  if (this._log.atLevel(GSLog.DEBUG))
      this._log.debug("[_toJS] return: " + JSON.stringify(obj));

  return obj;
};

ChangeCommon.resolveChoiceLabel = function(recordClassName, field, value) {
  if (!recordClassName || !field || !value)
      return null;

  var fieldChoices = GlideChoiceList.getChoiceList(recordClassName, field);
  if (fieldChoices.size() === 0)
      return value;

  // Case sensitive matching of choice value
  for (var i = 0; i < fieldChoices.getSize(); i++)
      if (fieldChoices.getChoice(i).getValue() + "" === value + "")
          return fieldChoices.getChoice(i).getLabel() + "";

  // Case insensitive matching of choice value
  for (var j = 0; j < fieldChoices.getSize(); j++)
      if ((fieldChoices.getChoice(j).getValue() + "").toUpperCase() === value.toUpperCase())
          return fieldChoices.getChoice(j).getLabel() + "";

  // Try and match using label instead, and if match, value is a label
  if (fieldChoices.getValueOf(value))
      return value;

  // Case insensitive matching of choice Label
  for (var k = 0; k < fieldChoices.getSize(); k++)
      if ((fieldChoices.getChoice(k).getLabel() + "").toUpperCase() === value.toUpperCase())
          return fieldChoices.getChoice(k).getLabel() + "";

  return value;
};

ChangeCommon.resolveChoice = function(recordClassName, field, value) {
  if (!recordClassName || !field || !value)
      return value || null;

  var fieldChoices = GlideChoiceList.getChoiceList(recordClassName, field);
  if (fieldChoices.size() === 0)
      return value;

  // Case sensitive matching of choice value
  for (var i = 0; i < fieldChoices.getSize(); i++)
      if (fieldChoices.getChoice(i).getValue() + "" === value + "")
          return value;

  // Case insensitive matching of choice value
  for (var j = 0; j < fieldChoices.getSize(); j++)
      if ((fieldChoices.getChoice(j).getValue() + "").toUpperCase() === value.toUpperCase())
          return fieldChoices.getChoice(j).getValue();

  // Try and match using label instead
  var valueByLabel = fieldChoices.getValueOf(value);

  if (valueByLabel)
      return valueByLabel;

  // Case insensitive matching of choice Label
  for (var k = 0; k < fieldChoices.getSize(); k++)
      if ((fieldChoices.getChoice(k).getLabel() + "").toUpperCase() === value.toUpperCase())
          return fieldChoices.getChoice(k).getValue();

  // We allow non-existent choice values, but Table REST API checks glide.rest.choice.allow_non_existing_value === true
  // However implementing this check would change behaviour for existing customers
  return value;
};

ChangeCommon.resolveReference = function(fieldED, value) {
  if (!fieldED || !value)
      return value;

  var referenceKey = fieldED.getReferenceKey();
  if (referenceKey !== null && referenceKey + "" !== "sys_id")
      return value;

  var resolvedSysId = GlideReferenceField.getSysID(fieldED.getReference(), value, false);
  resolvedSysId = GlideStringUtil.notNil(resolvedSysId) ? resolvedSysId : value;

  return resolvedSysId;
};

ChangeCommon.isReferenceField = function(fieldED) {
  if (!fieldED)
      return false;

  var internalType = fieldED.getInternalType() + "";
  return internalType === "reference" || internalType === "domain_id" || internalType === "glide_var";
};

ChangeCommon.getRoles = function() {
  return GlideStringUtil.join(GlideSecurityManager.get().getRoles());
};

ChangeCommon.isAccessibilityEnabled = function() {
  return GlideAccessibility.isEnabled();
};

ChangeCommon.isPluginActive = function(pluginName) {
  if (!pluginName)
      return false;

  return GlidePluginManager.isActive(pluginName);
};

ChangeCommon.canRead = function(tableName) {
  if (!tableName)
      return false;

  var tableDescriptor = GlideTableDescriptor.get(tableName);
  if (!tableDescriptor)
      return false;

  return tableDescriptor.canRead();
};

/**
*  Get a subset of the records supplied
*  limit  : Maximum record size to be returned
*  offset : Starting point of the return records
*
*  Returns array of JS'd GlideRecords
*/
ChangeCommon.getWindow = function(_gr, limit, offset) {
  var obj = [];

  if (!_gr || typeof _gr === "undefined")
      return obj;

  if (!offset || offset < 0)
      offset = 0;
  if (!limit || limit < 0)
      limit = 500;

  var currentOffset = 0;
  while (_gr.next() && limit > 0) {
      currentOffset++;
      if (!_gr.canRead())
          continue;
      if (currentOffset >= offset) {
          obj.push(ChangeCommon.toJS(_gr));
          limit--;
      }
  }

  return obj;
};

/**
*	Get a subset of the records supplied
*	nameValuePairs : which will be used to build query unless it contains sysparm_query
*	in which case the value of sysparm_query is used to build the query
*
*	Returns Object with containing encodedQuery and fields applied and ignored
*/
ChangeCommon.buildEncodedQuery = function(nameValuePairs, tableName) {
  var result = {
      encodedQuery: '',
      fields: {
          applied: [],
          ignored: []
      }
  };

  if (!nameValuePairs || typeof nameValuePairs === 'undefined')
      return result;

  if (!tableName || typeof tableName === 'undefined')
      tableName = 'change_request';

  var gr = new GlideRecord(tableName);
  var qc = null;
  if (nameValuePairs.sysparm_query && typeof nameValuePairs.sysparm_query !== 'undefined') {
      var sysparmQuery = nameValuePairs.sysparm_query + '';
      var queryString = new GlideQueryString(tableName, sysparmQuery);
      queryString.deserialize();

      var terms = queryString.getTerms();
      var previousTerm = null;
      for (var i = 0; i < terms.size(); i++) {
          if (i > 0)
              previousTerm = terms.get(i - 1);

          var term = terms.get(i);
          var field = term.getTermField();

          // handle ^EQ at end of encoded query
          if (field !== null) {
              // Validate only the first dot walk field
              var dotWalkField = (field + '').split('.');
              if (gr.isValidField(field) || (dotWalkField.length > 1 && gr.isValidField(dotWalkField[0]))) {

                  // handle ^OR inside of encoded query
                  if (term.isOR() && previousTerm !== null && qc !== null)
                      qc.addOrCondition(field, term.getOperator(), term.getValue());
                  else
                      qc = gr.addQuery(field, term.getOperator(), term.getValue());

                  result.fields.applied.push(field);
              } else
                  result.fields.ignored.push(field);
          }
      }

      result.encodedQuery = gr.getEncodedQuery();
  } else {
      Object.keys(nameValuePairs).forEach(function(name) {
          var value = nameValuePairs[name] + '';
          if (gr.isValidField(name)) {
              gr.addQuery(name, value);
              result.fields.applied.push(name);
          } else
              result.fields.ignored.push(name);
      }, this);
      result.encodedQuery = gr.getEncodedQuery();
  }

  return result;
};

ChangeCommon.isNil = function(value) {
  return JSUtil.nil(value) || value === "undefined";
};

ChangeCommon.methods = {

  update: function() {
      if (!this._gr.canWrite())
          return;

      return this._gr.update();
  },

  insert: function() {
      var canCreate = this._gr.canCreate();

      if (this._log.atLevel(GSLog.DEBUG))
          this._log.debug("[insert] canCreate: " + canCreate);

      if (!canCreate)
          return;

      var sysId = this._gr.insert();

      if (this._log.atLevel(GSLog.DEBUG))
          this._log.debug("[insert] sysId: " + sysId);

      return sysId;
  },

  deleteRecord: function() {
      return this._gr.deleteRecord();
  },

  refreshGlideRecord: function() {
      var gr = new GlideRecord(this._gr.getTableName());
      gr.addQuery("sys_id", this._gr.getUniqueValue());
      gr.query();
      if (!gr._next())
          this._gr = null;
      this.initialize(gr);
  },

  getGlideRecord: function() {
      return this._gr;
  },

  setValue: function(name, value) {
      var nameValuePairs = {};
      if (name)
          nameValuePairs[name] = value || "";
      return this.setValues(nameValuePairs);
  },

  setValues: function(nameValuePairs) {
      if (this._log.atLevel(GSLog.DEBUG))
          this._log.debug("[setValues] nameValuePairs: " + JSON.stringify(nameValuePairs));

      var fields = {
          applied: [],
          ignored: []
      };

      if (!nameValuePairs || !this._gr.canWrite())
          return fields;

      var encryptedFields;
      if (nameValuePairs.hasOwnProperty('encrypted_fields')) {
          if (typeof nameValuePairs.encrypted_fields === 'string')
              encryptedFields = nameValuePairs.encrypted_fields.split(',');
          else if (Array.isArray(nameValuePairs.encrypted_fields))
              encryptedFields = nameValuePairs.encrypted_fields;
          else
              encryptedFields = Object.keys(nameValuePairs.encrypted_fields);

          delete nameValuePairs.encrypted_fields;

          if (this._log.atLevel(GSLog.DEBUG))
              this._log.debug("[setValues] encryptedFields: " + encryptedFields);
      }

      Object.keys(nameValuePairs).forEach(function(name) {
          var value = nameValuePairs[name] + "";
          if (this._gr.isValidField(name) && this.canWriteTo(name)) {
              var fieldED = this._gr[name].getED();

              // Handle Reference and Choice
              if (ChangeCommon.isReferenceField(fieldED))
                  value = ChangeCommon.resolveReference(fieldED, value);
              else if (fieldED.isChoiceTable())
                  value = ChangeCommon.resolveChoice(this._gr.getRecordClassName(), fieldED.getName(), value);

              //  Handle Journal Field types
              if (fieldED.getInternalType() + "" === "journal_input")
                  this._gr[name].setJournalEntry(value);
              else {
                  // Support for encrypted fields
                  if (encryptedFields && Array.isArray(encryptedFields) && encryptedFields.indexOf(name) !== -1)
                      this._gr.setDisplayValue(name, value);
                  else
                      this._gr.setValue(name, value);
              }

              fields.applied.push(name);
          } else
              fields.ignored.push(name);
      }, this);

      if (this._log.atLevel(GSLog.DEBUG))
          this._log.debug("[setValues] fields: " + JSON.stringify(fields));

      return fields;
  },

  canWriteTo: function(fieldName) {
      if (!fieldName)
          return false;

      var canWrite = this._gr[fieldName].canWrite();

      if (this._log.atLevel(GSLog.DEBUG))
          this._log.debug("[canWriteTo] fieldName: " + fieldName + " canWrite: " + canWrite);

      return canWrite;
  },

  // provides legacy API
  resolveChoice: ChangeCommon.resolveChoice,
  resolveReference: ChangeCommon.resolveReference,
  isReferenceField: ChangeCommon.isReferenceField
};

ChangeCommon.filters = {

  sysId: function(sysId) {
      var re = /^[a-f0-9]{32}$/i;
      return re.test(sysId);
  },

  unique: function(value, index, arr) {
      return arr.indexOf(value) === index;
  }

};

/**
* Used to invalidate browser cache. 
* E.g. UI Macros, when applied through AngularJS templates, must include 
* the flushstamp from the macro cache to ensure customers get the latest file
*/
ChangeCommon.cacheInvalidation = {

  getUIMacroFlushStamp: function() {
      return GlideCacheManager.getFlushStamp('syscache_ui_macro');
  }

};

Sys ID

ba686ea3b773130096c3e4f6ee11a9d3

Offical Documentation

Official Docs: