Skip to content

Commit

Permalink
feat: service name and service info fns
Browse files Browse the repository at this point in the history
  • Loading branch information
dbouwman committed Jun 18, 2021
1 parent 58b7c06 commit bb5f90d
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 5 deletions.
7 changes: 5 additions & 2 deletions packages/arcgis-rest-portal/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ export * from "./sharing/unshare-item-with-group";
export * from "./sharing/is-item-shared-with-group";
export * from "./sharing/helpers";

export * from "./services/get-unique-service-name";
export * from "./services/is-service-name-available";

export * from "./util/get-portal";
export * from "./util/get-portal-settings";
export * from "./util/get-portal-url";
export * from './util/scrub-control-chars';
export * from "./util/scrub-control-chars";
export * from "./util/search";
export * from "./util/SearchQueryBuilder";
// we dont export 'generic-search' because its an internal utility method
Expand All @@ -62,5 +65,5 @@ export {
IFolder,
IGroupAdd,
IGroup,
GroupMembership
GroupMembership,
} from "@esri/arcgis-rest-types";
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* Copyright (c) 2018-2020 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import { UserSession } from "@esri/arcgis-rest-auth";
import { isServiceNameAvailable } from "./is-service-name-available";

/**
* Given a starting name, return a service name that is unqieu within
* the current users organization
*
* @export
* @param {string} name
* @param {UserSession} session
* @param {number} step
* @return {*} {Promise<string>}
*/
export function getUniqueServiceName(
name: string,
type: string,
session: UserSession,
step: number
): Promise<string> {
let nameToCheck = name;
if (step) {
nameToCheck = `${name}_${step}`;
}
return isServiceNameAvailable(nameToCheck, type, session).then((response) => {
if (response.available) {
return nameToCheck;
} else {
step = step + 1;
return getUniqueServiceName(name, type, session, step);
}
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* Copyright (c) 2018-2020 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import { UserSession } from "@esri/arcgis-rest-auth";
import { request } from "@esri/arcgis-rest-request";
import { IServiceNameAvailable } from "@esri/arcgis-rest-types";

/**
* Determine if a specific service name is available in the current user's organization
*
* @export
* @param {string} name
* @param {UserSession} session
* @return {*} {Promise<IServiceNameAvailable>}
*/
export function isServiceNameAvailable(
name: string,
type: string,
session: UserSession
): Promise<IServiceNameAvailable> {
const url = `${session.portal}/portals/self/isServiceNameAvailable`;
return request(url, {
params: {
name,
type,
},
httpMethod: "GET",
authentication: session,
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* Copyright (c) 2018-2020 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import * as isServiceNameAvailableModule from "../../src/services/is-service-name-available";

import { getUniqueServiceName } from "../../src/services/get-unique-service-name";
import { UserSession } from "@esri/arcgis-rest-auth";
import { TOMORROW } from "@esri/arcgis-rest-auth/test/utils";

describe("get-unique-service-name:", () => {
const MOCK_USER_SESSION = new UserSession({
clientId: "clientId",
redirectUri: "https://example-app.com/redirect-uri",
token: "fake-token",
tokenExpires: TOMORROW,
refreshToken: "refreshToken",
refreshTokenExpires: TOMORROW,
refreshTokenTTL: 1440,
username: "casey",
password: "123456",
portal: "https://myorg.maps.arcgis.com/sharing/rest",
});
it("does single check if unique", () => {
const spy = spyOn(
isServiceNameAvailableModule,
"isServiceNameAvailable"
).and.callFake(() => Promise.resolve({ available: true }));
return getUniqueServiceName(
"myService",
"Feature Service",
MOCK_USER_SESSION,
0
).then((result) => {
expect(result).toBe("myService", "should return name");
expect(spy.calls.count()).toBe(1, "should check one name");
});
});

it("makes multiple calls if already taken", () => {
let callNum = 1;
const spy = spyOn(
isServiceNameAvailableModule,
"isServiceNameAvailable"
).and.callFake(() => {
const result = callNum === 2;
callNum++;
return Promise.resolve({ available: result });
});
return getUniqueServiceName(
"myService",
"Feature Service",
MOCK_USER_SESSION,
0
).then((result) => {
expect(result).toBe("myService_1", "should return name");
expect(spy.calls.count()).toBe(2, "should check two names");
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* Copyright (c) 2018-2020 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import * as requestModule from "@esri/arcgis-rest-request";
import { isServiceNameAvailable } from "../../src/services/is-service-name-available";
import { UserSession } from "@esri/arcgis-rest-auth";
import { TOMORROW } from "@esri/arcgis-rest-auth/test/utils";

describe("is-service-name-available", () => {
const MOCK_USER_SESSION = new UserSession({
clientId: "clientId",
redirectUri: "https://example-app.com/redirect-uri",
token: "fake-token",
tokenExpires: TOMORROW,
refreshToken: "refreshToken",
refreshTokenExpires: TOMORROW,
refreshTokenTTL: 1440,
username: "casey",
password: "123456",
portal: "https://myorg.maps.arcgis.com/sharing/rest",
});

it("returns server response", () => {
const spy = spyOn(requestModule, "request").and.callFake(() =>
Promise.resolve({ available: true })
);
return isServiceNameAvailable(
"someService",
"Feature Service",
MOCK_USER_SESSION
).then((result) => {
expect(result.available).toBe(true, "should return the api response");
expect(spy.calls.count()).toBe(1, "should make one request");
expect(spy.calls.argsFor(0)[0]).toBe(
`${MOCK_USER_SESSION.portal}/portals/self/isServiceNameAvailable`
);
const opts = spy.calls.argsFor(0)[1];

expect(opts.params.name).toBe(
"someService",
"passes in the service name"
);
expect(opts.params.type).toBe("Feature Service", "passes in the type");
});
});
});
36 changes: 36 additions & 0 deletions packages/arcgis-rest-service-admin/src/get-service-admin-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* Copyright (c) 2018-2020 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

// TODO: Move to service-admin package in rest-js

import { request } from "@esri/arcgis-rest-request";
import { UserSession } from "@esri/arcgis-rest-auth";
import { IServiceInfo } from "@esri/arcgis-rest-types";

/**
* Given a Feature Service url, fetch the service admin information.
*
* The response from this call includes all the detailed information
* for each layer/table in the service as well as some admin properties
*
* @export
* @param {string} serviceUrl
* @param {UserSession} session
* @return {*} {Promise<IServiceInfo>}
*/
export function getServiceAdminInfo(
serviceUrl: string,
session: UserSession
): Promise<IServiceInfo> {
const serviceAdminUrl = serviceUrl.replace(
"/rest/services",
"/rest/admin/services"
);

return request(serviceAdminUrl, {
authentication: session,
params: {
f: "json",
},
});
}
20 changes: 20 additions & 0 deletions packages/arcgis-rest-service-admin/src/get-view-sources.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* Copyright (c) 2018-2020 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import { UserSession } from "@esri/arcgis-rest-auth";
import { request } from "@esri/arcgis-rest-request";
import { IViewServiceSources } from "@esri/arcgis-rest-types";

/**
* Return the sources response for a view service item
*
* @param {string} viewServiceUrl
* @param {UserSession} session
* @return {*} {Promise<Record<string, unknown>>}
*/
export function getViewSources(
viewServiceUrl: string,
session: UserSession
): Promise<IViewServiceSources> {
return request(`${viewServiceUrl}/sources`, { authentication: session });
}
5 changes: 4 additions & 1 deletion packages/arcgis-rest-service-admin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
export * from "./create";
export * from "./addTo";
export * from "./update";
export * from "./get-service-admin-info";
export * from "./get-view-sources";

export {
IFeatureServiceDefinition,
IExtent,
ISpatialReference,
ILayer,
ILayerDefinition,
ITable
ITable,
} from "@esri/arcgis-rest-types";
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* Copyright (c) 2018-2020 Environmental Systems Research Institute, Inc.
* Apache-2.0 */

import * as requestModule from "@esri/arcgis-rest-request";
import { getServiceAdminInfo } from "../src/get-service-admin-info";
import { TOMORROW } from "@esri/arcgis-rest-auth/test/utils";
import { UserSession } from "@esri/arcgis-rest-auth";

describe("get-service-admin-info: ", () => {
const MOCK_USER_SESSION = new UserSession({
clientId: "clientId",
redirectUri: "https://example-app.com/redirect-uri",
token: "fake-token",
tokenExpires: TOMORROW,
refreshToken: "refreshToken",
refreshTokenExpires: TOMORROW,
refreshTokenTTL: 1440,
username: "casey",
password: "123456",
portal: "https://myorg.maps.arcgis.com/sharing/rest",
});
it("makes request to the admin url", () => {
const spy = spyOn(requestModule, "request").and.callFake(() =>
Promise.resolve({ foo: "bar" })
);
return getServiceAdminInfo(
"https://servicesqa.arcgis.com/orgid/arcgis/rest/services/mysevice/FeatureServer",
MOCK_USER_SESSION
).then((result) => {
expect(result.foo).toBe("bar", "should return the api response");
expect(spy.calls.count()).toBe(1, "should make one request");
expect(spy.calls.argsFor(0)[0]).toBe(
"https://servicesqa.arcgis.com/orgid/arcgis/rest/admin/services/mysevice/FeatureServer"
);
});
});
});
40 changes: 40 additions & 0 deletions packages/arcgis-rest-service-admin/test/get-view-sources.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* Copyright (c) 2018-2020 Environmental Systems Research Institute, Inc.
* Apache-2.0 */
import * as requestModule from "@esri/arcgis-rest-request";
import { getViewSources } from "../src/get-view-sources";

import { UserSession } from "@esri/arcgis-rest-auth";
import { TOMORROW } from "@esri/arcgis-rest-auth/test/utils";

describe("get-view-sources: ", () => {
const MOCK_USER_SESSION = new UserSession({
clientId: "clientId",
redirectUri: "https://example-app.com/redirect-uri",
token: "fake-token",
tokenExpires: TOMORROW,
refreshToken: "refreshToken",
refreshTokenExpires: TOMORROW,
refreshTokenTTL: 1440,
username: "casey",
password: "123456",
portal: "https://myorg.maps.arcgis.com/sharing/rest",
});
it("makes request to the admin url", () => {
const spy = spyOn(requestModule, "request").and.callFake(() =>
Promise.resolve({ currentVersion: 1234 })
);
return getViewSources(
"https://servicesqa.arcgis.com/orgid/arcgis/rest/services/mysevice/FeatureServer",
MOCK_USER_SESSION
).then((result) => {
expect(result.currentVersion).toBe(
1234,
"should return the api response"
);
expect(spy.calls.count()).toBe(1, "should make one request");
expect(spy.calls.argsFor(0)[0]).toBe(
"https://servicesqa.arcgis.com/orgid/arcgis/rest/services/mysevice/FeatureServer/sources"
);
});
});
});
3 changes: 1 addition & 2 deletions packages/arcgis-rest-service-admin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"extends": "../../tsconfig.json",
"include": [
"src/**/*.ts"
]
"src/**/*.ts"]
}
33 changes: 33 additions & 0 deletions packages/arcgis-rest-types/src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,36 @@ export interface IFeatureServiceDefinition {
isLocationTrackingView: boolean;
zDefault?: number;
}
/**
* Very generic structure representing the return value from the
* /arcgis/rest/admin/services/<service-name>/FeatureServer?f=json response
*/
export interface IServiceInfo extends Record<string, unknown> {
adminServiceInfo?: Record<string, unknown>;
layers: Record<string, unknown>[];
}

/**
* Individual View Source entry
*/

export interface IViewServiceSource {
name: string;
type: string;
url: string;
serviceItemId: string;
}
/**
* Response from the /sources end-point of a view service
*/
export interface IViewServiceSources {
currentVersion: number;
services: IViewServiceSource[];
}

/**
* Response from the portals/Self/isServiceNameAvailable request
*/
export interface IServiceNameAvailable {
available: boolean;
}

0 comments on commit bb5f90d

Please sign in to comment.