Name
global.ValidateFacets
Description
Handles the Validation of Facet Records. This includes validating existing record to check they are in sync with the Search Profile, and validating the Facet Field when users configure a facet.
Script
var facet_inclusion_list = ["tags", "language"];
var inclusionPrefix = "topic";
var dateScalarTypes = ['date', 'time', 'datetime'];
var multiSelectAndTypes = ['tags', 'glide_list'];
var util = new AisConfigurationUtil();
var objectManager = GlideObjectManager.getManager();
var ValidateFacets = Class.create();
var arrayUtil = new ArrayUtil();
ValidateFacets.prototype = Object.extendsObject(AbstractAjaxProcessor, {
type: 'ValidateFacets',
validate_existing_records: function() {
if (!gs.hasRole('search_application_admin'))
return 'The search_application_admin role is required to execute this script';
var searchProfile = this.getParameter('sysparm_search_profile');
var searchAppConfig = this.getParameter('sysparm_search_config');
var invalidFacets = [];
//Fetch Facets Records
var facetGr = new GlideRecord('sys_search_facet');
facetGr.addQuery('search_context_config', searchAppConfig);
facetGr.query();
//Check if the Facet is in Search Sources
while (facetGr.next()) {
if (arrayUtil.contains(facet_inclusion_list, String(facetGr.ais_facet_name))) continue;
var tableName = (facetGr.ais_facet_name).split('.')[0];
var searchSourceGr = new GlideRecord('ais_search_profile_ais_search_source_m2m');
searchSourceGr.addQuery('profile.sys_id', searchProfile);
searchSourceGr.addQuery('search_source.datasource.source', tableName);
searchSourceGr.query();
var isFacetValid = searchSourceGr.hasNext();
if (!isFacetValid) invalidFacets.push(facetGr.getValue('name'));
}
//return list of invalid facets
return JSON.stringify(invalidFacets);
},
validate_facet_field: function() {
if (!gs.hasRole('search_application_admin'))
return 'The search_application_admin role is required to execute this script';
var profile_id = this.getParameter('sysparm_search_profile');
var facetFields = String(this.getParameter('sysparm_facet_field')).toLowerCase().split(',');
var facet_id = this.getParameter('sysparm_facet_id');
var type;
var scalarType;
var prevScalarType = null;
//Get Search Profile From Facet_Id
if (!profile_id) {
var facet_gr = new GlideRecord('sys_search_facet');
facet_gr.get(facet_id);
profile_id = facet_gr.search_context_config.search_profile;
}
for (var i = 0; i < facetFields.length; i++) {
var facetField = facetFields[i].trim();
//Bypass validations if exception
if (arrayUtil.contains(facet_inclusion_list,facetField))
return "valid";
//Check if string format is correct
if (!RegExp(/^\w+(\.\w+)+$/).test(facetField)) {
gs.addErrorMessage(gs.getMessage("Invalid Format. Please ensure the Facet Field is in the format: '[table name].[field name]' such as 'sys_user.name'"));
return "string_error";
}
var idx = facetField.indexOf('.');
var tableName = facetField.substring(0, idx);
var fieldName = facetField.substring(idx + 1);
//Validate Table Name
var gr = new GlideRecord('ais_search_profile_ais_search_source_m2m');
gr.addQuery('profile.sys_id', profile_id);
gr.addQuery('search_source.datasource.source', tableName);
gr.query();
if (!gr.hasNext()) {
gs.addErrorMessage(gs.getMessage("Invalid Table Name: \"{0}\". Please ensure that the table is defined in the current search profile's search sources.", [tableName]));
return "table_error:" + tableName;
}
//Bypass field validations if exception
if (fieldName.startsWith(inclusionPrefix))
return "valid";
//Validate Field Name
var types = this._getFieldType(facetField);
if (types == null) {
gs.addErrorMessage(gs.getMessage("Invalid Field Name: \"{0}\". Please ensure that the field is defined in the supplied table or child tables: \"{1}\"", [fieldName, tableName]));
return "field_error:" + tableName + ":" + fieldName;
}
scalarType = types[1];
if (facetFields.length > 1) {
if (prevScalarType != null && prevScalarType != scalarType)
return "inconsistent_field_types";
prevScalarType = scalarType;
}
}
return "valid";
},
validate_facet_type: function() {
var facetFields = this.getParameter('sysparm_facet_field');
var facetType = this.getParameter('sysparm_type');
return this.validate_facet_type_with_param(facetFields, facetType);
},
validate_facet_type_with_param: function(facetFields, facetType) {
if (!gs.hasRole('search_application_admin'))
return 'The search_application_admin role is required to execute this script';
facetFields = String(facetFields).toLowerCase().split(',');
facetType = String(facetType).toLocaleLowerCase();
for (var i in facetFields) {
var field = facetFields[i].trim();
var fieldTypes = this._getFieldType(field);
if (fieldTypes == null)
return 'error_field';
var type = fieldTypes[0];
var scalarType = fieldTypes[1];
switch (facetType) {
case 'single_select':
// date field can only be single select
break;
case 'multi_select_or':
if (arrayUtil.contains(dateScalarTypes,String(scalarType)))
return 'error_date_type';
break;
case 'multi_select_and':
default:
// null value defaults to multi-select-and
// multi-select-and only recommends to multi-value fields: glide_list/tags
if (arrayUtil.contains(dateScalarTypes,String(scalarType)))
return 'error_date_type';
if (!arrayUtil.contains(multiSelectAndTypes,String(type)))
return 'warning_multi_select_and';
}
}
return 'valid';
},
_getFieldType: function(facetField) {
var idx = facetField.indexOf('.');
if (idx < 0)
return facetField;
var facetFieldSplit = facetField.split('.');
var tableName = facetFieldSplit[0];
var column = facetFieldSplit[1];
var allColumn = facetField.substring(idx + 1);
var scalarType = null;
var type, el;
var gr = new GlideRecord(tableName);
if (!gr.isValidField(column)) {
var validChildTableField = util.validFieldInChildTable(tableName, column);
if (validChildTableField.matched) {
gr = new GlideRecord(validChildTableField.childTableName);
}
}
el = gr.getElement(allColumn);
if (el == null)
return null;
type = el.getED().getInternalType();
scalarType = objectManager.getObjectScalarType(type);
return [type, scalarType];
}
});
Sys ID
8ad1ff0dc3df5c109e777d127840ddef