Name

sn_appclient.AppsData

Description

Script Include to get all apps and their logos.

Script

var AppsData = Class.create();
AppsData.prototype = {
  
  CANNOT_READ_MESSAGE : "Insufficient privileges to read records from table {0}",
  	
  initialize: function(isMaint) {
  	this.versionComparator = new VersionComparator();
  	this.domainName = new ScopedAppRepoRequest().getUploadUrl();
  	this.validScopeKeys = gs.getProperty("sn_appauthor.all_company_keys", gs.getProperty("glide.appcreator.company.code")).split(",");
  	/*Add "x_ to all valid scope keys"*/
  	this.validScopeKeys = this.validScopeKeys.map(function(key, index) {
  		var validScopeTemplate = "x_{0}_";
  		return validScopeTemplate.replace("{0}", key.toLowerCase());
  	});
  	this.validScopeKeys.push("sn_");
  	this.validScopeKeys.push("global");
  	this.instanceId = gs.getProperty("instance_id");
  	this.storeDetailButtons = {
  		"get": gs.getMessage("Get"),
  		"buy": gs.getMessage("Buy"),
  		"try": gs.getMessage("Try"),
  		"request-app": gs.getMessage("Request App"),
  		"request-trial": gs.getMessage("Request Trial"),
  		"request-demo": gs.getMessage("Request a Demo"),
  		"app-requested": gs.getMessage("App Requested"),
  		"app-request-rejected": gs.getMessage("App Request Rejected"),
  		"purchased": gs.getMessage("Purchased"),
  		"trial-requested": gs.getMessage("Trial Requested"),
  		"trial-rejected": gs.getMessage("Trial Rejected"),
  		"trial-expiry-date": gs.getMessage("Trial Expires on "),
  		"trial-expired": gs.getMessage("Trial Expired"),
  		"trial-deactivated": gs.getMessage("Trial Deactivated"),
  		"quote-requested": gs.getMessage("Quote Requested"),
  		"purchase-with-po": gs.getMessage("Purchase with PO"),
  		"cancel-quote": gs.getMessage("Cancel Quote"),
  		"resend-quote": gs.getMessage("Resend Quote"),
  		"po-submitted": gs.getMessage("PO Submitted"),
  		"complete-purchase": gs.getMessage("Complete Purchase"),
  		"view-company-profile": gs.getMessage("View Company Profile"),
  		"request-install": gs.getMessage("Request Install"),
  		"view-requests": gs.getMessage("View Requests"),
  		"contact-seller": gs.getMessage("Contact Seller"),
  		"view-product": gs.getMessage("View Products"),
  		"go-to-install": gs.getMessage("Go to install")
  	};
  	this.indicatorMessages = {
  		"service_graph_certified": gs.getMessage("Service Graph Certified"),
  		"submitted_purchase_order": gs.getMessage("Processing Submitted Purchase Order"),
  		"pending_purchase_status": gs.getMessage("Please Complete Purchase in Store"),
  		"expecting_purchase_order": gs.getMessage("Expecting Purchase Order"),
  		"approved_purchase_request": gs.getMessage("Approved Purchase Request"),
  		"approved_trial_request": gs.getMessage("Approved Trial Request"),
  		"processing_purchase_request": gs.getMessage("Processing Purchase Request"),
  		"processing_trial_request": gs.getMessage("Processing Trial Request"),
  		"processing_quote_request": gs.getMessage("Processing Quote Request"),
  		"rejected_purchase_request": gs.getMessage("Rejected Purchase Request"),
  		"rejected_trial_request": gs.getMessage("Rejected trial request"),
  	};
  	this.termsAndConditionMap = {
  		"servicenow_terms_of_use": gs.getMessage("ServiceNow Store Terms Of Use"),
  		"servicenow_terms_of_use_beta": gs.getMessage("ServiceNow Store Beta Terms Of Use"),
  		"vendor_terms_and_conditions": gs.getMessage("Vendor App Subscription Terms and Conditions"),
  		"innovation_lab_app_addendum": gs.getMessage("ServiceNow Innovation Lab App Addendum"),
  		"servicenow_store_app_addendum": gs.getMessage("ServiceNow Store App Addendum")
  	};
  	this.infoMessagesMap = {
  		"trial_not_allowed_on_prod": gs.getMessage("You are on a production instance. The trial is active but is only allowed on your sub production instances."),
  		"purchase_requested": gs.getMessage("Your purchase request has already been submitted."),
  		"purchase_requested_other_version": gs.getMessage("An app request has been made on another version of this app and is pending review/purchase."),
  	};
  	this.storeFilterIndicators = this.generateFilterIndicatorObject();
  	this.listOfAppsWithNoInstalledFromInfo = {};
  	this.isFirstLoad = false;
  	this.overrideButtonToLinks = ["contact-seller", "view-company-profile"];
  	this.glideAppLoader = new GlideAppLoader();
  	this.isMaint = !!isMaint;
  },
  generateFilterIndicatorObject: function() {
  	var indicatorObj = {};
  	var i = 0;
  	for (var indicator in this.indicatorMessages) {
  		indicatorObj[indicator] = {
  			id: indicator,
  			message: this.indicatorMessages[indicator],
  			order: i
  		};
  		i++;
  	}
  	return indicatorObj;
  },

/*
 Connect to store to get all store apps. This payload includes
 1. All store apps in e-commerce interface
 2. Recommended store apps.
 */
  getAllStoreApps: function() {
      if(gs.getProperty("sn_appclient.client_calls_allowed","false") == "false" || gs.getProperty("sn_appclient.app.install.offline","true") == "true") {
              gs.info("getAllStoreApps returning without calling repo as client_calls_allowed is false");
              return {data: {}};
      }
  
      var allStoreAppsRequest = new ScopedAppRepoRequest("get_store_apps");
          allStoreAppsRequest.setParameter("instance_id", gs.getProperty("instance_id")),
          candidateStoreApps = allStoreAppsRequest.post(),
          allStoreAppsRequestStatusCode = allStoreAppsRequest.getStatusCode(),
          response = {data: {}};
      if(allStoreAppsRequestStatusCode == 200) {
          response.data = new global.JSON().decode(candidateStoreApps);
  	this.localizeFilterIndicators(response.data.apps);
      }
      response.statusCode = allStoreAppsRequestStatusCode;
      return response;
  },

  localizeFilterIndicators: function(data) {
  	if (data.errors) {
  		gs.error(data.message + " : " + data.errors[0]);
  		return;
  	}

  	data.forEach(function(app) {
  		if(app.filterIndicators)
  			app.filterIndicators.forEach(function(indicator, index) {
  				app.filterIndicators[index] = this.storeFilterIndicators[indicator] ? this.storeFilterIndicators[indicator] : indicator;
  			}, this);
  	}, this);
  },
  
  getStoreFilters: function() {
      if(gs.getProperty("sn_appclient.client_calls_allowed","false") == "false" || gs.getProperty("sn_appclient.app.install.offline","true") == "true") {
              gs.info("getStoreFilters returning without calling repo as client_calls_allowed is false");
              return {data: {}};
      }
  
      var allStoreFilters = new ScopedAppRepoRequest("get_store_filters");
          allStoreFilters.setParameter("instance_id", gs.getProperty("instance_id")),
          candidateStoreApps = allStoreFilters.post(),
          allStoreFiltersStatusCode = allStoreFilters.getStatusCode(),
          response = {data: {}};
      if(allStoreFiltersStatusCode == 200)
          response.data = new global.JSON().decode(candidateStoreApps);
      response.statusCode = allStoreFiltersStatusCode;
      return response;
  },

  getAllApps: function(){
      new UpdateChecker().checkAvailableUpdates();
  	var apps = [];
  	this._addNewApps(apps);
  	this._addInstalledApps(apps);
  	var custom = [];
  	this._addCustomApps(custom);
  	return {
  		data: apps,
  		custom: custom
  	};
  },

  getCustomApps: function(){
      var custom = [];
      this._addCustomApps(custom);
      return {
      	custom: custom
      };
  },

  getLatestAppBlockStatus: function(sourceAppId, version) {
  	var result = {"blockInstall": true};
  	new UpdateChecker().checkAvailableUpdates(true, true);
  	var gr = new GlideRecord("sys_app_version");
  	gr.addQuery("source_app_id", sourceAppId);
  	gr.addQuery("version", version);
  	gr.query();
  	if(!gr.next())
  		return result;

  	result.blockInstall = gr.block_install.toString() === "true";
  	if(result.blockInstall) {
  		result.blockMessage = gr.getValue("block_message");
  		result.appCompatibility = gr.getValue("compatibilities") ? gr.getValue("compatibilities").split(",") : [];
  		result.instanceOnBuild = gs.getProperty("glide.buildname");
  	}

  	return result;
  },

  getAllAppsFromLocal: function(sharedInternally, isFirstLoad, hideOnUiAppScope, sysIdList) {
  	var starttime = new GlideDateTime().getNumericValue();
  	var apps = [];
  	this.hideOnUiAppScope = hideOnUiAppScope;
  	var inActiveAppSysIdMap = this._addInactiveInstalledApps(apps, sharedInternally);
  	this._addNewApps(apps, sharedInternally, inActiveAppSysIdMap, sysIdList);
  	this._addInstalledApps(apps, sharedInternally, sysIdList);
  	this._addVersionsToApps(apps);
      var endtime = new GlideDateTime().getNumericValue();
  	return {
  		data: apps,
  		appServer: gs.getProperty("sn_appclient.store_base_url", "http://localhost:8080/"),
          dataProcessingTime: endtime - starttime,
          storeURL: this.domainName
  	};
  },
  
  getAllAppsWithVersions: function(sharedInternally, isFirstLoad, hideOnUiAppScope, forceUpdate){
  	var cachedStoreAppResponse = new global.AppManagerCache().getResponseFromCache("storeResponse", sharedInternally);
  	if(gs.nil(cachedStoreAppResponse) || cachedStoreAppResponse.data.length == 0 || forceUpdate) {
  		var localResponse = this.getAllAppsFromLocal(sharedInternally, isFirstLoad, hideOnUiAppScope);
  		new global.AppManagerCache().putResponseInCache("storeResponse", localResponse, sharedInternally);
  		cachedStoreAppResponse = localResponse;
  		cachedStoreAppResponse['servedFromDB'] = true;
  	}

  	if(isFirstLoad) {
  		var storeSyncTrackerId = this.checkUpdatesFromStore(sharedInternally);
  		cachedStoreAppResponse['storetrackerId'] = storeSyncTrackerId;
  	}

  	return cachedStoreAppResponse;
  },

  putStoreResponseInAppManagerCache: function(sharedInternally, appMap, forceUpdate) {
  	var sysIdList = [];
  	if(!gs.nil(appMap))
  		sysIdList = Object.keys(appMap);

  	var cachedStoreAppResponse = new global.AppManagerCache().getResponseFromCache("storeResponse", sharedInternally);
  	var localResponse = {};
  	if(gs.nil(cachedStoreAppResponse) || cachedStoreAppResponse.data.length == 0 || forceUpdate || sysIdList.length == 0) {
  		localResponse = this.getAllAppsFromLocal(sharedInternally, false, false);
  		new global.AppManagerCache().putResponseInCache("storeResponse", localResponse, sharedInternally);
  	} else {
  		localResponse = this.getAllAppsFromLocal(sharedInternally, false, false, sysIdList);
  		this.updateAppsInCache(localResponse, sharedInternally);
  	}
  },

  updateAppsInCache: function(localResponse, sharedInternally) {
  	if(gs.nil(localResponse) || gs.nil(localResponse.data) || localResponse.data.length == 0)
  		return;

  	var args = {};
  	args.specificAppsToUpdate = [];
  	args.sharedInternally = sharedInternally;
  	args.appsList = localResponse.data;

  	localResponse.data.forEach(function(app){
  		args.specificAppsToUpdate.push({
  			sourceAppId: app.sys_id
  		});
  	});

  	new global.AppManagerCache().removeAndAppendCorrectAppsInCache(args);
  },

  _addNewApps: function(/*[]*/ apps, sharedInternally, inActiveAppSysIdMap, sysIdList) {
  	var appDetails = new GlideRecordSecure('sys_remote_app');
  	appDetails.addQuery("shared_internally", sharedInternally);
      appDetails.orderByDesc('sys_created_on');

      if (!gs.nil(sysIdList) && sysIdList.length > 0) {
          appDetails.addQuery("sys_id", "IN", sysIdList.join());
      }

      appDetails.query();
      while(appDetails.next()) {
          if (this.isVisible(appDetails)){
  	var app = this._getAppDetails(appDetails);
  	if(inActiveAppSysIdMap[app.sys_id])
  	   app.is_uninstalled_with_retain_data = true;
              apps.push(app);
      }
  		
      }
  	
  	// Assumes no store app is ever deleted from the store
  	appDetails = new GlideRecordSecure('sys_store_app');
      appDetails.addActiveQuery();
      appDetails.addNullQuery('version');
      appDetails.addQuery("shared_internally", sharedInternally);
      appDetails.orderByDesc('sys_created_on');
      if (!gs.nil(sysIdList) && sysIdList.length > 0) {
          appDetails.addQuery("sys_id", "IN", sysIdList.join());
      }
      appDetails.query();
      while(appDetails.next()) {
          if (this.isVisible(appDetails))
              apps.push(this._getAppDetails(appDetails));
      }
  },
  
  _addInstalledApps: function(/*[]*/ apps, sharedInternally, sysIdList, useGlideRecord) {
      //DEF0334116:Made a flag to use GlideRecord instead of GlideRecordSecure if the call is made from AppUpgrader, post installation.
      var appDetails = useGlideRecord? new GlideRecord('sys_store_app'): new GlideRecordSecure('sys_store_app');
      if(sharedInternally){
      	appDetails.addQuery("shared_internally",sharedInternally);
      }else{
      	var gc = appDetails.addNullQuery("shared_internally");
      	gc.addOrCondition("shared_internally",sharedInternally);
      }
  	
      if (!gs.nil(sysIdList) && sysIdList.length > 0) {
          appDetails.addQuery("sys_id", "IN", sysIdList.join());
      }
      appDetails.addActiveQuery();
      appDetails.addNotNullQuery('version');
      appDetails.orderByDesc('update_date');
      appDetails.query();
      while(appDetails.next()) {
          this.captureAppsWithNoLastInstalledFrom(appDetails);
          if (this.isVisible(appDetails))
              apps.push(this._getAppDetails(appDetails));
      }
      this.updateAppstorePlugins();
  },
  
  _addInactiveInstalledApps: function(/*[]*/ apps, sharedInternally) {
  	  var inActiveAppSysIdMap = {};
      var appDetails = new GlideRecordSecure('sys_store_app');
      var appDetailsBuilder = appDetails.addQuery("shared_internally", sharedInternally);
      if(!sharedInternally)
          appDetailsBuilder.addOrCondition("shared_internally", "=", "NULL");
      appDetails.addQuery("active", false);
      appDetails.addNotNullQuery('version');
      appDetails.orderByDesc('update_date');
      appDetails.query();
      while(appDetails.next()) {
        var isRemoteUpdateAvailable = this._isRemoteUpdateAvailable(appDetails);
        var isVisible = this.isVisible(appDetails);
          if (!isRemoteUpdateAvailable && isVisible)
              apps.push(this._getAppDetails(appDetails));
          else if (isRemoteUpdateAvailable && isVisible)
          	 inActiveAppSysIdMap[appDetails.getValue("sys_id")] = true;
      }
      return inActiveAppSysIdMap;
  },
  
  _isRemoteUpdateAvailable: function(appDetails) {
      var sysRemoteApp = new GlideRecord("sys_remote_app");
      sysRemoteApp.get(appDetails.getValue("sys_id"));
      
      return sysRemoteApp.isValid();
  },
  
  _addCustomApps: function(/*[]*/ custom) {
      var customApps = new GlideRecordSecure('sys_app');
      if(customApps.isValid()) {
          customApps.orderByDesc('sys_created_on');
          customApps.query();
          while(customApps.next()) {
              custom.push(this._getAppDetails(customApps));
          }
      } else {
          gs.info(gs.getMessage(this.CANNOT_READ_MESSAGE, 'sys_app'));
      }
  },

  _addVersionsToApps: function(/*array*/ apps) {
  	var i;
  	for(i=0; i<apps.length; i++) {
  		app = apps[i];
  		this._addAppVersions(app);
  	}
  },

  _addAppVersions: function(/*{app}*/ app) {
  	app.versions = [];
  	var versions = new GlideRecord("sys_app_version");
  	versions.addQuery("source_app_id", app.sys_id);
  	versions.query();
  	while (versions.next()) {
  		var has_manifest = !gs.nil(versions.getValue("manifest")) && versions.manifest.contains('app_info');
          		if(app.version && app.version == versions.getValue("version")) {
  			app.has_manifest = this.isInstanceOffline() ? false : true;
          		} else if (app.latest_version && app.latest_version == versions.getValue("version")) {
  			app.has_manifest = this.isInstanceOffline() ? false : true;
          		}
  		//remember app is *NOT* a GlideRecord
  		if (this.versionComparator.isDowngrade(app.version, versions.getValue("version")))
  			continue;

  		var tempObj = {};
  		if(versions.isValidField('needs_app_engine_licensing'))
  			tempObj.needs_app_engine_licensing = versions.needs_app_engine_licensing ? true : false;
  		if(versions.isValidField('custom_table_count'))
  			tempObj.custom_table_count = versions.custom_table_count.toString();
  		tempObj.auto_update = versions.getValue("auto_update");
  		tempObj.demo_data = versions.getValue("demo_data") == "has_demo_data" ? true : false;
  		tempObj.dependencies = versions.getValue("dependencies");
  		tempObj.name = versions.getValue("name");
  		tempObj.number = versions.getValue("number");
  		tempObj.publish_date = versions.getValue("publish_date");
  		tempObj.publish_date_display = versions.getValue("publish_date");
  		tempObj.remote_application = versions.getValue("remote_application");
  		tempObj.scope = versions.getValue("scope");
  		tempObj.short_description = versions.getValue("short_description");
  		tempObj.source_app_id = versions.getValue("source_app_id");
  		tempObj.sys_id = versions.getValue("sys_id");
  		tempObj.title = versions.getValue("title");
  		tempObj.vendor = versions.getValue("vendor");
  		tempObj.vendor_key = versions.getValue("vendor_key");
  		tempObj.version = versions.getValue("version");
  		tempObj.block_install = versions.block_install ? true: false;
  		tempObj.block_message = versions.getValue("block_message");
          tempObj.compatibilities = versions.compatibilities.toString();
  		tempObj.version_display = this._getMajorAndMinorDisplayVersion(tempObj.version);
          tempObj.store_link = versions.getValue("is_store_app") ?
                  this._getStoreLink(tempObj.source_app_id, tempObj.version) : "";
  	        tempObj.has_manifest = this.isInstanceOffline() ? false : true;
  		//add a pretty display date for publish_date
  		tempObj.price_type = versions.getValue("price_type") || "";
  		tempObj.lob = new global.JSON().decode(versions.getValue("lob")) ? new global.JSON().decode(versions.getValue("lob")) : [];
  		tempObj.indicators = new global.JSON().decode(versions.getValue("indicators")) ? new global.JSON().decode(versions.getValue("indicators")) : [];
  		tempObj.display_message = versions.getValue("display_message") || "";
  		tempObj.upload_info = versions.getValue("upload_info") || "";
  		if (tempObj.publish_date) {
  			var displayDate = new GlideClientDate();
  			displayDate.setValue(tempObj.publish_date.toString());
  			tempObj.publish_date_display = displayDate.getDisplayValue();
  		}
  		app.versions.push(tempObj);
  	}

  	var that = this;
  	app.versions.sort(function (a, b) {
  		if (that.versionComparator.isDowngrade(a.version, b.version))
  			return 1;

  		if (that.versionComparator.isUpgrade(a.version, b.version))
  			return -1;

  		if (that.versionComparator.isEqual(a.version, b.version))
  			return 0;
  	});


  	for (var i=0; i<app.versions.length; i++) {
  		app.versions[i].sortable_version = i + 1;
  	}
  },


  _getProductsList: function(productFamilyList) {
  	productFamilyList = JSON.parse(productFamilyList) || [];
  	var products = [];
  	var addedProductIds = {};
  	for(var i in productFamilyList) {
  		for(var j in productFamilyList[i].productList) {
  			var productObj = productFamilyList[i].productList[j];
  			if(addedProductIds.hasOwnProperty(productObj.productId) && addedProductIds[productObj.productId])
  				continue;
  			products.push(productObj);
  			addedProductIds[productObj.productId] = true;
  		}
  	}
  	return products;
  },
  
  getLogo: function(/*GlideRecord sys_remote_app | sys_store_app | sys_app */ appDetails) {
  	var logo = "";
  	if(!this.isInstanceOffline() && (appDetails.getValue("sys_class_name") != 'sys_app') && appDetails.getValue("logo") && (appDetails.getValue("logo") != 'undefined'))
  		logo = this.getStoreURL() + appDetails.logo.toString() + ".iix" ;
  	
  	 if (!logo) {
  		var logoGR = new GlideRecord('sys_attachment');
  		logoGR.addQuery('table_sys_id', appDetails.sys_id.toString());
  		logoGR.addQuery('file_name', 'logo');
  		logoGR.query();
  		if (logoGR.next())
  			logo = logoGR.getValue("sys_id")+".iix";
  	}
  	return logo;
  	
  },

  _getAppDetails: function(/*GlideRecord sys_remote_app | sys_store_app | sys_app */ appDetails) {
  	var tempobj = {};
  	tempobj.logo = this.getLogo(appDetails);
  	tempobj.short_description = appDetails.short_description.toString();
  	if(appDetails.isValidField('needs_app_engine_licensing'))
  		tempobj.needs_app_engine_licensing = appDetails.needs_app_engine_licensing ? true : false;
  	if(appDetails.isValidField('custom_table_count'))
  		tempobj.custom_table_count = appDetails.custom_table_count.toString();
  	tempobj.name = appDetails.name.toString();
  	tempobj.vendor = appDetails.vendor.toString();
  	tempobj.vendor_prefix = appDetails.vendor_prefix.toString();
  	tempobj.link = this._checkAppIsProperlyInstalled(appDetails) ? this._getAppLink(appDetails) : ""; //Link to the app should be given only when app is propertly installed.
  	tempobj.scope = appDetails.scope.toString();
  	tempobj.compatibilities = appDetails.compatibilities ? appDetails.compatibilities.toString() : "" ;
  	tempobj.active = appDetails.isValidField('active') ? appDetails.active.toString() == 'true' : false;
  	tempobj.price_type = appDetails.getValue("price_type") || "" ;
  	tempobj.lob = new global.JSON().decode(appDetails.getValue("lob")) ? new global.JSON().decode(appDetails.getValue("lob")) : [];
  	tempobj.source = appDetails.getValue("sys_class_name") ? appDetails.getValue("sys_class_name") : "";
  	tempobj.shared_internally = appDetails.getValue("shared_internally");
  	tempobj.indicators = new global.JSON().decode(appDetails.getValue("indicators")) ? new global.JSON().decode(appDetails.getValue("indicators")) : [];
  	if (tempobj.indicators && tempobj.indicators.length > 0)
  		tempobj.indicators.forEach(function(indicator){
  			if ("not_licensed" == indicator.id)
  					tempobj.entitled = 'no';
  		});
  	tempobj.display_message = appDetails.getValue("display_message");
  	tempobj.upload_info = appDetails.getValue("upload_info") || "";
  	tempobj.products = this._getProductsList(appDetails.getValue("products"));

  	if(appDetails.getTableName() == "sys_app")
  		tempobj.side_loaded = this._checkForSideLoading(appDetails);
  	

  	var install_date = null;
  	if (appDetails.isValidField('install_date') && !appDetails.install_date.nil()) {
  		install_date = new GlideClientDate();
  		install_date.setValue(appDetails.install_date);
  	} else if (appDetails.isValidField('version') && !gs.nil(appDetails.version)) {
  		install_date = new GlideClientDate();
  		install_date.setValue(appDetails.sys_created_on);
  	}

  	var update_date = '';
  	if (appDetails.isValidField('update_date') && !appDetails.update_date.nil()) {
  		update_date = new GlideClientDate();
  		update_date.setValue(appDetails.update_date);
  	}

  	tempobj.install_date = gs.nil(install_date) ? '' : install_date.getDisplayValue();
  	tempobj.update_date = gs.nil(update_date) ? '' : update_date.getDisplayValue();

  	if ('sys_remote_app' == appDetails.getRecordClassName()) {
  		tempobj.version = "";
  		tempobj.assigned_version = "";
  		if (!gs.nil(appDetails.latest_version)) {
  			tempobj.latest_version = appDetails.latest_version.toString();
  			tempobj.latest_version_display = this._getMajorAndMinorDisplayVersion(appDetails.latest_version.toString());
  		} else {
  			tempobj.latest_version = tempobj.version;
  		}
  		tempobj.block_install = appDetails.block_install ? true: false;
  		tempobj.block_message = appDetails.block_message.toString();
  		tempobj.uninstall_blocked = appDetails.uninstall_blocked ? true : false;
  	} else {
  		if(appDetails.guided_setup_guid && appDetails.guided_setup_guid.toString())
  			tempobj.guided_setup_guid = appDetails.guided_setup_guid.toString();
  		if (!gs.nil(appDetails.version)) {
  			tempobj.version = appDetails.version.toString();
  			tempobj.version_display = this._getMajorAndMinorDisplayVersion(appDetails.version.toString());
  		} else
  			tempobj.version = "";

  		if (appDetails.isValidField('assigned_version') && !gs.nil(appDetails.assigned_version))
  			tempobj.assigned_version = appDetails.assigned_version;
  		else
  			tempobj.assigned_version = tempobj.version;

  		if (appDetails.isValidField('latest_version') && !gs.nil(appDetails.latest_version)) {
  			//gs.debug("App: {0} Latest version: {1} Version: {2} ", appDetails.name.toString(), appDetails.latest_version.toString(), appDetails.version.toString());
  			tempobj.latest_version = appDetails.latest_version.toString();
  			tempobj.latest_version_display = this._getMajorAndMinorDisplayVersion(appDetails.latest_version.toString());
  			// if the versions are in fact different, the UI must show a difference
  			if (tempobj.version != tempobj.latest_version && tempobj.version_display == tempobj.latest_version_display)
  				tempobj.latest_version_display = tempobj.latest_version;

  			//gs.debug("tempobj is {0}", new global.JSON().encode(tempobj));
  		} else {
  			tempobj.latest_version = tempobj.version;
  			tempobj.latest_version_display = tempobj.version_display;
  			//gs.debug("App: {0} Set latest version to {1} and display to {2} ", appDetails.name, tempobj.version, tempobj.version_display);

  		}
  	}

  	tempobj.demo_data = appDetails.isValidField('demo_data')
  		? appDetails.demo_data.toString()
  	: '';
  	tempobj.sys_id = appDetails.sys_id.toString();
  	tempobj.sys_updated_on = appDetails.sys_updated_on.toString();
  	tempobj.sys_created_on = appDetails.sys_created_on.toString();

      var canCustomize = sn_app_customization.AppCustomizationAPI.isAppCustomizationCapableById(tempobj.sys_id);
      var canEditInStudio = appDetails.can_edit_in_studio == true ? true : false;
      tempobj.can_edit_in_studio = canEditInStudio && canCustomize;

      tempobj.can_open_in_studio = !canEditInStudio && canCustomize;
      tempobj.is_customized_app = sn_app_customization.AppCustomizationAPI.isCustomizedAppOnAllAppsPage(tempobj.sys_id);
      tempobj.can_install_or_upgrade_customization = sn_app_customization.AppCustomizationAPI.canInstallOrRepairCustomization(tempobj.sys_id);

      tempobj.customized_version_info = sn_app_customization.AppCustomizationAPI.getCustomizationVersionInfo(tempobj.sys_id);
      tempobj.customized_version_info.latest_customized_version = this._getLatestCustomizedVersion(tempobj.customized_version_info.customization_versions) || tempobj.customized_version_info.customized_version_default;

  	var storeVersion = tempobj.version ? tempobj.version : tempobj.latest_version;
      tempobj.is_store_app = appDetails.is_store_app ? true: false;
      tempobj.store_link = tempobj.is_store_app ? this._getStoreLink(tempobj.sys_id, storeVersion) : "";

  	var createdOn = new GlideClientDate();
  	createdOn.setValue(appDetails.sys_created_on.toString());
  	tempobj.sys_created_on_display = createdOn.getDisplayValue();

  	var updatedOn = new GlideClientDate();
  	updatedOn.setValue(appDetails.sys_updated_on.toString());
  	tempobj.sys_updated_on_display = updatedOn.getDisplayValue();

  	var displayDate;
  	if ('sys_store_app' == appDetails.getRecordClassName()) {
  		tempobj.isSubscriptionApplicable = (gs.hasRole("admin") || gs.hasRole("maint") || this.isMaint) && tempobj.needs_app_engine_licensing && GlideCustomTableUtils.getUnmappedTableCount("Application", appDetails.sys_id.toString()) > 0;
  		if(tempobj.isSubscriptionApplicable)
  			tempobj.inventoryURI = GlideCustomTableUtils.getInventoryURI("Application", appDetails.sys_id.toString());
  		if (!appDetails.update_date.nil()) {
  			displayDate = new GlideClientDate();
  			displayDate.setValue(appDetails.update_date.toString());
  			tempobj.publish_date_display = displayDate.getDisplayValue();
  		}
  		tempobj.isAppstorePlugin =  sn_app_api.AppStoreAPI.isAppstorePlugin(appDetails.getValue("scope"), appDetails.getValue("sys_code"));
  		tempobj.uninstall_blocked =  !this.glideAppLoader.canUninstall(appDetails.getValue("scope"), appDetails.getValue("sys_code"));
  		tempobj.sys_code = appDetails.sys_code.toString();
  	} else {
  		displayDate = new GlideClientDate();
  		var publishDate = appDetails.isValidField('publish_date')
  		&& !appDetails.publish_date.nil() ? appDetails.publish_date.toString() : appDetails.sys_updated_on.toString();
  		displayDate.setValue(publishDate);
  		tempobj.publish_date_display = displayDate.getDisplayValue();
  		if (appDetails.isValidField("delivery_source"))
  			tempobj.isAppstorePlugin = ["store","offline","out_of_band"].indexOf(appDetails.delivery_source.toString()) != -1;
  	}

  	tempobj.can_install_or_upgrade = this._canInstallOrUpgrade(appDetails);
  	tempobj.isInstalled = tempobj.active && !gs.nil(tempobj.version);
  	if(tempobj.isInstalled){
  		var isLatestVersionHigher = new VersionComparator().isUpgrade(tempobj.version, tempobj.latest_version);
  		tempobj.isInstalledAndUpdateAvailable = isLatestVersionHigher && tempobj.can_install_or_upgrade;

          var isLatestCustomizationVersionHigher = false;
          if (tempobj.customized_version_info.hasOwnProperty('currently_installed_customization'))
              isLatestCustomizationVersionHigher = new VersionComparator().isUpgrade(tempobj.customized_version_info.currently_installed_customization,  tempobj.customized_version_info.customized_version_default);
  		tempobj.isCustomizationUpdateAvailable = isLatestCustomizationVersionHigher && tempobj.can_install_or_upgrade_customization;
  	}
  	if (appDetails.isValidField('installed_as_dependency'))
  		tempobj.installed_as_dependency = appDetails.installed_as_dependency.toString() == "true" ?  true : false;
  	//gs.debug("Including " + appDetails.getRecordClassName() + ": " + new global.JSON().encode(tempobj));
  	tempobj.app_schedule_details = new ScheduledInstallService().fetchActiveSchedulesForEntity({source_app_id: appDetails.sys_id.toString()});
  	tempobj.dependencies = appDetails.getValue("dependencies");
  	return tempobj;
  },

  _getLatestCustomizedVersion: function(customizationVersionList) {
  	if(!customizationVersionList || customizationVersionList.length == 0) {
  		return null;
  	}
  	customizationVersionList = customizationVersionList.map(function(version) {
  		return version.value;
  	}).filter(function(version) {
  		return version.value != 'none';
  	});
  	return new VersionComparator().getLatestVersion(customizationVersionList);
  },
  
  _checkForSideLoading: function(app) {
  	if(this.validScopeKeys.length === 0)
  		return false;
  	
  	for( var keyIndex = 0; keyIndex < this.validScopeKeys.length; keyIndex++ ) {
  		if(app.getValue("scope").toLowerCase().startsWith(this.validScopeKeys[keyIndex]))
  			return false;
  	}	
  	
  	return true;	
  },
  
  /*Redirect link to sys_store_app to handle apps that inactive in sys_store_app table and still have record in sys_remote_app */
  _getAppLink: function(appDetails) {
  	var table = appDetails.getTableName();
  	if(table == "sys_remote_app")
  		table = "sys_store_app";  
  	
  	var link = "/" + table + ".do?sys_id=" + appDetails.sys_id
  	
  	return link;
  },

  _canInstallOrUpgrade: function(/*GlideRecord sys_remote_app | sys_store_app*/ appDetails) {
  	if (GlidePluginManager.isActive("com.glide.app_api")) {
  		if (typeof sn_app_api.AppStoreAPI.canInstallOrUpgrade != "undefined")
  			return sn_app_api.AppStoreAPI.canInstallOrUpgrade(appDetails);
  	}

  	// admin or app_client_user is allowed to install or upgrade
  	if (gs.hasRole('sn_appclient.app_client_user'))
  		return true;

  	return false;
  },

  _getMajorAndMinorDisplayVersion: function(val) {
  	var ary = val.toString().split('.');
  	if (ary.length <= 1)
  		return val;

  	if (ary[ary.length - 1].length >= 12)
  		return val;

  	if (ary.length >= 2 && ary[0] === 0 && ary[1] === 0)
  		return val;

  	while(ary[ary.length - 1] == 0)
  		ary.pop();

  	return ary.join('.');
  },

  _checkAppIsProperlyInstalled: function(appDetails) {
  	var tableName = appDetails.getTableName();
  	if (tableName == 'sys_remote_app') {
  		var gr = new GlideRecord("sys_store_app");
  		gr.get(appDetails.sys_id);
  		if(gr.isValid() && !gr.active)
  			return true;
  		return false;
  	}
  	else if (tableName == 'sys_store_app') { // if app is aborted then also app is not properly installed so return false.
  		if (appDetails.getValue('active') == '0') {
  			var ga = new GlideAggregate('sys_metadata');
  			ga.addQuery('sys_scope', appDetails.sys_id);
  			ga.setGroup(false);
  			ga.query();
  			return ga.hasNext();
  		}
  	}
  	return true;
  },

  _getStoreLink: function (source_app_id, version) {
      return this.domainName.replace("apprepo.service-now","store.servicenow") + "sn_appstore_store.do#!/store/application/"+source_app_id+"/"+version;
  },

  checkUpdatesFromStore : function(sharedInternally, args) {
  	if(gs.nil(args))
  		args = {};
  	args.isMaint = gs.hasRole("maint");
  	 args.sharedInternally = sharedInternally;
  	 var storeSyncTrackerId = this.isStoreSyncInProgress();
  	var honourChecksum = args.hasOwnProperty("honourChecksum") ? args.honourChecksum : true;
      var isInteractive = args.hasOwnProperty("isInteractive") ? args.isInteractive : true;
      if (!gs.nil(storeSyncTrackerId))
  		return storeSyncTrackerId;
      var worker = new GlideScriptedHierarchicalWorker();
      worker.setProgressName("Checking store app updates");
      worker.setBackground(true);
      worker.setCannotCancel(true);
      worker.setScriptIncludeName("sn_appclient.UpdateChecker");
      worker.setScriptIncludeMethod("checkAvailableUpdates");
      worker.putMethodArg("isInteractive", isInteractive);
      worker.putMethodArg("honourChecksum", honourChecksum);
  	worker.putMethodArg("args", args);
      worker.start();
      return worker.getProgressID();
  },

  isStoreSyncInProgress : function(){
  	var gr = new GlideRecord("sys_progress_worker");
  	gr.addQuery("name","Checking store app updates");
  	gr.addQuery("state",'IN',"starting,running");
  	gr.orderByDesc("sys_created_on");
  	gr.setLimit(1);
  	gr.query();
  	if (gr.next()){
  		var currentDateTime = new GlideDateTime().getNumericValue();
  		var progressWorkerCreatedTime = new GlideDateTime(gr.sys_created_on).getNumericValue();
  		if ((currentDateTime - progressWorkerCreatedTime) > 3600000)
  			return "";
  		return gr.getUniqueValue();
  	}
  	return "";
  },

  entitleApp: function(sourceAppId, version, requestType){
      if(this.isInstanceOffline())
       	return;
  var request = new ScopedAppRepoRequest('entitle_app_on_instance');
  request.setParameter('source_app_id', sourceAppId);
  request.setParameter('version', version);
  request.setParameter('request_type', requestType);
  request.setParameter('user_name', gs.getUserName());
  request.post();
  var response = {data:{}};
  response.data.sourceAppId = sourceAppId;
  response.data.version = version;
  response.message = request.message;
  response.statusCode = request.getStatusCode();
  return response;
  },
  getSubscribedProductForApp: function(sourceAppId, version){
      if(this.isInstanceOffline())
  	return [];
  var request = new ScopedAppRepoRequest('entitle_app_on_instance');
  request.setParameter('source_app_id', sourceAppId);
  request.setParameter('request_type', 'get_subscribed_products');
  var subscribedProducts = new global.JSON().decode(request.post());
  var productURL = this.getProductURL();
  var response = {};
  for (var i = 0 ; i <  subscribedProducts.length ; i++)
  	subscribedProducts[i].url = productURL + subscribedProducts[i].productId;
  response.productList = subscribedProducts;
  response.status = request.getStatusCode();
  return response;
 },
 getProductURL: function(){
  var productURL = new ScopedAppRepoRequest().getUploadUrl();
  return productURL.replace("apprepo.service-now" , "store.servicenow") + "/sn_appstore_store.do#!/store/product/";
 },
 isInstanceOffline: function(){
  return gs.getProperty("sn_appclient.app.install.offline" , "true") == "true";
 },

  getAppRecord: function(sys_id, getActiveOnly) {
  	if(gs.nil(getActiveOnly)) getActiveOnly = true;

  	var gr = new GlideRecordSecure("sys_remote_app");
      	gr.addQuery("sys_id", sys_id);
  	gr.addQuery("shared_internally", false);
  	gr.query();
  	if(gr.next())
  	    return gr;

  	gr = new GlideRecordSecure("sys_store_app");
  	gr.addQuery("sys_id", sys_id);
  	getActiveOnly && gr.addQuery("active", true);
  	gr.addQuery("shared_internally", false);
  	gr.query();
  	if(gr.next())
  	    return gr;

  	return null;
  },
  
  updateAppStatusOnInstance: function(appData) {
  	var sysId = appData.source_app_id ? appData.source_app_id : appData.id;
  	var gr = this.getAppRecord(sysId);
  	if(gr) {
  		if(gr.getRecordClassName() == "sys_store_app")
  			appData.isAppUpdateAvailable = new VersionComparator().isUpgrade(appData.version, appData.latest_version) ?  this._canInstallOrUpgrade(gr) : false;
  		if(gr.getRecordClassName() == "sys_remote_app")
  			appData.isAppInstallationAvailable = true;
  		appData.isAppEntitledForInstance = true;
  		appData.isAppCompatible = true;
  		appData.appUrl = "$allappsmgmt.do?sysparm_search==" + gr.scope;
  	}else
  		appData.appUrl = this._getStoreLink(sysId, appData.version);
  },
  
  updateDependentAppStatusOnInstance: function(dependentApp) {
  	if(!dependentApp.app_list)
  		return;
  	
  	dependentApp.app_list.forEach(function(app) {
  		this.updateAppStatusOnInstance(app);
  	}.bind(this));
  },

  localizeAndSetTargetUrl: function(app) {
  	if (app.error)
  	    return;
  	app.isInstalled = this.isAppInstalled(app);
  	var connectedStoreInstance = this.domainName.replace("apprepo.service-now", "store.servicenow");
  	app.storeAppButtons.forEach(function(btn) {
  	    if (btn.id == "trial-expiry-date") {
  		var gdt = new GlideDateTime(app.trialExpiryDate);
  		btn.title = this.storeDetailButtons[btn.id] + gdt.getDate().getByFormat("MM/dd/yy");
  	    } else if(btn.id == "go-to-install" && app.isInstalled)
  		btn.title = gs.getMessage("Manage Application");
  	    else
  		btn.title = this.storeDetailButtons[btn.id];

  	    if (!btn.disabled) {
  		if (btn.redirect)
  		    btn.targetUrl = connectedStoreInstance + btn.targetUrl + "&iid=" + this.instanceId;
  		else {
  			if(btn.id == "view-product") {
  				var isAppPartOfSingleProduct = app.parentProducts.length == 1 && app.parentProducts[0].productList.length == 1;
  				btn.targetUrl = isAppPartOfSingleProduct ? "$products.do?productId=" + app.parentProducts[0].productList[0].productId : "$products.do";
  			}
  			else
  				btn.targetUrl = "$allappsmgmt.do?sysparm_search==" + app.scope;
  		}
  	    }
  	}, this);
  	if(app.termsAndConditions)
  		app.termsAndConditions.forEach(function (termsAndCondition){
  			termsAndCondition.URL = connectedStoreInstance + termsAndCondition.URL;
  			if (this.termsAndConditionMap[termsAndCondition.id])
  				termsAndCondition.title = this.termsAndConditionMap[termsAndCondition.id];
  		}, this);
  	if(app.infoMessages)
  		app.infoMessages.forEach(function (infoMessage){
  			if (this.infoMessagesMap[infoMessage.id])
  				infoMessage.message = this.infoMessagesMap[infoMessage.id];
  		}, this);
  	app.storeAppLinks = [];
  	var indexedStoreAppButton = app.storeAppButtons.map(function(ele) { return ele.id; });
  	this.overrideButtonToLinks.forEach(function(link) {
  		var overrideIndex = indexedStoreAppButton.indexOf(link);
  		if(overrideIndex > -1)
  			app.storeAppLinks.push(app.storeAppButtons.splice(overrideIndex, 1)[0]);
  	}, this);
  },

  getStoreAppDetail: function(app_id, version, requiredForPurchase) {
  	var result = {};
  	if(this.isInstanceOffline()) {
  		result.error = "client_call_not_allowed";
  		return result;
  	}
  	var appDetail = new ScopedAppRepoRequest("get_store_app_detail")
  	    .setParameter("app_id", app_id)
  	    .setParameter("version", version)
  	    .setParameter("for_purchase", requiredForPurchase);
  	var response = appDetail.get();
  	if(appDetail.getStatusCode() == 200 || appDetail.getStatusCode() == 400) {
  		try {
  			result = new global.JSON().decode(response)[0];
  			this.localizeAndSetTargetUrl(result.appDetails);
  			this.updateDependentAppStatusOnInstance(result.appDependency);
  		} catch(e) {
  			result = {};
  			result.error = gs.getMessage("Error in processing app details at : {0}", e);
  		}
  	}else
  		result.error = "no response returned";

  	return result;
      },

  getStoreAppReview: function(app_id) {
  	var result = {};
  	if(this.isInstanceOffline()) {
  		result.error = "client call not allowed";
  		return result;
  	}
  	var appDetails = new ScopedAppRepoRequest("get_store_app_review").setParameter("app_id", app_id);
  	var response = appDetails.get();
  	if(appDetails.getStatusCode() == 200 || appDetail.getStatusCode() == 400)
  		result = new global.JSON().decode(response);
  	else
  		result.error = "no response returned";
  		
  	return result;
      },

  isVisible : function (appDetails) {
  	var isInstalledAppWithCustomizations = sn_app_customization.AppCustomizationAPI.isCustomizedAppOnAllAppsPage(appDetails.sys_id) && 'sys_store_app' == appDetails.getTableName();
  	var canShowOnUI = appDetails.isValidField('hide_on_ui') && !appDetails.hide_on_ui;
  	return gs.hasRole("maint") || this.isMaint || (canShowOnUI || isInstalledAppWithCustomizations ) || (this.hideOnUiAppScope && (appDetails.scope == this.hideOnUiAppScope) && appDetails.block_install);
  },

  getLatestErrorMessage: function(requestType) {
  	var gr = new GlideRecord("sn_appclient_store_outbound_http_quota");
  	gr.get("request_type", requestType);
  	return gr.getValue("last_request_error_message") || "";
  },

  isAppstorePlugin : function(source_app_id) {
  	var storeAppGr = new GlideRecord("sys_store_app");
  	storeAppGr.addActiveQuery();
  	storeAppGr.addQuery("sys_id", source_app_id);
  	storeAppGr.query();
  	if (storeAppGr.next())
  		return sn_app_api.AppStoreAPI.isAppstorePlugin(storeAppGr.scope.toString(), storeAppGr.sys_code.toString());
  	return null;
  },
  isAppInstalled : function(app) {
  	var status = false;
  	var sysId = app.source_app_id ? app.source_app_id : app.id;
  	var gr = this.getAppRecord(sysId);
  	if (gr)
  	    status = (gr.getRecordClassName() == "sys_store_app");
  	return status;
  },

  updateAppstorePlugins : function() {
  	var appMap = this.listOfAppsWithNoInstalledFromInfo;
  	var appSysIds = Object.keys(appMap);
  	if (appSysIds.length == 0)
  		return;

  	var pluginsInfoMap = sn_app_api.AppStoreAPI.checkForAppstorePlugins(appMap);
  	var pluginInfo;
  	var store_app_sysids = Object.keys(pluginsInfoMap);
  	if (store_app_sysids.length == 0)
  		return;

  	var storeAppGr = new GlideRecord("sys_store_app");
  	storeAppGr.addQuery("sys_id", "IN", store_app_sysids);
  	storeAppGr.addNullQuery('last_installed_from');
  	storeAppGr.query();
  	while(storeAppGr.next()){
  		pluginInfo = pluginsInfoMap[storeAppGr.getUniqueValue()];
  		storeAppGr.setValue("last_installed_from" , !pluginInfo["is_appstore_plugin"]? 'dist' : 'store' );
  		if (!pluginInfo["is_appstore_plugin"] && !storeAppGr.hide_on_ui)
  			storeAppGr.setValue('hide_on_ui' , !pluginInfo["is_published"]);
  		storeAppGr.setWorkflow(false);
  		storeAppGr.update();
  	}
  },

  updateLastInstalledFrom: function() {
  	var gr = new GlideRecord("sys_store_app");
  	gr.addEncodedQuery("last_installed_from=^active=true");
  	gr.query();

  	while (gr.next()) {
  		if (gs.nil(gr.getValue("last_installed_from"))) {
  			key = gr.getValue("scope") + ":" + gr.getValue("sys_code");
  			this.listOfAppsWithNoInstalledFromInfo[key] = gr.getUniqueValue();
  		}
  	}

  	this.updateAppstorePlugins();
  },

  captureAppsWithNoLastInstalledFrom : function(appDetails){
  	var key;
  	if (gs.nil(appDetails.getValue("last_installed_from")) && this.isFirstLoad){
  		key = appDetails.getValue("scope") + ":" + appDetails.getValue("sys_code");
  		this.listOfAppsWithNoInstalledFromInfo[key] = appDetails.getUniqueValue();
  	}
  },

  isMapped : function(app_id) {
  	var scopeGR = new GlideRecord("sys_scope");
  	if (!scopeGR.get(app_id))
  		return false;

  	var licenseID = scopeGR.getValue("license");
  	return GlideStringUtil.notNil(licenseID);
  },

  canMap : function() {
  	var encodedQuery = this.getValidSubscriptionsQuery();

  	var tableGR = new GlideRecord("license_details");
  	tableGR.addEncodedQuery(encodedQuery);
  	tableGR.query();

  	return tableGR.hasNext();
  },

  enforcePreinstallMapping : function() {
  	return sn_lef.GlideEntitlement.isCustomAppSubscriptionMappingEnforced() && this.canMap();
  },
  
  getStoreURL: function() {
  	return this.domainName.replace("apprepo.service-now", "store.servicenow");
  },

  getValidSubscriptionsQuery : function() {
  	return sn_lef.GlideEntitlement.getEligibleCustomAppSubscriptionsQuery();
  },
  
  checkForInactiveInstalledApp: function(appInfo) {
  	var apps = [];
  	var inActiveAppSysIdMap = this._addInactiveInstalledApps(apps, appInfo.shared_internally);
  	if (inActiveAppSysIdMap[appInfo.sys_id]) {
  		appInfo.is_uninstalled_with_retain_data = true;
  	}
  },
  
  getAppInfoFromInstance: function(sourceAppId, appRecord) {
      if (!sourceAppId)
          throw "AppsData.getAppInfoFromInstance(): Invalid sourceAppId:" + sourceAppId;
      if (!appRecord) appRecord = this.getAppRecord(sourceAppId, false);
      if (!appRecord)
          throw "AppsData.getAppInfoFromInstance(): No app found matching sourceAppId:" + sourceAppId;
      var appInfo = this._getAppDetails(appRecord);
      var tracker = new ProgressTracker().getInProgressInstallationByAppId(sourceAppId);
      appInfo.install_tracker_id = tracker.id;
      if(tracker.id)
          appInfo.tracker = tracker;
      this.checkForInactiveInstalledApp(appInfo);
      this._addAppVersions(appInfo);
      if (appInfo.isInstalled) {
      	appInfo.new_guided_setup_id = this.getNewGuidedSetupId(sourceAppId);
      	appInfo.upgradeHistoryId = new sn_appclient.AppUpgrader().getLatestUpgradeHistory(appInfo.scope);
      	appInfo.upgradeDetailsInfo = this.getUpgradeInfo(appInfo.upgradeHistoryId);
      	var installationInfo = {};
      	installationInfo.installation_log = this.getInstallationInfo(appInfo.scope);
      	installationInfo.installed_files = this.getInstalledFilesQuery(sourceAppId);
      	installationInfo.customized_files = this.getCustomizedFiles(sourceAppId);
      	appInfo.installationInfo = installationInfo;
      	appInfo.installedFilesQuery = this.getInstalledFilesQuery(sourceAppId);
      	appInfo.customizedFilesQuery = this.getCustomizedFiles(sourceAppId);
      }
      return appInfo;
  },
  getNewGuidedSetupId: function(id) {
  	if(gs.nil(id)) return null;

  	var gr = new GlideRecord("help_guidance");
  	gr.addQuery('sys_scope', id).addOrCondition('sys_package', id);
  	gr.addQuery("type", "global_setup");
  	gr.addQuery("status", "published");
  	gr.query();
  	if (gr.next()) {
  		return gr.getUniqueValue();
  	}
  	return null;
  },
  getInstallationInfo: function(pluginId, pluginOrID){
  	var sysPluginLog = new GlideRecord("sys_plugin_log");
  	var qc = sysPluginLog.addQuery("plugin", pluginId);
  	if(pluginOrID)
  		qc.addOrCondition("plugin", pluginOrID);
  	sysPluginLog.query();
  	return {"count": sysPluginLog.getRowCount(), "query": sysPluginLog.getEncodedQuery()};
  },
  getUpgradeInfo: function(upgradeHistoryId){
  	var upgradeInfo = {};
  	var pluginsData = new global.PluginsData();
  	upgradeInfo.changes_skipped = pluginsData.getUpgradeHistoryInfo("dispositionIN4,104,9,10^changed=true^ORdisposition=9^resolution_status=not_reviewed^ORresolution_status=^upgrade_history.sys_id="+upgradeHistoryId);
  	upgradeInfo.changes_applied = pluginsData.getUpgradeHistoryInfo('dispositionIN1,2,3,101,102,103^changed=true^upgrade_history.sys_id='+upgradeHistoryId);
  	upgradeInfo.changes_processed = pluginsData.getUpgradeHistoryInfo('dispositionIN4,5,104,105,9,10^changed=true^ORdispositionIN9,5,105^resolution_status!=not_reviewed^resolution_status!=^upgrade_history.sys_id='+upgradeHistoryId);
  	upgradeInfo.copies_to_review = pluginsData.getUpgradeHistoryInfo('dispositionIN201,202,203^resolution_status=not_reviewed^ORresolution_status=^upgrade_history.sys_id='+upgradeHistoryId);
  	upgradeInfo.customized_unchanged = pluginsData.getUpgradeHistoryInfo('dispositionIN4,104^changed=false^upgrade_history.sys_id='+upgradeHistoryId);
  	upgradeInfo.upgrade_details = pluginsData.getUpgradeHistoryInfo('upgrade_history.sys_id='+upgradeHistoryId);
  	return upgradeInfo;
  },
  getInstalledFilesQuery: function(appID) {
  	var files = new GlideRecord('sys_metadata');
  	files.addQuery('sys_scope', appID);
  	files.addQuery('sys_customer_update', true);
  	files.query();
  	var customerFileIds = new global.UpdateVersionAPI().getCustomerFileIds(files);
  	var metaData = new GlideRecord('sys_metadata');
  	if (customerFileIds.length > 0)
  		metaData.addQuery('sys_id', 'NOT IN', customerFileIds);
  	metaData.addQuery('sys_scope', appID);
  	metaData.query();
  	return {
  		"count": metaData.getRowCount(),
  		"query": metaData.getEncodedQuery()
  	};
  },
  getCustomizedFiles: function(appID) {
  	var modifiedFiles = sn_app_customization.AppCustomizationAPI.getAppCustomizationFiles(appID);
  	var metaData = new GlideRecord("sys_metadata");
  	metaData.addQuery("sys_scope", appID);
  	metaData.addQuery("sys_update_name", "IN", modifiedFiles);
  	metaData.query();
  	return {
  		"count": metaData.getRowCount(),
  		"query": metaData.getEncodedQuery()
  	};
  },

  isStoreSyncCompleted: function(trackerId) {
      var pt = new ProgressTracker();
      var response = {
          isComplete: pt.isComplete(trackerId)
      };
      if (response.isComplete) {
          response.repoTime = pt.getExecutionTime(trackerId) || 0;
          response.errorMessage = new AppsData().getLatestErrorMessage("get_all_available_apps") || "";
          response.appsLastSyncTime = new GlideDateTime(gs.getProperty("sn_appclient.apps_last_sync_time")).getDisplayValue();;

          var collectionData = {};
          collectionData.type = "store_updates_time";
          collectionData.time = (response.repoTime.storeUpdatesTime / 1000).toFixed(2);
          new AppClientGCFUtil().recordPageLoadAnalytics(collectionData);

          if (response.repoTime.pluginUpdatesTime) {
              collectionData.type = "plugin_updates_time";
              collectionData.time = (response.repoTime.pluginUpdatesTime / 1000).toFixed(2);
              new AppClientGCFUtil().recordPageLoadAnalytics(collectionData);
          }
      }

      return response;
  },

  processSyncAppsRequest: function(args) {
      var queryParams = args.queryParams;
      var requestType = queryParams.request_type;
      var trackerId = queryParams.tracker_id;
      switch (requestType) {
          case 'trigger_apps_sync':
              return {
                  trackerId: this.checkUpdatesFromStore(false, {
                      appManagerCacheEnabled: false,
                      honourChecksum: false,
                      isInteractive: false
                  })
              };
          case 'get_apps_sync_status':
              if (!trackerId) {
                  throw new Error("Missing parameters: tracker_id");
              }
              return this.isStoreSyncCompleted(trackerId);
          default:
              throw new Error("Unknown request type");
      }
  },

  type: 'AppsData'
};

Sys ID

233b6a00d72221004a1dcdcf6e61036f

Offical Documentation

Official Docs: