@esri/solution-common
Version:
Provides general helper functions for @esri/solution.js.
270 lines • 11.1 kB
JavaScript
/** @license
* Copyright 2024 Esri
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as restHelpersGet from "./restHelpersGet";
import * as zipUtils from "./zip-utils";
import { request } from "./arcgisRestJS";
import { removeGroup } from "./restHelpers";
import { getEnterpriseServers, getItemDataAsJson } from "./restHelpersGet";
import { createMimeTypedFile } from "./resources/copyDataIntoItem";
import { getProp } from "./generalHelpers";
import JSZip from "jszip";
// ------------------------------------------------------------------------------------------------------------------ //
/**
* Compresses a workflow configuration into a zip file.
*
* @param workflowConfig Workflow configuration
* @returns Promise resolving with a zip file
*/
export async function compressWorkflowIntoZipFile(workflowConfig) {
const zip = new JSZip();
Object.keys(workflowConfig).forEach((key) => {
zip.file(key, workflowConfig[key]);
});
const zipFile = createMimeTypedFile({
blob: await zip.generateAsync({ type: "blob" }),
filename: `workflow_configuration.zip`,
mimeType: "application/zip",
});
return Promise.resolve(zipFile);
}
/**
* Deletes a workflow.
*
* @param itemId Id of the workflow item
* @param workflowBaseUrl URL of the workflow manager, e.g., "https://workflow.arcgis.com/orgId"
* @param authentication Credentials for the request to AGOL
* @returns Promise resolving with success or faliure of the request
*/
export async function deleteWorkflowItem(itemId, workflowBaseUrl, authentication) {
// Get the id of the Workflow Manager Admin group because the group has to be deleted separately
const data = await getItemDataAsJson(itemId, authentication);
const adminGroupId = data?.groupId;
// Delete the item
const url = `${workflowBaseUrl}/admin/${itemId}`;
const options = {
authentication,
headers: {
"Accept": "application/json",
"Authorization": `Bearer ${authentication.token}`,
"X-Esri-Authorization": `Bearer ${authentication.token}`,
},
httpMethod: "DELETE",
params: {
f: "json",
},
};
const response = await request(url, options);
// Delete the admin group
if (adminGroupId) {
await removeGroup(adminGroupId, authentication);
}
return Promise.resolve(response.success);
}
/**
* Extracts a workflow configuration from a zip file into a JSON object.
*
* @param zipFile Zip file containing a workflow configuration
* @returns Promise resolving with a workflow configuration as JSON object, with each file being a key
*/
export async function extractWorkflowFromZipFile(zipFile) {
const zippedFiles = await zipUtils.getZipObjectContents(await zipUtils.blobToZipObject(zipFile));
const workflowConfig = {};
zippedFiles.forEach((zippedFile) => {
workflowConfig[zippedFile.file] = zippedFile.content;
});
return Promise.resolve(workflowConfig);
}
/**
* Check the license capability of Workflow Manager Server.
*
* @param workflowBaseUrl URL of the workflow manager, e.g., "https://workflow.arcgis.com/orgId"
* @param authentication Credentials for the request to AGO
* @returns Promise resolving with a boolean indicating whether the organization has the license
* @throws {WorkflowJsonExceptionDTO} if request to workflow manager fails
*/
export async function getWorkflowManagerAuthorized(workflowBaseUrl, authentication) {
try {
const url = `${workflowBaseUrl}/checkStatus`;
const options = {
authentication,
httpMethod: "GET",
params: {
f: "json",
},
};
const response = await request(url, options);
const isAuthorized = response?.hasAdvancedLicense || false;
return Promise.resolve(isAuthorized);
}
catch (err) {
// User is not authorized for Workflow Manager
return Promise.resolve(false);
}
}
/**
* Determines the URL to the Workflow Manager.
*
* @param authentication Authenticated user session
* @param portalResponse Response from portal "self" call; will be fetched if not supplied
* @param orgId Id of organization whose license is to be checked; if truthy, the URL will be for AGO;
* if falsy, the URL will be for Workflow Manager Enterprise
* @returns A URL based on ArcGIS Online or Enterprise, e.g., "https://abc123.esri.com:6443/arcgis"
*/
export async function getWorkflowBaseURL(authentication, portalResponse, orgId) {
let workflowServerUrl;
if (!portalResponse) {
const user = await restHelpersGet.getUser(authentication);
orgId = orgId ?? user.orgId;
portalResponse = await restHelpersGet.getPortal("", authentication);
}
const portalURL = `https://${portalResponse.portalHostname}`;
const portalRestURL = `${portalURL}/sharing/rest`;
if (portalResponse.isPortal) {
// Enterprise
workflowServerUrl = await getWorkflowEnterpriseServerRootURL(portalRestURL, authentication);
}
else {
// ArcGIS Online
workflowServerUrl = portalResponse.helperServices?.workflowManager?.url ?? portalURL;
}
return Promise.resolve(orgId ? `${workflowServerUrl}/${orgId}` : `${workflowServerUrl}/workflow`);
}
/**
* Get the URL for the Workflow Manager Enterprise application.
*
* @param portalRestUrl URL of the portal REST endpoint, e.g., "https://gisserver.domain.com/server/rest/services"
* @param authentication Credentials for the request to AGO
* @returns URL for the Workflow Manager Enterprise application (e.g., "https://abc123.esri.com:6443/arcgis"),
* or an empty string if Workflow Manager is not enabled
*/
export async function getWorkflowEnterpriseServerRootURL(portalRestUrl, authentication) {
// Get the servers
const servers = await getEnterpriseServers(portalRestUrl, authentication);
// Find the Workflow Manager server
const workflowServer = servers.find((server) => server.serverFunction === "WorkflowManager");
if (!workflowServer) {
return "";
}
return workflowServer.url;
}
/**
* Remove feature service templates that will be auto-generated by Workflow when
* creating the Workflow item.
*
* Also store key values from any Workflow items so we can update variables in other items.
*
* @param templates The list of all templates from the Solutions
* @param templateDictionary Hash of facts: folder id, org URL, adlib replacements
*
* @returns An object that contains the items that should use standard deployment and
* templates that will be deployed by Wokflow deployment.
*/
export function preprocessWorkflowTemplates(templates, templateDictionary) {
const workflowItems = templates.filter((t) => t.type === "Workflow");
const serviceIds = workflowItems.reduce((prev, cur) => {
templateDictionary.workflows = { ...templateDictionary.workflows };
templateDictionary.workflows[cur.itemId] = {};
storeKeyWorkflowServiceId("viewSchema", templateDictionary, cur, prev);
storeKeyWorkflowServiceId("workflowLocations", templateDictionary, cur, prev);
storeKeyWorkflowServiceId("workflowSchema", templateDictionary, cur, prev);
return prev;
}, []);
const workflowManagedTemplates = [];
const deployTemplates = templates.filter((t) => {
if (serviceIds.indexOf(t.itemId) < 0) {
return true;
}
else {
workflowManagedTemplates.push(t);
}
});
return {
deployTemplates,
workflowManagedTemplates,
};
}
/**
* Store key values from any Workflow items so we can update variables in other items.
*
* @param key property from a workflow item that will contain an item id that we will need for variable replacement
* @param templateDictionary Hash of facts: folder id, org URL, adlib replacements
* @param template Workflow template
* @param ids list of ids that will be auto generated by Workflow
*
*/
export function storeKeyWorkflowServiceId(key, templateDictionary, template, ids) {
const id = getProp(template, `data.${key}.itemId`).replace("{{", "").replace(".itemId}}", "");
if (id && ids.indexOf(id) < 0) {
ids.push(id);
}
templateDictionary.workflows[template.itemId][key] = id;
templateDictionary[id] = {};
}
/**
* Replace various IDs in the templates based on items that were created by Workflow
*
* @param templates The list of all templates from the Solutions
* @param templateDictionary Hash of facts: folder id, org URL, adlib replacements
*
* @returns The updated collection of templates
*/
export function updateWorkflowTemplateIds(templates, templateDictionary) {
if (templateDictionary.workflows) {
Object.keys(templateDictionary.workflows).forEach((k) => {
// the ids retained here are that of the source items
// we justr need to swap them out in the templates arrey
const workflowHash = templateDictionary.workflows[k];
const viewSchemaId = workflowHash.viewSchema;
const workflowLocationsId = workflowHash.workflowLocations;
const workflowSchemaId = workflowHash.workflowSchema;
const workflowIds = [viewSchemaId, workflowLocationsId, workflowSchemaId];
templates = templates.map((t) => {
if (workflowIds.indexOf(t.itemId) > -1) {
t.dependencies = t.dependencies.map((d) => {
if (workflowIds.indexOf(d) > -1) {
d = templateDictionary[d].itemId;
}
return d;
});
t.itemId = templateDictionary[t.itemId].itemId;
}
return t;
});
});
}
return templates;
}
/**
* Get the various dependencies from the workflow item and add them to the current templates dependency list
*
* @param template The IItemTemplate of the workflow item
*
*/
export function getWorkflowDependencies(template) {
const data = template.data;
if (data) {
const keys = ["viewSchema", "workflowLocations", "workflowSchema"];
keys.forEach((k) => {
if (Object.keys(data).indexOf(k) > -1) {
const id = data[k].itemId;
if (id && template.dependencies.indexOf(id) < 0) {
template.dependencies.push(id);
}
}
});
}
}
//# sourceMappingURL=workflowHelpers.js.map