Skip to content

Commit

Permalink
Merge pull request #278 from Esri/b/130995-unique-item-title-and-slug
Browse files Browse the repository at this point in the history
  • Loading branch information
vivzhang authored Jun 23, 2020
2 parents 0884094 + dfc6cbf commit c8a869c
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 0 deletions.
25 changes: 25 additions & 0 deletions packages/common/src/items/does-item-exist-with-title.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { searchItems } from '@esri/arcgis-rest-portal';
import { IAuthenticationManager } from '@esri/arcgis-rest-request';

/**
* Check if a site/page exists with a specific name
*/
export function doesItemExistWithTitle (
itemTitle: string,
options: Record<string,string>,
authMgr: IAuthenticationManager,
) {
// if options have multiple properties, put them into one string separated with 'AND'
let optionsQuery = Object.keys(options).map(key => {
return `${key}:"${options[key]}"`;
}).join(' AND ');
let opts = {
q: `title:"${itemTitle}" AND ${optionsQuery}`,
authentication: authMgr
};
return searchItems(opts)
.then(searchResponse => searchResponse.results.length > 0)
.catch(e => {
throw Error(`Error in doesItemExistWithTitle ${e}`);
});
}
39 changes: 39 additions & 0 deletions packages/common/src/items/get-unique-item-title.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { doesItemExistWithTitle } from "./does-item-exist-with-title";
import { IAuthenticationManager } from '@esri/arcgis-rest-request';

/**
* Given a title, construct a site/page title that is unique
* if that title exists, this fn will add a number on the end, and increment until
* an available title is found
* @param {string} title site/page title to ensure if unique
* @param {object} options an object that can be passed in to the q, eg. typekeywords, type
* @param {object} authMgr auth info tells the function what url to use for the "root" of the API,
* if missing, it will search against PROD
* @param {number} step Number to increment. Defaults to 0
*/

export function getUniqueItemTitle (
title: string,
options: Record<string,string>,
authMgr: IAuthenticationManager,
step = 0
): Promise<string> {
let combinedName = title;

if (step) {
combinedName = `${title} ${step}`;
}

return doesItemExistWithTitle(combinedName, options, authMgr)
.then(result => {
if (result) {
step++;
return getUniqueItemTitle(title, options, authMgr, step);
} else {
return combinedName;
}
})
.catch(e => {
throw Error(`Error in getUniqueItemTitle ${e}`);
});
}
2 changes: 2 additions & 0 deletions packages/common/src/items/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ export * from "./serialize-model";
export * from "./share-item-to-groups";
export * from "./unprotect-model";
export * from "./unshare-item-from-groups";
export * from "./does-item-exist-with-title";
export * from "./get-unique-item-title";
Empty file.
70 changes: 70 additions & 0 deletions packages/common/test/items/does-item-exist-with-title.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { doesItemExistWithTitle } from '../../src';
import * as portalModule from "@esri/arcgis-rest-portal";
import { IAuthenticationManager } from '@esri/arcgis-rest-request';

describe('doesItemExistWithTitle', () => {
let options = {
typekeywords: "foo"
};

const authMgr = {} as IAuthenticationManager;

it('should resolve true when item with same name exists', async () => {
const opts = {
q: `title:"exists"`,
authentication: authMgr
};
const spy = spyOn(portalModule, "searchItems").and.returnValue(
Promise.resolve({
results: [{}]
})
);
const res = await doesItemExistWithTitle("exists", options, authMgr);
expect(res).toBeTruthy();

const expectedSearchOpts = {
q: `title:"exists" AND typekeywords:"foo"`,
authentication: authMgr
};
expect(spy.calls.argsFor(0)[0]).toEqual(
expectedSearchOpts,
"searchItems called with correct options"
);
});


it('should resolve false when item with same name DOES NOT exist', async () => {
const opts = {
q: `title:"not-exists"`,
authentication: authMgr
};
const spy = spyOn(portalModule, "searchItems").and.returnValue(
Promise.resolve({
results: [] // empty
})
);
const res = await doesItemExistWithTitle("not-exists", options, authMgr);
expect(res).toBeFalsy();

const expectedSearchOpts = {
q: `title:"not-exists" AND typekeywords:"foo"`,
authentication: authMgr
};
expect(spy.calls.argsFor(0)[0]).toEqual(
expectedSearchOpts,
"searchItems called with correct options"
);
});

it('should reject if error', async () => {
spyOn(portalModule, "searchItems").and.returnValue
(Promise.reject());

try {
await doesItemExistWithTitle("not-exists", options, authMgr);
fail("should reject");
} catch (err) {
expect(err).toBeDefined();
}
});
});
41 changes: 41 additions & 0 deletions packages/common/test/items/get-unique-item-title.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { getUniqueItemTitle } from '../../src';
import * as doesItemExistWithTitleModule from "../../src/items/does-item-exist-with-title";
import { IAuthenticationManager } from '@esri/arcgis-rest-request';

describe('getUniqueItemTitle', () => {
const opts = {
typekeywords: 'typeX'
};
it("generates a unique name", async function() {
const initialTitle = "foobar";
spyOn(doesItemExistWithTitleModule, "doesItemExistWithTitle").and.callFake(function(
candidate: string
) {
return Promise.resolve(
[`${initialTitle}`, `${initialTitle} 1`].indexOf(candidate) !== -1
);
});

const uniqueTitle = await getUniqueItemTitle(
initialTitle,
opts,
{} as IAuthenticationManager
);

expect(uniqueTitle).toBe("foobar 2");
});

it("rejects if error", async function() {
const initialTitle = "foobar";
spyOn(doesItemExistWithTitleModule, "doesItemExistWithTitle").and.returnValue(
Promise.reject("something")
);

try {
await getUniqueItemTitle(initialTitle, opts, {} as IAuthenticationManager);
fail("should reject");
} catch (err) {
expect(err).toBeDefined();
}
});
});

0 comments on commit c8a869c

Please sign in to comment.