Name

global.TopicCategoryContentSurfacingUtilSNC

Description

No description available

Script

var TopicCategoryContentSurfacingUtilSNC = Class.create();
TopicCategoryContentSurfacingUtilSNC.prototype = {
  initialize: function() {
      this.JOB_LAST_EXECUTION_PROPERTY = "taxonomy.category.new_content_job_last_run";
      this.CATALOG_CONTENT_TYPE = "98f9a16553622010069addeeff7b1248";
      this.KNOWLEDGE_CONTENT_TYPE = "4c32a92153622010069addeeff7b12a3";
  },

  /**
   * Return filtered GlideRecord based on table name and encoded query
   */
  _getFilteredGlideRecord: function(tableName, encodedQuery, disableWorkflow) {
      var gr = new GlideRecord(tableName);
      if (disableWorkflow)
          gr.setWorkflow(false);
      if (encodedQuery)
          gr.addEncodedQuery(encodedQuery);
      gr.query();
      return gr;
  },

  /**
   * Insert records in unconnected_category_content based on a list of values
   */
  _createUnconnectedContentRecords: function(records) {
      records.forEach(function(record) {
          var gr = new GlideRecord("unconnected_category_content");
          for (key in record)
              gr[key] = record[key];
          gr.insert();
      });
  },

  /**
   * Returns a object where the key is the category id and the value is an empty object
   */
  _buildCategoryContentMap: function(contentType, categoryRefField) {
      var categoryContentMap = {};

      var connectedCategoryGr = new GlideAggregate("m2m_connected_category");
      connectedCategoryGr.addQuery("content_type", contentType);
      connectedCategoryGr.addNotNullQuery(categoryRefField);
      connectedCategoryGr.groupBy(categoryRefField);
      connectedCategoryGr.query();

      while (connectedCategoryGr.next())
          categoryContentMap[connectedCategoryGr.getValue(categoryRefField)] = {};
      return categoryContentMap;
  },

  /**
   * Returns a object for linking category and content
   * Structure of the object is {<categoryId>: {contentId: {contentId: <content id>, published: <published date>}}}
   */
  _identifyNewContentInCategories: function(categoryContentMap, categoryField, tableName, encodedQuery) {
      var last_run_date = gs.getProperty(this.JOB_LAST_EXECUTION_PROPERTY);

      var query = categoryField + "IN" + Object.keys(categoryContentMap).join(",");
      if (last_run_date)
          query += "^sys_created_on>=" + last_run_date;
      if (encodedQuery)
          query += "^" + encodedQuery;
      var contentGr = this._getFilteredGlideRecord(tableName, query);

      while (contentGr.next()) {
          var categoryId = contentGr.getValue(categoryField);
          categoryContentMap[categoryId][contentGr.sys_id.toString()] = {
              contentId: contentGr.sys_id.toString(),
              content_creation_date: contentGr.getValue("sys_created_on")
          };
      }
  },

  /**
   * Identifies new catalog items that have been added in the connected categories
   */
  _identifyNewContentInCategoriesForCatalog: function(categoryContentMap) {
      var last_run_date = gs.getProperty(this.JOB_LAST_EXECUTION_PROPERTY);

      var query = "sc_categoryIN" + Object.keys(categoryContentMap).join(",");
      if (last_run_date)
          query += "^sc_cat_item.sys_created_on>=" + last_run_date;
      var contentGr = this._getFilteredGlideRecord("sc_cat_item_category", query);

      while (contentGr.next()) {
          var categoryId = contentGr.sc_category.toString();
          var contentId = contentGr.sc_cat_item.toString();
          var content_creation_date = contentGr.sc_cat_item.sys_created_on.toString();
          categoryContentMap[categoryId][contentId] = {
              contentId: contentId,
              content_creation_date: content_creation_date
          };
      }
  },

  /**
   * Returns the list of content ids that should not be suggested
   * These content includes the ones that have been already dismissed or are already connected via m2m_connected_content table
   */
  _getExclusionContentForTopic: function(topicId, contentType, contentRefField) {
      var excludedContentIds = {};
      var existingUnconnectedContentGr = this._getFilteredGlideRecord("unconnected_category_content", "topic=" + topicId + "^content_type=" + contentType, true);
      while (existingUnconnectedContentGr.next())
          excludedContentIds[existingUnconnectedContentGr[contentRefField]] = existingUnconnectedContentGr[contentRefField];

      var existingConnectedContentGr = this._getFilteredGlideRecord("m2m_connected_content", "topic=" + topicId + "^content_type=" + contentType);
      while (existingConnectedContentGr.next())
          excludedContentIds[existingConnectedContentGr[contentRefField]] = existingUnconnectedContentGr[contentRefField];
      return Object.keys(excludedContentIds);
  },

  /**
   * Returns the list of KB article sys ids that should not be suggested
   * New translations of KB articles are not suggested if any existing language for the same KB articles has been dismissed
   * New versions of KB articles are not suggested if any existing version has been dismissed
   */
  _getExcludedKBArticlesForTopic: function(topicId) {
      var excludedKBIds = {};

      var KBTranslationUtil = new sn_ex_sp.KBContentTranslationUtil();
      query = "dismissed=true^content_type=" + this.KNOWLEDGE_CONTENT_TYPE + "^topic=" + topicId;
      var unconnectedContentGr = this._getFilteredGlideRecord("unconnected_category_content", query, true);

      while (unconnectedContentGr.next()) {
          // New versions should not be suggested for dismissed KB articles
          var kbVersionsGr = this._getFilteredGlideRecord("kb_knowledge", "number=" + unconnectedContentGr.getValue("knowledge"));
          while (kbVersionsGr.next())
              excludedKBIds[kbVersionsGr.getValue("sys_id")] = 1;

          // New translations should not be suggested for dismissed KB articles
          if (GlidePluginManager.isActive("com.glideapp.knowledge.i18n2")) {
              var translatedVersionsGr = KBTranslationUtil.getTranslatedVersionsFromSysId(unconnectedContentGr.getValue('knowledge'));
              while (translatedVersionsGr.next())
                  excludedKBIds[translatedVersionsGr.getValue("sys_id")] = 1;
          }
      }

      return Object.keys(excludedKBIds);

  },

  surfaceNewContent: function() {
      var contentConfigGr = this._getFilteredGlideRecord(
          "taxonomy_content_configuration",
          "category_reference_fieldISNOTEMPTY^content_table_category_fieldISNOTEMPTY^category_tableISNOTEMPTY^active=true"
      );
      var recordDataList = [];

      while (contentConfigGr.next()) {
          var contentType = contentConfigGr.getValue("sys_id");
          // connected content fields
          var contentRefField = contentConfigGr.content_reference_field.toString();
          // connected category fields
          var connectedCategoryTable = contentConfigGr.connected_category_table.toString();
          var categoryRefField = contentConfigGr.category_reference_field.toString();
          var contentTable = contentConfigGr.content_table.toString();
          var contentTableCategoryField = contentConfigGr.content_table_category_field.toString();

          var categoryContentMap = this._buildCategoryContentMap(contentType, categoryRefField);

          if (contentType == this.CATALOG_CONTENT_TYPE)
              this._identifyNewContentInCategoriesForCatalog(categoryContentMap);
          else if (contentType == this.KNOWLEDGE_CONTENT_TYPE && GlidePluginManager.isActive("com.snc.knowledge_advanced"))
              this._identifyNewContentInCategories(categoryContentMap, contentTableCategoryField, contentTable, "latest=true");
          else
              this._identifyNewContentInCategories(categoryContentMap, contentTableCategoryField, contentTable);

          var topicGr = this._getFilteredGlideRecord("topic");

          while (topicGr.next()) {
              recordDataList = [];
              connectedCategoryGr = new GlideRecord(connectedCategoryTable);
              connectedCategoryGr.addQuery("topic", topicGr.sys_id.toString());
              connectedCategoryGr.addQuery("content_type", contentType);
              connectedCategoryGr.query();

              var excludedContentIds = this._getExclusionContentForTopic(topicGr.sys_id.toString(), contentType, contentRefField);
              if (contentType == this.KNOWLEDGE_CONTENT_TYPE)
                  excludedContentIds = excludedContentIds.concat(this._getExcludedKBArticlesForTopic(topicGr.getValue("sys_id")));

              connectedCategoryGr = this._getFilteredGlideRecord(connectedCategoryTable, "topic=" + topicGr.sys_id.toString() + "^content_type=" + contentType);
              while (connectedCategoryGr.next()) {
                  newContents = categoryContentMap[connectedCategoryGr[categoryRefField]];
                  if (!newContents)
                      continue;

                  for (contentId in newContents) {
                      if (excludedContentIds.indexOf(contentId) > -1)
                          continue;
                      var record = {
                          content_type: contentType,
                          topic: topicGr.sys_id.toString(),
                          content_creation_date: newContents[contentId]["content_creation_date"]
                      };
                      record[contentRefField] = contentId;
                      record[categoryRefField] = connectedCategoryGr[categoryRefField].toString();
                      recordDataList.push(record);
                  }
              }
              if (recordDataList)
                  this._createUnconnectedContentRecords(recordDataList);
          }
      }

      gs.setProperty(this.JOB_LAST_EXECUTION_PROPERTY, (new GlideDateTime()).getDate());

      if (gs.getProperty("taxonomy.category.new_feature_alert") === "true")
          gs.setProperty("taxonomy.category.new_feature_alert", false);
  },

  type: 'TopicCategoryContentSurfacingUtilSNC'
};

Sys ID

61b8e4eb77755110cd1b756f1b5a993a

Offical Documentation

Official Docs: