From 99c671226aca4b65e2e2d19e6b6627fb8000bfb4 Mon Sep 17 00:00:00 2001 From: Andrew Tate Date: Thu, 16 Sep 2021 13:23:56 -0500 Subject: [PATCH] refactor(hub-search): use a new base-64 encoding lib affects: @esri/hub-common, @esri/hub-search --- packages/common/src/index.ts | 1 + packages/search/package.json | 2 - .../convert-request-to-portal-params.ts | 23 ++-- .../search/src/util/merge-pagination/merge.ts | 2 +- .../convert-request-to-portal-params.test.ts | 109 +++++++++--------- 5 files changed, 71 insertions(+), 66 deletions(-) diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 198a5e0919a..a07e8a31c42 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -24,3 +24,4 @@ import OperationStack from "./OperationStack"; import OperationError from "./OperationError"; // Re-exports export { OperationStack, OperationError }; +export { btoa, atob } from "abab"; diff --git a/packages/search/package.json b/packages/search/package.json index 03dc1feffc3..cce5484db54 100644 --- a/packages/search/package.json +++ b/packages/search/package.json @@ -10,7 +10,6 @@ "types": "dist/types/index.d.ts", "license": "Apache-2.0", "dependencies": { - "base-64": "^1.0.0", "tslib": "^1.13.0" }, "peerDependencies": { @@ -31,7 +30,6 @@ "@rollup/plugin-commonjs": "^15.0.0", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^9.0.0", - "@types/base-64": "^0.1.3", "@types/faker": "^5.1.5", "faker": "^5.1.0", "rollup": "^2.26.5", diff --git a/packages/search/src/content/helpers/convert-request-to-portal-params.ts b/packages/search/src/content/helpers/convert-request-to-portal-params.ts index d73f808fad3..a5ca59a5a09 100644 --- a/packages/search/src/content/helpers/convert-request-to-portal-params.ts +++ b/packages/search/src/content/helpers/convert-request-to-portal-params.ts @@ -1,5 +1,4 @@ -import { decode } from "base-64"; -import { Logger } from "@esri/hub-common"; +import { Logger, atob as decode } from "@esri/hub-common"; import { IPagingParams, ISearchOptions } from "@esri/arcgis-rest-portal"; import { UserSession } from "@esri/arcgis-rest-auth"; import { @@ -7,13 +6,13 @@ import { IContentSearchFilter, IContentSearchOptions, IContentSearchRequest, - IContentFieldFilter + IContentFieldFilter, } from "../../types/content"; import { IDateRange } from "../../types/common"; import { isFilterAnArrayWithData, isFilterANonEmptyString, - isFilterFieldADateRange + isFilterFieldADateRange, } from "./common"; const TERM_FIELD = "terms"; @@ -25,7 +24,7 @@ const STRING_ENCLOSED_FILTER_FIELDS = [ "description", "tags", "snippet", - "categories" + "categories", ]; /** @@ -72,7 +71,7 @@ export function processPage(request: IContentSearchRequest): IPagingParams { const options: IContentSearchOptions = request.options || {}; const providedPage: IPagingParams | string = options.page || { start: 1, - num: 10 + num: 10, }; return typeof providedPage === "string" ? decodePage(providedPage) @@ -94,12 +93,12 @@ function createSearchOptions( countFields: options.aggregations, countSize: options.aggregations ? 200 : undefined, start: page.start, - num: page.num + num: page.num, }, bbox: options.bbox, portal: options.portal || defaultPortal, authentication: options.authentication || defaultAuthentication, - httpMethod: "POST" + httpMethod: "POST", }; } @@ -143,8 +142,9 @@ function processDateField( filterField: string, filterValue: IDateRange ) { - return `(${filterField}: [${filterValue.from || 0} TO ${filterValue.to || - new Date().getTime()}])`; + return `(${filterField}: [${filterValue.from || 0} TO ${ + filterValue.to || new Date().getTime() + }])`; } function processFieldFilter( @@ -181,6 +181,9 @@ function stringifyFilterValue( function decodePage(page: string): IPagingParams { try { const decodedPage: any = decode(page); + if (decodedPage === null) { + throw new Error(); + } return JSON.parse(decodedPage); } catch (err) { Logger.error( diff --git a/packages/search/src/util/merge-pagination/merge.ts b/packages/search/src/util/merge-pagination/merge.ts index 818348d8426..113de024028 100644 --- a/packages/search/src/util/merge-pagination/merge.ts +++ b/packages/search/src/util/merge-pagination/merge.ts @@ -1,4 +1,4 @@ -import { encode } from "base-64"; +import { btoa as encode } from "@esri/hub-common"; import { InvalidPaginationInputError } from "./invalid-pagination-input"; /** diff --git a/packages/search/test/content/helpers/convert-request-to-portal-params.test.ts b/packages/search/test/content/helpers/convert-request-to-portal-params.test.ts index 7512ff17e49..d9839095196 100644 --- a/packages/search/test/content/helpers/convert-request-to-portal-params.test.ts +++ b/packages/search/test/content/helpers/convert-request-to-portal-params.test.ts @@ -4,8 +4,9 @@ import { SortDirection } from "../../../src/types/common"; import { IBooleanOperator, IContentSearchFilter, - IContentSearchOptions + IContentSearchOptions, } from "../../../src/types/content"; +import { btoa } from "@esri/hub-common"; describe("Convert Portal Params Function", () => { it("can convert content filters to Portal API filters", () => { @@ -23,8 +24,8 @@ describe("Convert Portal Params Function", () => { culture: ["en", "de"], categories: { value: ["category one", "category 2", "category three"], - bool: IBooleanOperator.AND - } + bool: IBooleanOperator.AND, + }, }; // Test @@ -63,8 +64,8 @@ describe("Convert Portal Params Function", () => { culture: ["en", "de"], categories: { value: ["category one", "category 2", "category three"], - bool: IBooleanOperator.AND - } + bool: IBooleanOperator.AND, + }, }; // Test @@ -101,7 +102,7 @@ describe("Convert Portal Params Function", () => { type: { value: null }, access: "", culture: [], - categories: null + categories: null, }; // Test @@ -140,8 +141,8 @@ describe("Convert Portal Params Function", () => { culture: ["en", "de"], categories: { value: ["category one", "category 2", "category three"], - bool: IBooleanOperator.AND - } + bool: IBooleanOperator.AND, + }, }; const page: string = "eyJzdGFydCI6NSwibnVtIjoyMH0="; @@ -149,7 +150,7 @@ describe("Convert Portal Params Function", () => { // Test const portalParams = convertToPortalParams({ filter: filters, - options: { page } + options: { page }, }); // Assert @@ -170,7 +171,7 @@ describe("Convert Portal Params Function", () => { expect(portalParams.bbox).toBeUndefined(); }); - it("can handle an error occuring upon decoding a page", () => { + fit("can handle an error occuring upon decoding a page", () => { // Setup const filters: IContentSearchFilter = { terms: "water", @@ -185,34 +186,36 @@ describe("Convert Portal Params Function", () => { culture: ["en", "de"], categories: { value: ["category one", "category 2", "category three"], - bool: IBooleanOperator.AND - } + bool: IBooleanOperator.AND, + }, + }; + const testInvalidPageOption = (pageOption: string) => { + // Test + const portalParams = convertToPortalParams({ + filter: filters, + options: { page: pageOption }, + }); + + // Assert + expect(portalParams).toBeDefined(); + expect(portalParams.q).toBeDefined(); + expect(portalParams.q).toEqual( + `(water) AND (owner: me OR owner: you) AND (created: [1609459200000 TO 1612137600000]) AND (modified: [1609459200000 TO 1612137600000]) AND (-title: "a title" AND -title: "b title") AND (typekeywords: "a type keyword") AND (tags: "tag 1" OR tags: "tag 2" OR tags: "tag 3") AND (type: "Feature Layer" OR type: "Table" OR type: "CSV") AND (access: private) AND (culture: en OR culture: de) AND (categories: "category one" AND categories: "category 2" AND categories: "category three") AND (-type: "code attachment")` + ); + expect(portalParams.sortOrder).toBeUndefined(); + expect(portalParams.sortField).toBeUndefined(); + expect(portalParams.params).toBeDefined(); + expect(portalParams.params.start).toBeDefined(); + expect(portalParams.params.start).toEqual(1); + expect(portalParams.params.num).toBeDefined(); + expect(portalParams.params.num).toEqual(10); + expect(portalParams.params.countFields).toBeUndefined(); + expect(portalParams.params.countSize).toBeUndefined(); + expect(portalParams.bbox).toBeUndefined(); }; - const page: string = "dummy"; - - // Test - const portalParams = convertToPortalParams({ - filter: filters, - options: { page } - }); - - // Assert - expect(portalParams).toBeDefined(); - expect(portalParams.q).toBeDefined(); - expect(portalParams.q).toEqual( - `(water) AND (owner: me OR owner: you) AND (created: [1609459200000 TO 1612137600000]) AND (modified: [1609459200000 TO 1612137600000]) AND (-title: "a title" AND -title: "b title") AND (typekeywords: "a type keyword") AND (tags: "tag 1" OR tags: "tag 2" OR tags: "tag 3") AND (type: "Feature Layer" OR type: "Table" OR type: "CSV") AND (access: private) AND (culture: en OR culture: de) AND (categories: "category one" AND categories: "category 2" AND categories: "category three") AND (-type: "code attachment")` - ); - expect(portalParams.sortOrder).toBeUndefined(); - expect(portalParams.sortField).toBeUndefined(); - expect(portalParams.params).toBeDefined(); - expect(portalParams.params.start).toBeDefined(); - expect(portalParams.params.start).toEqual(1); - expect(portalParams.params.num).toBeDefined(); - expect(portalParams.params.num).toEqual(10); - expect(portalParams.params.countFields).toBeUndefined(); - expect(portalParams.params.countSize).toBeUndefined(); - expect(portalParams.bbox).toBeUndefined(); + testInvalidPageOption("invalid base 64"); + testInvalidPageOption(btoa("invalid serialized json")); }); it("can convert content filters to Portal API filters with proper sorting", () => { @@ -230,7 +233,7 @@ describe("Convert Portal Params Function", () => { culture: "en", categories: { value: ["category one", "category 2", "category three"] }, orgid: ["org one", "org two"], - id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT } + id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT }, }; const portalOptions = { sortField: "title", sortOrder: SortDirection.desc }; @@ -238,7 +241,7 @@ describe("Convert Portal Params Function", () => { // Test const portalParams = convertToPortalParams({ filter: filters, - options: portalOptions + options: portalOptions, }); // Assert @@ -276,19 +279,19 @@ describe("Convert Portal Params Function", () => { culture: "en", categories: { value: ["category one", "category 2", "category three"] }, orgid: ["org one", "org two"], - id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT } + id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT }, }; const portalOptions = { sortField: "title", sortOrder: SortDirection.desc, - aggregations: "categories,type,access" + aggregations: "categories,type,access", }; // Test const portalParams = convertToPortalParams({ filter: filters, - options: portalOptions + options: portalOptions, }); // Assert @@ -328,20 +331,20 @@ describe("Convert Portal Params Function", () => { culture: "en", categories: { value: ["category one", "category 2", "category three"] }, orgid: ["org one", "org two"], - id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT } + id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT }, }; const portalOptions = { sortField: "title", sortOrder: SortDirection.desc, aggregations: "categories,type,access", - bbox: "bbox" + bbox: "bbox", }; // Test const portalParams = convertToPortalParams({ filter: filters, - options: portalOptions + options: portalOptions, }); // Assert @@ -382,7 +385,7 @@ describe("Convert Portal Params Function", () => { culture: "en", categories: { value: ["category one", "category 2", "category three"] }, orgid: ["org one", "org two"], - id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT } + id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT }, }; const portalOptions: IContentSearchOptions = { @@ -391,14 +394,14 @@ describe("Convert Portal Params Function", () => { aggregations: "categories,type,access", bbox: "bbox", portal: "dummy-portal-sharing-one", - authentication: new UserSession({ portal: "dummy-portal-one" }) + authentication: new UserSession({ portal: "dummy-portal-one" }), }; // Test const portalParams = convertToPortalParams( { filter: filters, - options: portalOptions + options: portalOptions, }, "dummy-portal-sharing-two", new UserSession({ portal: "dummy-portal-two" }) @@ -446,21 +449,21 @@ describe("Convert Portal Params Function", () => { culture: "en", categories: { value: ["category one", "category 2", "category three"] }, orgid: ["org one", "org two"], - id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT } + id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT }, }; const portalOptions: IContentSearchOptions = { sortField: "title", sortOrder: SortDirection.desc, aggregations: "categories,type,access", - bbox: "bbox" + bbox: "bbox", }; // Test const portalParams = convertToPortalParams( { filter: filters, - options: portalOptions + options: portalOptions, }, "dummy-portal-sharing-two", new UserSession({ portal: "dummy-portal-two" }) @@ -508,20 +511,20 @@ describe("Convert Portal Params Function", () => { culture: "en", categories: { value: ["category one", "category 2", "category three"] }, orgid: ["org one", "org two"], - id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT } + id: { value: ["1", "2", "3"], bool: IBooleanOperator.NOT }, }; const portalOptions: IContentSearchOptions = { sortField: "title", sortOrder: SortDirection.desc, aggregations: "categories,type,access", - bbox: "bbox" + bbox: "bbox", }; // Test const portalParams = convertToPortalParams({ filter: filters, - options: portalOptions + options: portalOptions, }); // Assert