Name

sn_cd.cd_TodoProcessor

Description

No description available

Script

var cd_TodoProcessor = Class.create();
cd_TodoProcessor.prototype = {
  initialize: function() {},

  /** Process content for a content type
   * @param contentType string content type value e.g. task'
   */
  processContent: function() {
      var grContentVisibility = new GlideRecord('sn_cd_content_visibility');
      grContentVisibility.addActiveQuery();
      grContentVisibility.addNotNullQuery('when_to_process');
      grContentVisibility.addNullQuery('approvers').addOrCondition('state', 'published');
      grContentVisibility.addQuery('content.content_type.category', 'todo_content');
      grContentVisibility.orderBy('when_to_process');
      grContentVisibility.query();

      if (grContentVisibility.hasNext())
          this.processTodos(grContentVisibility);
  },

  /** Process to-dos for content visibility audience
   * @param grContentVisibility GlideRecord [sn_cd_content_visibility] Content visibility record to retrieve audience from
   */
  processTodos: function(grContentVisibility) {
      var TASK_EVENT_NAME = 'sn_cd.todo.content_todo';
      var MAX_RUN_TIME = this._getNumberProperty("sn_cd.todo.max_run_time", 600);
      var MAX_ASSIGNEES = this._getNumberProperty("sn_cd.todo.max_assignees", 50000);
      var MAX_USERS_PER_EVENT = this._getNumberProperty("sn_cd.todo.max_users_per_event", 10000);
      var MAX_EVENTS = this._getNumberProperty("sn_cd.todo.max_events", 50);
      var EVENT_STAGGER = this._getNumberProperty("sn_cd.todo.event_stagger", 60);
      var cd_Audience = new sn_cd.cd_Audience();
      var gdtStart = new GlideDateTime();
      var gdtEnd = new GlideDateTime();
     
      gdtEnd.addSeconds(MAX_RUN_TIME);
      var eventCount = 0;
      while (eventCount < MAX_EVENTS &&
          gdtEnd.after(new GlideDateTime()) &&
          grContentVisibility.next()) {
          var grContentTask = grContentVisibility.content.getRefRecord();
          if (!grContentTask.isValidRecord() || !grContentTask.active) {
              grContentVisibility.setValue("notification_status", "error");
              grContentVisibility.setValue("active", false);
              grContentVisibility.update();
              gs.warn("Script - " + this.type + ": Failed to find active content for schedule " + grContentVisibility.getUniqueValue());
              continue;
          }
          var assignees;
          if (grContentVisibility.getValue('use_adhoc_users') == true)
              assignees = grContentVisibility.getValue('users').split(",");
          else
              assignees = cd_Audience.getAudience(grContentVisibility.getValue("audience"));
          var eventsToCreate = Math.ceil(assignees.length / MAX_USERS_PER_EVENT);
          // Filter out content visibilities that can never process due to exceeding maximums
          if (assignees.length > MAX_ASSIGNEES || eventsToCreate > MAX_EVENTS) {
              grContentVisibility.setValue("notification_status", "max_exceeded");
              grContentVisibility.setValue("active", false);
              grContentVisibility.update();
              continue;
          }

          // Skip if content visibility will exceed leftover event allotment. NOTE: It's possible that every next content visibility exceeds the leftover
          if (eventCount + eventsToCreate > MAX_EVENTS)
              continue;

          // Mark completed_on before creating tasks to prevent duplicate tasks if transaction times out
          grContentVisibility.setValue("active", false);
          grContentVisibility.setValue("notification_status", "sent"); // This field now acts as Content status
          grContentVisibility.completed_on = new GlideDateTime();
          grContentVisibility.update();

          // Chunk and stagger events
          var gdtWhenToProcess = new GlideDateTime(grContentVisibility.when_to_process);
          // Adjust this time to now if in the past
          if (gdtWhenToProcess.before(gdtStart))
              gdtWhenToProcess = new GlideDateTime();
          for (var i = 0; i < assignees.length && MAX_USERS_PER_EVENT > 0; i += MAX_USERS_PER_EVENT) {
              var assigneesChunk = assignees.slice(i, i + MAX_USERS_PER_EVENT);
              gs.eventQueueScheduled(TASK_EVENT_NAME, grContentVisibility, assigneesChunk, null, gdtWhenToProcess);
              eventCount++;
              gdtWhenToProcess.addSeconds(EVENT_STAGGER);
          }
      }
  },
  /** Create tasks for a list of users
   * @param grContentVisibility GlideRecord [sn_cd_content_visibility] The visibility record referencing a content to-do to create tasks with
   * @param userArray Array List of sys_user sys_id's to create tasks for
   */
  createTasks: function(grContentVisibility, userArray) {
      if (!userArray || !userArray.length)
          return;

      var grContentTask = grContentVisibility.content.getRefRecord();
      if (!grContentTask.isValidRecord() || !grContentTask.active) {
          gs.warn("Script - " + this.type + ": Failed to find active content for schedule " + grContentVisibility.getUniqueValue());
          return;
      }

      for (var i = 0; i < userArray.length; i++) {
          var grTask = new GlideRecord("sn_cd_task");
          grTask.setValue("assigned_to", userArray[i]);
          grTask.setValue("short_description", grContentTask.title.toString());
          if (grContentVisibility.due_date.toString())
              grTask.due_date.setDateNumericValue(grContentVisibility.due_date.dateNumericValue());
          grTask.setValue("content_todo", grContentTask.getUniqueValue());
          grTask.setValue("sys_domain", grContentTask.sys_domain.toString());
          if (GlidePluginManager.isActive("com.snc.esign"))
              grTask.setValue("sn_esign_esignature_configuration", grContentTask.esig_template.toString());
          grTask.setValue("created_from_scheduled_content", grContentVisibility.getUniqueValue());
          grTask.insert();
      }
  },

  /** Return a number value for a given property
   * @param propName String Name of a property
   * @param defaultValue Number The default value to use for a property
   * @return Number The number value for a given property
   */
  _getNumberProperty: function(propName, defaultValue) {
      var propValue = Number(gs.getProperty(propName, defaultValue));
      if (isNaN(propValue)) {
          gs.warn("Script - " + this.type + ": Overriding invalid property value for " + propName);
          propValue = defaultValue;
      }
      return propValue;
  },

  type: 'cd_TodoProcessor'
};

Sys ID

60db0c42eb721300a9e7e26ac106fe95

Offical Documentation

Official Docs: