Name

sn_chg_soc.SoCModelBuilderSNC

Description

SNC functions for building Change Schedule models.

Script

var SoCModelBuilderSNC = Class.create();
SoCModelBuilderSNC.prototype = Object.extendsObject(SoC, {

  initialize: function(_gs) {
  	SoC.prototype.initialize.call(this, null, _gs);
  	// Style indexing
  	// Default style rules for the keyed filtered table name in order of application
  	this._defaultSR = {};
  	// All styles which apply to the keyed definition id in order of application.
  	// Includes defined and default
  	this._definitionSR = {};
  	// All styles rule definitions keyed by definition table name
  	this._allSR = {};
  	this._allSR[SoC.STYLE_RULE] = {};
  	this._allSR[SoC.DEFINITION_STYLE_RULE] = {};
  	this._allSR[SoC.DEFINITION_CHILD_STYLE_RULE] = {};

  	// Container for the SoCDefinition for this builder if needed.
  	this._def = null;
  	this._childDef = null;
  	this._defModel = null;
  },

  // Returns top level definitions with profiles
  definitionsWithProfile: function() {
  	var socDefGr = SoCDefinition.findAll();
  	var socDef = new SoCDefinition(socDefGr, this._gs);

  	var definitions = [];
  	var profiles = {};

  	while (socDefGr.next()) {
  		var defOwnerId = socDefGr.owner + "";
  		// Add profile information
  		if (!socDefGr.owner.nil() && !profiles[defOwnerId])
  			profiles[defOwnerId] = new global.ChangeSoCUtil().getUserProfile(defOwnerId);
  		definitions.push(socDef.toJS());
  	}

  	return {
  		"chg_soc_definition": definitions,
  		"__table_meta": socDef.metadataJS(),
  		"__profiles": profiles
  	};
  },

  buildModel: function(socDefId, changeCount, condition) {
  	if (!socDefId)
  		return null;

  	var socDefGr = SoCDefinition.findById(socDefId);
  	if (!socDefGr)
  		return null;

  	var model = {
  		"__struct" : [],  // Record structure definition
  		"__more" : false, // If there are more changes than those returned
  		"__change_count": changeCount // Count of change_request records
  	};

  	model[SoC.CHANGE_REQUEST] = {};
  	model[SoC.DEFINITION] = this.buildDefinitionModel(socDefGr);

  	if (isNaN(changeCount))
  		changeCount = 0;

  	var limit = parseInt(gs.getProperty("sn_chg_soc.change_soc_initial_limit", "30"), 10);
  	if (changeCount !== 0)
  		limit = changeCount + SoC.LIMIT;

  	var conflictConfig = {};
  	if (!!socDefGr.show_blackout || !!socDefGr.show_maintenance) {
  		conflictConfig.cmdb_ancestor = global.ChangeCheckConflicts.buildAncestorClassInfo("cmdb");
  		conflictConfig.change_request_ancestor = global.ChangeCheckConflicts.buildAncestorClassInfo("change_request");
  		conflictConfig.maintenance = this._findMaintenanceSchedules();
  		conflictConfig.include_blackout_window = !!socDefGr.show_blackout;
  		if (conflictConfig.include_blackout_window)
  			conflictConfig.blackout = this._findBlackoutSchedules();
  	}

  	var chgReqGr = this._def.getRecords(changeCount, condition);
  	var chgReqFields = SoCDefinition.getRequiredFields(socDefGr);
  	var usedSchedules = {};
  	var changeReqs = {};

  	while (changeCount < limit && chgReqGr.next()) {
  		changeCount++;
  		var socChgReq = new SoCChangeRequest(chgReqGr, this._gs);

  		var changeSysId = chgReqGr.getUniqueValue();
  		changeReqs[changeSysId] = {
  			"table_name": SoC.CHANGE_REQUEST,
  			"sys_id": changeSysId,
  			"style": this._getStyleReference(socDefId, chgReqGr),
  			"schedule_window": {}, // Blackout/Maintenance spans
  			"related": {}, // Related recored keyed by definition
  			"more": {} // If there are more records for the related definition
  		};

  		// Add the change request to the flattened data if it doesn't exist
  		if (!model.change_request[changeSysId])
  			model.change_request[changeSysId] = this._toJSFields(chgReqGr, chgReqFields);

  		// Add the change_request table meta data if it doesn't exist
  		if (!model.change_request.__table_meta)
  			model.change_request.__table_meta = this._metadataJSFields(chgReqGr, chgReqFields);

  		// Add Maintenance/Blackout windows for this change_request
  		if (!!socDefGr.show_blackout || !!socDefGr.show_maintenance)
  			changeReqs[changeSysId].schedule_window = socChgReq.getScheduleSpans(socDefGr, conflictConfig, usedSchedules);
  	}

  	model = this._buildRelatedModel(model, changeReqs);

  	if (chgReqGr.hasNext())
  		model.__more = true;

  	// Add the style definitions
  	for (var styleTN in this._allSR)
  		model[styleTN] = this._allSR[styleTN];

  	model._css = this.getCSS();
  	model.__change_count = changeCount;
  	return model;
  },

  _buildRelatedModel: function(model, changeReqs) {
  	for (var cdi = 0; cdi < this._childDef.length; cdi++) {
  		var socDefChild = this._childDef[cdi];
  		var socDefChildId = socDefChild._gr.getUniqueValue();

  		var childRecGr = socDefChild.getAllRecords(Object.keys(changeReqs));
  		if (childRecGr === null)
  			return model;
  		var childRecFields = SoCDefinitionChild.getRequiredFields(socDefChild._gr);
  		var childTN = childRecGr.getTableName();

  		while (childRecGr.next()) {
  			var childSysId = childRecGr.getUniqueValue();
  			// Add the related record to the flattened related data if it doesn't exist
  			if (!model[childTN])
  				model[childTN] = {};
  			if (!model[childTN].__table_meta)
  				model[childTN].__table_meta = this._metadataJSFields(childRecGr, childRecFields);
  			if (!model[childTN][childSysId])
  				model[childTN][childSysId] = this._toJSFields(childRecGr, childRecFields);
  			model[childTN].__has_children = true;

  			var changeSysId = childRecGr.getValue(socDefChild._gr.reference_field + "");
  			if (!changeReqs[changeSysId].related[socDefChildId])
  				changeReqs[changeSysId].related[socDefChildId] = [];
  			// Add the related record reference to the change
  			changeReqs[changeSysId].related[socDefChildId].push({
  				"table_name" : childTN,
  				"sys_id" : childSysId,
  				"style" : this._getStyleReference(socDefChildId, childRecGr)
  			});
  		}
  	}

  	for (var changeId in changeReqs)
  		if (changeReqs.hasOwnProperty(changeId))
  			model.__struct.push(changeReqs[changeId]);

  	return model;
  },

  // Builds the definition model, styles etc.
  buildDefinitionModel: function(socDefGr) {
  	if (!socDefGr || !socDefGr.isValid() || !socDefGr.isValidRecord())
  		return null;

  	// If the model has already been built and it's the same as requested, just return it.
  	if (this._def && this._def._gr.getUniqueValue() === socDefGr.getUniqueValue())
  		return this._defModel;

  	this._def = new SoCDefinition(socDefGr, this._gs);
  	//Style information
  	this._addDefaultStyleRules(this._def);
  	this._addDefinitionStyleRules(this._def);

  	this._childDef = [];
  	var definition = this._def.toJS();
  	definition.__table_meta = this._def.metadataJS();

  	this._defModel = this._buildChildDefinition(definition, socDefGr);
  	return definition;
  },

  _buildChildDefinition: function(definition, socDefGr) {
  	var socDefChildGr = SoCDefinitionChild.findByDefId(socDefGr.getUniqueValue());
  	var socDefChild = new SoCDefinitionChild(socDefChildGr, this._gs);
  	if (socDefChildGr && socDefChildGr.hasNext()) {
  		definition.__child = {
  			"order": []
  		};

  		while (socDefChildGr.next()) {
  			this._addDefaultStyleRules(socDefChild);
  			this._addDefinitionStyleRules(socDefChild);
  			definition.__child.order.push(socDefChildGr.getUniqueValue());
  			definition.__child[socDefChildGr.getUniqueValue()] = socDefChild.toJS();

  			// For repeatability store individual GlideRecords
  			var csdgr = new GlideRecord(socDefChildGr.getTableName());
  			csdgr.get(socDefChildGr.getUniqueValue());
  			this._childDef.push(new SoCDefinitionChild(csdgr, gs));
  		}
  	}
  	return definition;
  },

  _addDefinitionStyleRules: function(socDef) {
  	if (!socDef)
  		return null;

  	var sysId = socDef._gr.getUniqueValue();
  	var tableName = socDef._gr.table_name + "";
  	// Already enumerated, return
  	if (this._definitionSR[sysId] && this._definitionSR[sysId][tableName])
  		return null;

  	var styleRule = socDef.getStyleRules();
  	var styles = [];
  	while (styleRule._gr.next()) {
  		var style = styleRule.toJS();
  		this._allSR[styleRule._gr.getTableName() + ""][styleRule._gr.getUniqueValue() + ""] = style;
  		styles.push(style);
  	}

  	// If we have default styles defined, add them as the last elements
  	if (this._defaultSR[tableName])
  		styles = styles.concat(this._defaultSR[tableName]);

  	if (!this._definitionSR[sysId])
  		this._definitionSR[sysId] = {};

  	if (!this._definitionSR[sysId][tableName])
  		this._definitionSR[sysId][tableName] = styles;
  },

  _addDefaultStyleRules: function(socDef) {
  	if (!socDef)
  		return null;

  	var tableName = socDef._gr.table_name + "";
  	// Already enumerated, return
  	if (this._defaultSR[tableName])
  		return null;

  	var styleRuleGr = SoCStyleRule.findByTableName(tableName);
  	var styleRule = new SoCStyleRule(styleRuleGr, this._gs);
  	var styles = [];
  	while (styleRuleGr.next()) {
  		var style = styleRule.toJS();
  		this._allSR[SoC.STYLE_RULE][styleRuleGr.getUniqueValue() + ""] = style;
  		styles.push(style);
  	}

  	this._defaultSR[tableName] = styles;
  },

  getCSS: function() {
  	var css = "";
  	for (var table in this._allSR)
  		if (this._allSR.hasOwnProperty(table))
  			for (var sysId in this._allSR[table])
  				if (this._allSR[table].hasOwnProperty(sysId))
  					css += this._allSR[table][sysId].style.value + "\n";
  	return css;
  },

  _findMaintenanceSchedules: function() {
  	// Maintenance - ChangeCollisionHelper.getConditionalMaintenanceSchedules
  	var maintenanceSchedules = [];
  	var scheduleGR = new GlideRecord("cmn_schedule_maintenance");
  	scheduleGR.addNotNullQuery("applies_to");
  	scheduleGR.query();
  	while (scheduleGR.next()) {
  		maintenanceSchedules.push({
  			sys_id : scheduleGR.sys_id.toString(),
  			condition : scheduleGR.condition.toString(),
  			name : scheduleGR.name.toString(),
  			applies_to : scheduleGR.applies_to.toString()
  		});
  	}
  	return maintenanceSchedules;
  },

  _findBlackoutSchedules: function() {
  	var blackoutSchedules = [];
  	var scheduleGR = new GlideRecord("cmn_schedule_blackout");
  	scheduleGR.addQuery("type", "blackout");
  	scheduleGR.query();
  	while (scheduleGR.next()) {
  		blackoutSchedules.push({
  			sys_id : scheduleGR.sys_id.toString(),
  			condition : scheduleGR.condition.toString(),
  			name : scheduleGR.name.toString(),
  			applies_to : scheduleGR.applies_to.toString()
  		});
  	}
  	return blackoutSchedules;
  },

  // Returns a style reference to be applied to the provided record for the given definition
  _getStyleReference: function (defId, recordGr) {
  	var recTN = recordGr.getTableName();
  	if (this._definitionSR[defId] && this._definitionSR[defId][recTN]) {
  		var styleRules = this._definitionSR[defId][recTN];
  		for (var sri = 0; sri < styleRules.length; sri++) {
  			if (!styleRules[sri].condition)
  				continue;

  			if (GlideFilter.checkRecord(recordGr, styleRules[sri].condition.value))
  				return {
  					table_name : styleRules[sri].sys_class_name.value,
  					sys_id : styleRules[sri].sys_id.value
  				};
  		}
  	}
  	return null;
  },

  type: 'SoCModelBuilderSNC'
});

Sys ID

5d041e6767230300b410afa00585ef7e

Offical Documentation

Official Docs: