Skip to content

Commit 36a41ca

Browse files
authored
Merge pull request #1521 from Esri/web-tool-enterprise
Web tool enterprise
2 parents 4acf338 + 7eb89d9 commit 36a41ca

File tree

2 files changed

+217
-45
lines changed

2 files changed

+217
-45
lines changed

packages/web-tool/src/web-tool-processor.ts

Lines changed: 101 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -205,51 +205,108 @@ export function createWebTool(
205205
destinationAuthentication: common.UserSession,
206206
): Promise<any> {
207207
return new Promise<any>((resolve, reject) => {
208-
if (templateDictionary?.portalUrls?.notebooks.https.length > 0) {
209-
const notebookUrl = templateDictionary.portalUrls.notebooks.https[0];
210-
const url = `https://${notebookUrl}/admin/services/createService?f=json&request.preventCache=${Date.now()}`;
211-
212-
const params = {
213-
serviceProperties: {
214-
description: template.item.description,
215-
provider: "notebooks",
216-
type: "GPServer",
217-
jsonProperties: {
218-
timeoutInMinutes: template.data.timeoutInMinutes,
219-
title: template.item.title,
220-
notebookId: template.data.notebookId,
221-
tasks: [
222-
{
223-
type: "notebook",
224-
name: template.data.name,
208+
getNotebookServerCreateServiceURL(
209+
templateDictionary.portalBaseUrl,
210+
destinationAuthentication,
211+
templateDictionary,
212+
).then(
213+
(url) => {
214+
if (url) {
215+
const params = {
216+
serviceProperties: {
217+
description: template.item.description,
218+
provider: "notebooks",
219+
type: "GPServer",
220+
jsonProperties: {
221+
timeoutInMinutes: template.data.timeoutInMinutes,
222+
title: template.item.title,
223+
notebookId: template.data.notebookId,
224+
tasks: [
225+
{
226+
type: "notebook",
227+
name: template.data.name,
228+
},
229+
],
225230
},
226-
],
227-
},
228-
},
229-
};
230-
231-
const requestOptions = {
232-
httpMethod: "POST",
233-
authentication: destinationAuthentication,
234-
params,
235-
headers: {
236-
"Accept": "application/json",
237-
"Authorization": `Bearer ${destinationAuthentication.token}`,
238-
"Content-Type": "application/json",
239-
"X-Esri-Authorization": `Bearer ${destinationAuthentication.token}`,
240-
},
241-
} as common.IRequestOptions;
231+
},
232+
};
242233

243-
common.request(url, requestOptions).then(
244-
(response) => {
245-
resolve(response);
246-
},
247-
(e) => {
248-
reject(e);
249-
},
250-
);
251-
} else {
252-
reject();
253-
}
234+
const requestOptions = {
235+
httpMethod: "POST",
236+
authentication: destinationAuthentication,
237+
params,
238+
headers: {
239+
"Accept": "application/json",
240+
"Authorization": `Bearer ${destinationAuthentication.token}`,
241+
"Content-Type": "application/json",
242+
"X-Esri-Authorization": `Bearer ${destinationAuthentication.token}`,
243+
},
244+
} as common.IRequestOptions;
245+
246+
common.request(url, requestOptions).then(
247+
(response) => {
248+
resolve(response);
249+
},
250+
(e) => {
251+
reject(e);
252+
},
253+
);
254+
} else {
255+
reject();
256+
}
257+
},
258+
(e) => {
259+
reject(e);
260+
},
261+
);
254262
});
255263
}
264+
265+
/**
266+
* Get the URL for the Notebook server in Enterprise.
267+
*
268+
* @param portalBaseUrl URL of the portal endpoint, e.g., "https://gisserver.domain.com/server"
269+
* @param authentication Credentials for the request to AGO
270+
* @returns URL for the Notebook server Enterprise application (e.g., "https://abc123.esri.com:6443/gis"),
271+
* or an empty string if Notebook server is not installed
272+
*/
273+
export async function getNotebookServerCreateServiceURL(
274+
portalBaseUrl: string,
275+
authentication: common.UserSession,
276+
templateDictionary: any,
277+
): Promise<string> {
278+
const notebookUrl = templateDictionary.isPortal
279+
? await getNotebookEnterpriseServerRootURL(portalBaseUrl, authentication)
280+
: templateDictionary.portalUrls?.notebooks.https.length > 0
281+
? templateDictionary.portalUrls.notebooks.https[0]
282+
: "";
283+
284+
return notebookUrl && templateDictionary.isPortal
285+
? `${notebookUrl}/admin/services/createService?f=json&request.preventCache=${Date.now()}`
286+
: notebookUrl
287+
? `https://${notebookUrl}/admin/services/createService?f=json&request.preventCache=${Date.now()}`
288+
: "";
289+
}
290+
291+
/**
292+
* Get the URL for the Notebook server in Enterprise.
293+
*
294+
* @param portalBaseUrl URL of the portal endpoint, e.g., "https://gisserver.domain.com/server"
295+
* @param authentication Credentials for the request to AGO
296+
* @returns URL for the Notebook server Enterprise application (e.g., "https://abc123.esri.com:6443/gis"),
297+
* or an empty string if Notebook server is not installed
298+
*/
299+
export async function getNotebookEnterpriseServerRootURL(
300+
portalBaseUrl: string,
301+
authentication: common.UserSession,
302+
): Promise<string> {
303+
// Get the servers
304+
const servers = await common.getEnterpriseServers(`${portalBaseUrl}/sharing/rest`, authentication);
305+
306+
// Find the Notebook server
307+
const notebookServer = servers.find((s: any) => s.serverFunction.indexOf("NotebookServer") > -1);
308+
if (!notebookServer) {
309+
return "";
310+
}
311+
return notebookServer.url as string;
312+
}

packages/web-tool/test/web-tool-processor.test.ts

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,33 @@ describe("Module `web-tool-processor`: ", () => {
153153
expect(blobToJsonSpy.calls.count()).toBe(1);
154154
});
155155

156+
it("can handle error on getEnterpriseServers", async () => {
157+
const getEnterpriseServersSpy = spyOn(common, "getEnterpriseServers").and.throwError("error")
158+
159+
await WebToolProcessor.createItemFromTemplate(
160+
{
161+
id: "bc3",
162+
type: "Geoprocessing Service",
163+
item: {
164+
typeKeywords: ["Web Tool"],
165+
thumbnail: "thumb",
166+
},
167+
data: {
168+
notebookId: "123",
169+
name: "NotebookName",
170+
},
171+
} as any,
172+
{
173+
isPortal: true
174+
},
175+
MOCK_USER_SESSION,
176+
cb,
177+
);
178+
179+
expect(getEnterpriseServersSpy.calls.count()).toBe(1);
180+
expect(getEnterpriseServersSpy).toThrowError();
181+
});
182+
156183
it("Web Tool Geoprocessing Service handles cancel with item removal", async () => {
157184
const createCb2 = () => {
158185
let calls = 0;
@@ -638,12 +665,100 @@ describe("Module `web-tool-processor`: ", () => {
638665
type: "Geoprocessing Service",
639666
item: { typeKeywords: ["Web Tool"] },
640667
} as any,
641-
undefined,
668+
{},
642669
MOCK_USER_SESSION,
643670
).then(
644671
() => fail(),
645672
(e) => expect(e).toBeUndefined(),
646673
);
647674
});
648675
});
676+
677+
describe("getNotebookServerCreateServiceURL", () => {
678+
it("should fetch servers for Enterprise", async () => {
679+
const notebookBaseUrl = "https://RQALnxBI01NB.esri.com/gis";
680+
const getEnterpriseServersSpy = spyOn(common, "getEnterpriseServers").and.resolveTo([
681+
{
682+
"id": "e0d0rP32Fai4ToC3",
683+
"name": "RQALnxBI01Sv.esri.com:6443",
684+
"adminUrl": "https://RQALnxBI01Sv.esri.com:6443/arcgis",
685+
"url": "https://RQALnxBI01Sv.esri.com/gis",
686+
"isHosted": true,
687+
"serverType": "ArcGIS",
688+
"serverRole": "HOSTING_SERVER",
689+
"serverFunction": "KnowledgeServer,WorkflowManager"
690+
},
691+
{
692+
"id": "U5yshUHhJkWINozX",
693+
"name": "RQALnxBI01NB.esri.com:11443",
694+
"adminUrl": "https://RQALnxBI01NB.esri.com:11443/arcgis",
695+
"url": notebookBaseUrl,
696+
"isHosted": false,
697+
"serverType": "ARCGIS_NOTEBOOK_SERVER",
698+
"serverRole": "FEDERATED_SERVER",
699+
"serverFunction": "NotebookServer"
700+
}
701+
]);
702+
703+
return WebToolProcessor.getNotebookServerCreateServiceURL(
704+
"https://gisserver.domain.com/server",
705+
MOCK_USER_SESSION,
706+
{
707+
isPortal: true
708+
}
709+
).then(
710+
(url) => {
711+
expect(getEnterpriseServersSpy.calls.count()).toBe(1);
712+
expect(url.startsWith(
713+
`${notebookBaseUrl}/admin/services/createService?f=json&request.preventCache=`
714+
)).toBe(true);
715+
},
716+
() => fail(),
717+
);
718+
});
719+
720+
721+
it("should handle missing Enterprise server", async () => {
722+
const getEnterpriseServersSpy = spyOn(common, "getEnterpriseServers").and.resolveTo([
723+
{
724+
"id": "e0d0rP32Fai4ToC3",
725+
"name": "RQALnxBI01Sv.esri.com:6443",
726+
"adminUrl": "https://RQALnxBI01Sv.esri.com:6443/arcgis",
727+
"url": "https://RQALnxBI01Sv.esri.com/gis",
728+
"isHosted": true,
729+
"serverType": "ArcGIS",
730+
"serverRole": "HOSTING_SERVER",
731+
"serverFunction": "KnowledgeServer,WorkflowManager"
732+
}
733+
]);
734+
735+
return WebToolProcessor.getNotebookServerCreateServiceURL(
736+
"https://gisserver.domain.com/server",
737+
MOCK_USER_SESSION,
738+
{
739+
isPortal: true
740+
}
741+
).then(
742+
(url) => {
743+
expect(getEnterpriseServersSpy.calls.count()).toBe(1);
744+
expect(url).toBe("");
745+
},
746+
() => fail(),
747+
);
748+
});
749+
750+
it("should handle missing portalUrls", async () => {
751+
return WebToolProcessor.getNotebookServerCreateServiceURL(
752+
"https://gisserver.domain.com/server",
753+
MOCK_USER_SESSION,
754+
{}
755+
).then(
756+
(url) => {
757+
expect(url).toBe("");
758+
},
759+
() => fail(),
760+
);
761+
});
762+
763+
});
649764
});

0 commit comments

Comments
 (0)