Name

sn_appclient.AppPluginInstallation

Description

No description available

Script

var AppPluginInstallation = Class.create();
AppPluginInstallation.prototype = {
  initialize: function() {
      this.blockingDependencies = [];
      this.conflictingDependencies = [];
      this.installationResponse = {};
      this.batchInstallMap = {};
      this.productName = '';
      this.INSTALLATION_WARNING_MESSAGE = gs.getMessage('These applications will not be part of the group installation because these applications have at least one dependent application that conflicts with the version you chose to install.');
      this.INSTALLATION_ERROR_MESSAGE = gs.getMessage('One or more required dependencies for this application are not installed on your instance. Please install them first to install the application.');
      this.UNABLE_TO_COMPLETE_INSTALL_MESSAGE = gs.getMessage('Unable to complete installation successfully');
      this.ANOTHER_OPERATION_IS_RUNNING_MESSAGE = gs.getMessage('Application installation is unavailable because another operation is running: {0}');
  },

  /**
   * AppCustomization is not supported currently.

   ex. installationDetails = {
   "sys_id": "18e849d169284372d77ad961ee8fa009",
   "app_name": "AES Catalog Builder Wizard",
   "version": "21.1.3",
   "loadDemoData": false,
   "appScope": "sn_aes_catalog_wzd",
   "dependencies": "com.glide.uxbuilder:sys,com.devsnc_sn_gw_wrapper:sys,com.devsnc_sn_gw_page:sys,com.devsnc_sn_gw_info_summary:sys,com.servicenow_now_input:sys,com.servicenow_now_tooltip:sys"
   }

   ex. response = {
   "id":"INSTALLTION_STATUS",
   "installationAllowed":true,
   "installationSuccess":true,
   "progressId": null,
   "message":"Successfully installed <app_name>:<version>"
   }";"
   **/
  validateAndInstallApps: function(installationDetails) {
      var installationSuccess = false;

      if (global.JSUtil.nil(installationDetails))
          return this._getInstallationResponse("INVALID PAYLOAD", false, installationSuccess, null, "Invalid payload");

      var dependencies = this._getAppDependencies(installationDetails.sys_id, installationDetails);

      // Check if the system is busy, user correct role(s) and current domain is safe for installation
      var isInstallationAllowed = this._isInstallationAllowed();
      if (!isInstallationAllowed.installationAllowed)
          return isInstallationAllowed;

      if (dependencies) {
          var dependencyList = new DependencyProcessor(installationDetails.appScope, false).processDependency(dependencies.split(","));
          var inactiveDependency = false;
          for (var depIndex = 0; depIndex < dependencyList.length; depIndex++) {
              if (!dependencyList[depIndex].active || dependencyList[depIndex].status === "Installation blocked") {
                  inactiveDependency = true;
                  break;
              }
          }

          if (inactiveDependency)
              return this._getInstallationResponse("BLOCKING_DEPENDENCY", false, false, null, gs.getMessage(this.INSTALLATION_ERROR_MESSAGE));
      }

      // Install app and dependencies
      var appId = installationDetails.sys_id;
      var version = installationDetails.version;
      var customizedAppSelectedVersion = installationDetails.customizedAppSelectedVersion || '';
      var loadDemoData = installationDetails.loadDemoData;
      var msg = '';

      try {
          installationSuccess = new AppUpgrader().upgrade(appId, version, loadDemoData, customizedAppSelectedVersion);
      } catch (ex) {
          return this._getInstallationResponse("INSTALLATION_ERROR", true, installationSuccess, null, ex);
      }

      if (installationSuccess && global.JSUtil.notNil(installationDetails.customizedAppSelectedVersion))
          msg = gs.getMessage("Successfully installed customization version {0} for application {1}:{2}", customizedAppSelectedVersion, installationDetails.app_name, version);
      else if (installationSuccess && installationDetails.customizedAppSelectedVersion === undefined)
          msg = gs.getMessage("Successfully installed application {0}:{1}", installationDetails.app_name, version);
      else if (!installationSuccess)
          msg = this.UNABLE_TO_COMPLETE_INSTALL_MESSAGE;

      return this._getInstallationResponse("INSTALLATION_STATUS", true, installationSuccess, null, msg);
  },

  /**
   Customization version are not support currently

   ex. installationDetails = {
   "plugin_id": "com.glide.awa.test_data",
   "plugin_name": "Advanced Work Assignment Testing Tools",
   "loadDemoData": false
   };

   ex. response = {
   "id":"INSTALLTION_STATUS",
   "installationAllowed":true,
   "installationSuccess":null,
   "progressId":8632aa34530f8510d0f9ddeeff7b12d9,
   "message":"Successfully installed plugin <plugin_name>:<version>"
   }";"
   **/
  validateAndInstallPlugins: function(installationDetails) {
      // Check if the system is busy, user has correct role(s) and current domain is safe for installation
      var isInstallationAllowed = this._isInstallationAllowed();
      if (!isInstallationAllowed.installationAllowed)
          return isInstallationAllowed;

      var progressName = gs.getMessage("Installing plugin {0}", installationDetails.plugin_id);
      var progressId = '';
      var pluginName = installationDetails.plugin_name;
      var pluginId = installationDetails.plugin_id;
      var customizationVersion = installationDetails.customizationVersion || '';
      var loadDemoData = installationDetails.loadDemoData;
      var installationSuccess = false;
      var msg = '';

      try {
          progressId = new global.PluginUpgrader().upgrade(pluginId, customizationVersion, progressName, loadDemoData, false);

          if (progressId) {
              installationSuccess = true;
              // Refresh cache if plugin activation execution is triggered successfully
              new global.AppManagerCacheHelper().refreshAppManagerCache();
          }
      } catch (ex) {
          return this._getInstallationResponse("INSTALLATION_ERROR", true, installationSuccess, null, ex);
      }

      if (progressId && global.JSUtil.notNil(installationDetails.customizationVersion))
          msg = gs.getMessage("Started installing customization version {0} for plugin {1}", customizationVersion, pluginName);
      else if (progressId && installationDetails.customizationVersion === undefined)
          msg = gs.getMessage("Started installing plugin {0}", pluginName);
      else if (progressId === '')
          msg = this.UNABLE_TO_COMPLETE_INSTALL_MESSAGE;

      return this._getInstallationResponse("INSTALLATION_STATUS", true, installationSuccess, progressId, msg);
  },

  // API to batch install dependency applications/plugins
  /**
   ex selectedApps = {
   "com.snc.financial_management_for_apm": {
   "plugin_id": "com.snc.financial_management_for_apm",
   "scope": "global",
   "app_name": "Financial Management For APM",
   "isPlugin": true
   },
   "d30787a873ac0010fe9978ba4cf6a763": {
   "sys_id": "d30787a873ac0010fe9978ba4cf6a763",
   "app_name": "Adobe Experience Platform Spoke",
   "versionObj": {
   "version": "2.0.0",
   //dependencies is option - fetch if not supplied
   "dependencies": "com.glide.cobject:sys,com.glide.hub.integration.runtime:sys,com.glide.hub.action_step.rest:sys,com.glide.hub.action_type.datastream:sys,com.glide.hub.dynamic_inputs:sys,com.glide.hub.dynamic_outputs:sys"
   },
   "isStoreApp": true,
   "appScope": "sn_adobe_exp_spoke"
   }
   };

   ex. response = {"batchInfo":{"execution_tracker_id":"8632aa34530f8510d0f9ddeeff7b12d9","batch_installation_id":"c232aa34530f8510d0f9ddeeff7b12d8"}}
   **/
  validateAndBatchInstall: function(productName, selectedApps) {
      this.productName = productName;
      this._checkForDependenciesAndStartBatchInstall(selectedApps);

      return this.installationResponse;
  },

  _checkForDependenciesAndStartBatchInstall: function(selectedApps) {
      var apps = [];
      for (var key in selectedApps) {
          if (!selectedApps[key].isPlugin) {
              if (selectedApps[key].versionObj)
                  apps.push({
                      "scope": selectedApps[key].appScope,
                      "version": selectedApps[key].versionObj.version,
                      "dependencies": this._getAppDependencies(selectedApps[key].sys_id, selectedApps[key].versionObj)
                  });
              this.batchInstallMap[selectedApps[key]['appScope']] = selectedApps[key]['app_name'];
          }
      }
      if (apps.length == 0)
          this._startBatchInstallProcess(selectedApps);
      else {
          var response = new DependencyProcessor(null, true).processBatchDependencies(apps);
          if (response && response.dependencies) {
              var responsePayload = response.dependencies;
              this._processDependencies(responsePayload.dependencies);
              this._processConflicts(responsePayload.conflicts);
              if (this.blockingDependencies.length > 0)
                  this.installationResponse.error = this.INSTALLATION_ERROR_MESSAGE;
              else if (this.conflictingDependencies.length > 0)
                  this.installationResponse.warning = this.INSTALLATION_WARNING_MESSAGE;
              else
                  this._startBatchInstallProcess(selectedApps);
          }
      }
  },

  _getAppDependencies: function(sys_id, installationDetails) {
      return global.JSUtil.nil(installationDetails.dependencies) ? new AppsData().getAppRecord(sys_id).getValue('dependencies') : installationDetails.dependencies;
  },

  _startBatchInstallProcess: function(selectedApps) {
      var batchInfo;
      try {
          var installationPlan = this._getBatchInstallPayload(selectedApps);
          if (installationPlan) {
              if (installationPlan && installationPlan.hasOwnProperty('name') && installationPlan.hasOwnProperty('packages') && installationPlan.packages.length > 0) {
                  batchInfo = new AppUpgrader().installBatch(JSON.stringify(installationPlan), false);
                  if (batchInfo != null)
                      this.installationResponse.batchInfo = JSON.parse(batchInfo);
                  else
                      this.installationResponse.error = gs.getMessage('Unknown error. Failed to install product');
              } else {
                  this.installationResponse.error = gs.getMessage('Invalid product payload');
              }
          }
      } catch (e) {
          this.installationResponse.error = gs.getMessage("Failed to process product Install: {0}", e);
      }
  },

  _getBatchInstallPayload: function(selectedApps) {
      var batchPayload = {
          name: this.productName || 'Adminx batch install' + new GlideDateTime().getDisplayValue(),
          packages: []
      };
      var payload;
      for (var key in selectedApps) {
          if (selectedApps[key].isPlugin)
              payload = this._getPluginPayload(selectedApps[key]);
          else
              payload = this._getAppPayload(selectedApps[key]);

          batchPayload.packages.push(payload);
      }

      return batchPayload;
  },

  _getAppPayload: function(app) {
      var app_payload = {
          id: app.sys_id,
          type: 'application',
          load_demo_data: app.loadDemoData,
          requested_version: app.versionObj.version
      };
      if (app.customizedAppSelectedVersion)
          app_payload.requested_customization_version = app.customizedAppSelectedVersion;

      return app_payload;
  },

  _getPluginPayload: function(plugin) {
      var plugin_payload = {
          id: plugin.plugin_id,
          type: 'plugin',
          load_demo_data: plugin.loadDemoData
      };
      if (plugin.customizedAppSelectedVersion)
          plugin_payload.requested_customization_version = plugin.customizedAppSelectedVersion;

      return plugin_payload;
  },

  _processDependencies: function(dependencies) {
      var childDependencies;
      for (var batchItem in dependencies) {
          childDependencies = dependencies[batchItem];
          childDependencies = childDependencies.filter(function(childDependency) {
              return !childDependency.active;
          });
          if (childDependencies.length > 0)
              this.blockingDependencies.push({
                  "batchItemName": this.batchInstallMap[batchItem],
                  "dependencies": childDependencies
              });
      }
  },

  _processConflicts: function(conflicts) {
      for (var batchItem in conflicts) {
          this.conflictingDependencies.push(conflicts[batchItem]);
      }
  },

  _getInstallationResponse: function(id, installationAllowed, installationSuccess, progressId, msg) {
      return {
          id: id,
          installationAllowed: installationAllowed,
          installationSuccess: installationSuccess,
          progressId: progressId,
          message: msg
      };
  },

  _isCurrentDomainSafe: function() {
      if (gs.getProperty("glide.sys.domain.delegated_administration", "false") == "true")
          return (global.JSUtil.nil(gs.getUser().getDomainID()) || gs.getUser().getDomainID() === 'global');

      return true;
  },

  _isInstallationAllowed: function() {
      if (GlidePluginManager.isUpgradeSystemBusy())
          return {
              id: "SYSTEM_BUSY",
              installationAllowed: false,
              message: gs.getMessage(this.ANOTHER_OPERATION_IS_RUNNING_MESSAGE, gs.getMessage("Upgrade system is busy running an upgrade"))
          };
      if (!sn_app_api.AppStoreAPI.isUpdateMutexAvailable())
          return {
              id: "SYSTEM_BUSY",
              installationAllowed: false,
              message: gs.getMessage(this.ANOTHER_OPERATION_IS_RUNNING_MESSAGE, gs.getMessage(this._getCurrentMutexMessage()))
          };
      if (!(gs.hasRole('admin') || gs.hasRole('sn_appclient.app_client_user')))
          return {
              id: "INSUFFICIENT_PRIVILEGE",
              installationAllowed: false,
              message: gs.getMessage("Insufficient privileges to install or update application packages.")
          };
      if (!this._isCurrentDomainSafe())
          return {
              id: "INCORRECT_DOMAIN",
              installationAllowed: false,
              message: gs.getMessage("You must be part of global domain to install or update application packages.")
          };

      return {
          installationAllowed: true
      };
  },

  _getCurrentMutexMessage: function() {
      var gr = new GlideRecord('sys_status');
      gr.addQuery('name', 'update_mutex_status_message');
      gr.query();
      gr.next();

      var msg = gr.isValidRecord() ? gr.getValue('value') : '';

      return global.JSUtil.nil(msg) ? "Unknown update operation" : msg;
  },

  type: 'AppPluginInstallation'
};

Sys ID

948929a8538b4510d0f9ddeeff7b1254

Offical Documentation

Official Docs: