Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete a workflow #1461

Merged
merged 2 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/common/src/deleteHelpers/removeItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as reportProgress from "./reportProgress";
import * as hubSites from "@esri/hub-sites";
import * as portal from "@esri/arcgis-rest-portal";
import * as restHelpers from "../restHelpers";
import * as workflowHelpers from "../workflowHelpers";
import { createHubRequestOptions } from "../create-hub-request-options";

// ------------------------------------------------------------------------------------------------------------------ //
Expand Down Expand Up @@ -85,6 +86,8 @@ export function removeItems(
if (hubSiteItemIds.includes(itemToDelete.id)) {
const options = await createHubRequestOptions(authentication);
return hubSites.removeSite(itemToDelete.id, options);
} else if (itemToDelete.type === "Workflow") {
return workflowHelpers.deleteWorkflowItem(itemToDelete.id, authentication);
} else {
return restHelpers.removeItem(itemToDelete.id, authentication);
}
Expand Down
57 changes: 56 additions & 1 deletion packages/common/src/workflowHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
import * as interfaces from "./interfaces";
import * as request from "@esri/arcgis-rest-request";
import * as zipUtils from "./zip-utils";
import { removeGroup } from "./restHelpers";
import { getEnterpriseServers, getItemDataAsJson } from "./restHelpersGet";
import { createMimeTypedFile } from "./resources/copyDataIntoItem";
import { getEnterpriseServers } from "./restHelpersGet";
import JSZip from "jszip";

// ------------------------------------------------------------------------------------------------------------------ //
Expand Down Expand Up @@ -52,6 +53,60 @@ export async function compressWorkflowIntoZipFile(
return Promise.resolve(zipFile);
}

/**
* Deletes a workflow.
*
* @param itemId Id of the workflow item
* @param authentication Credentials for the request to AGOL
* @returns Promise resolving with success or faliure of the request
*/
export async function deleteWorkflowItem(
itemId: string,
authentication: interfaces.UserSession,
): Promise<boolean> {
// Get the user
const user: interfaces.IUser = await authentication.getUser(authentication);
const orgId = user.orgId;

const portal = await authentication.getPortal({ authentication});
const workflowURL: string | undefined = portal.helperServices?.workflowManager?.url;
if (!workflowURL) {
return Promise.reject({
message: "Workflow Manager is not enabled for this organization."
});
}

// 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 workflowUrlRoot = getWorkflowManagerUrlRoot(orgId, workflowURL);
const url = `${workflowUrlRoot}/admin/${itemId}`;

const options: request.IRequestOptions = {
authentication,
headers: {
Accept: "application/json",
Authorization: `Bearer ${authentication.token}`,
"X-Esri-Authorization": `Bearer ${authentication.token}`
},
httpMethod: "DELETE" as any,
params: {
f: "json"
}
};

const response = await request.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.
*
Expand Down
89 changes: 89 additions & 0 deletions packages/common/test/deleteHelpers/removeItems.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/** @license
* Copyright 2018 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.
*/

/**
* Provides tests for removing items from AGO.
*/

import * as interfaces from "../../src/interfaces";
import * as portal from "@esri/arcgis-rest-portal";
import * as removeItems from "../../src/deleteHelpers/removeItems";
import * as utils from "../mocks/utils";
import * as workflowHelpers from "../../src/workflowHelpers";

// ------------------------------------------------------------------------------------------------------------------ //

let MOCK_USER_SESSION: interfaces.UserSession;

beforeEach(() => {
MOCK_USER_SESSION = utils.createRuntimeMockUserSession();
});

describe("Module `removeItems`: removing items from AGO", () => {

it("handles defaulting all options", async () => {
const solutionSummary: interfaces.ISolutionPrecis = {
id: "sln1234567890",
title: "Solution Title",
folder: "fld1234567890",
items: [{
id: "itm1234567890",
type: "Workflow",
title: "Item Title",
modified: 1234567890,
owner: "fred"
}],
groups: []
};

spyOn(portal, "unprotectItem").and.resolveTo(utils.getSuccessResponse());
spyOn(workflowHelpers, "deleteWorkflowItem").and.resolveTo(true);

const expectedResult: interfaces.ISolutionPrecis[] = [{
// Successful deletions
id: "sln1234567890",
title: "Solution Title",
folder: "fld1234567890",
items: [{
id: "itm1234567890",
type: "Workflow",
title: "Item Title",
modified: 1234567890,
owner: "fred"
}],
groups: []
}, {
// Failed deletions
id: "sln1234567890",
title: "Solution Title",
folder: "fld1234567890",
items: [],
groups: []
}];

const result: interfaces.ISolutionPrecis[] = await removeItems.removeItems(
solutionSummary,
[], // hubSiteItemIds
MOCK_USER_SESSION,
50, // percentDone
10, // progressPercentStep
{} // deleteOptions
);

expect(result).toEqual(expectedResult);
});

});
1 change: 0 additions & 1 deletion packages/common/test/restHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import * as zipUtils from "../src/zip-utils";
import * as zipUtilsTest from "./zip-utils.test";
import { IPagingParams } from "@esri/arcgis-rest-portal";


// ------------------------------------------------------------------------------------------------------------------ //

let MOCK_USER_SESSION: interfaces.UserSession;
Expand Down
52 changes: 50 additions & 2 deletions packages/common/test/workflowHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
*/

import * as interfaces from "../src/interfaces";
import * as utils from "../../common/test/mocks/utils";
import * as request from "@esri/arcgis-rest-request";
import * as restHelpers from "../src/restHelpers";
import * as restHelpersGet from "../src/restHelpersGet";
import * as utils from "../../common/test/mocks/utils";
import * as workflowHelpers from "../src/workflowHelpers";
import * as request from "@esri/arcgis-rest-request";
import JSZip from "jszip";

// ------------------------------------------------------------------------------------------------------------------ //
Expand All @@ -45,6 +46,53 @@ describe("Module `workflowHelpers`", () => {
});
});

describe("deleteWorkflowItem", () => {
it("basic test", async () => {
MOCK_USER_SESSION.getUser = () => Promise.resolve({ orgId: "org123" });
MOCK_USER_SESSION.getPortal = () => Promise.resolve({ helperServices: { workflowManager: { url: "https://workflow.arcgis.com" } } });
spyOn(restHelpersGet, "getItemDataAsJson").and.resolveTo({ "groupId": "grp1234567890" });
const requestSpy = spyOn(request, "request").and.resolveTo(utils.getSuccessResponse());
const removeGroupSpy = spyOn(restHelpers, "removeGroup").and.resolveTo(utils.getSuccessResponse({ id: "grp1234567890" }));

const result: boolean = await workflowHelpers.deleteWorkflowItem("itm1234567890", MOCK_USER_SESSION);

expect(requestSpy.calls.argsFor(0)[0]).toEqual("https://workflow.arcgis.com/org123/admin/itm1234567890");
expect(result).toBeTrue();
expect(removeGroupSpy).toHaveBeenCalled();
});

it("handles missing helperServices", async () => {
MOCK_USER_SESSION.getUser = () => Promise.resolve({ orgId: "org123" });
const restHelpersGetSpy = spyOn(restHelpersGet, "getItemDataAsJson").and.resolveTo({});
const requestSpy = spyOn(request, "request").and.resolveTo(utils.getSuccessResponse());
const removeGroupSpy = spyOn(restHelpers, "removeGroup").and.resolveTo(utils.getSuccessResponse({ id: "grp1234567890" }));

let result: boolean;
try {
result = await workflowHelpers.deleteWorkflowItem("itm1234567890", MOCK_USER_SESSION);
fail();
} catch(err) {
expect(err).toEqual({ message: 'Workflow Manager is not enabled for this organization.' });
expect(restHelpersGetSpy).not.toHaveBeenCalled();
expect(requestSpy).not.toHaveBeenCalled();
expect(removeGroupSpy).not.toHaveBeenCalled();
}
});

it("handles missing group id", async () => {
MOCK_USER_SESSION.getUser = () => Promise.resolve({ orgId: "org123" });
MOCK_USER_SESSION.getPortal = () => Promise.resolve({ helperServices: { workflowManager: { url: "https://workflow.arcgis.com" } } });
spyOn(restHelpersGet, "getItemDataAsJson").and.resolveTo(null);
spyOn(request, "request").and.resolveTo(utils.getSuccessResponse());
const removeGroupSpy = spyOn(restHelpers, "removeGroup").and.resolveTo(utils.getSuccessResponse({ id: "grp1234567890" }));

const result: boolean = await workflowHelpers.deleteWorkflowItem("itm1234567890", MOCK_USER_SESSION);

expect(result).toBeTrue();
expect(removeGroupSpy).not.toHaveBeenCalled();
});
});

describe("extractWorkflowFromZipFile", () => {
it("basic test", async () => {
const sampleWorkflowConfig = await generateWorkflowZipFileWithId();
Expand Down
Loading