From 24af24167116e4537bc774b423eaa1fce13d5cd9 Mon Sep 17 00:00:00 2001 From: john gravois Date: Fri, 29 Mar 2019 13:37:52 -0700 Subject: [PATCH] fix: force FormData when calling /updateResources AFFECTS PACKAGES: @esri/arcgis-rest-request @esri/arcgis-rest-items ISSUES CLOSED: #499 --- packages/arcgis-rest-items/src/update.ts | 15 ++-- .../arcgis-rest-items/test/update.test.ts | 90 ++++++++++--------- packages/arcgis-rest-request/src/request.ts | 9 +- .../src/utils/encode-form-data.ts | 8 +- .../src/utils/process-params.ts | 2 +- .../test/utils/process-params.test.ts | 2 +- 6 files changed, 72 insertions(+), 54 deletions(-) diff --git a/packages/arcgis-rest-items/src/update.ts b/packages/arcgis-rest-items/src/update.ts index ee46ad48ba..4b2cecb3b1 100644 --- a/packages/arcgis-rest-items/src/update.ts +++ b/packages/arcgis-rest-items/src/update.ts @@ -1,7 +1,11 @@ /* Copyright (c) 2018 Environmental Systems Research Institute, Inc. * Apache-2.0 */ -import { request, getPortalUrl } from "@esri/arcgis-rest-request"; +import { + request, + getPortalUrl, + IRequestOptions +} from "@esri/arcgis-rest-request"; import { IItemUpdate } from "@esri/arcgis-rest-common-types"; @@ -87,9 +91,9 @@ export function updateItemResource( requestOptions: IItemResourceRequestOptions ): Promise { const owner = determineOwner(requestOptions); - const url = `${getPortalUrl(requestOptions)}/content/users/${owner}/items/${ - requestOptions.id - }/updateResources`; + const url = `${getPortalUrl( + requestOptions as IRequestOptions + )}/content/users/${owner}/items/${requestOptions.id}/updateResources`; // mix in user supplied params requestOptions.params = { @@ -99,13 +103,12 @@ export function updateItemResource( ...requestOptions.params }; - // only override whatever access was specified previously if 'private' was passed explicitly + // only override the access specified previously if 'private' is passed explicitly if (typeof requestOptions.private !== "undefined") { requestOptions.params.access = requestOptions.private ? "private" : "inherit"; } - return request(url, requestOptions); } diff --git a/packages/arcgis-rest-items/test/update.test.ts b/packages/arcgis-rest-items/test/update.test.ts index d1698d0f18..ba39791402 100644 --- a/packages/arcgis-rest-items/test/update.test.ts +++ b/packages/arcgis-rest-items/test/update.test.ts @@ -214,19 +214,21 @@ describe("search", () => { content: "jumbotron", ...MOCK_USER_REQOPTS }) - .then(response => { + .then(() => { const [url, options]: [string, RequestInit] = fetchMock.lastCall("*"); expect(url).toEqual( "https://myorg.maps.arcgis.com/sharing/rest/content/users/dbouwman/items/3ef/updateResources" ); expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain( - encodeParam("fileName", "image/banner.png") - ); - expect(options.body).toContain(encodeParam("text", "jumbotron")); - expect(options.body).not.toContain(encodeParam("access", "inherit")); - expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body instanceof FormData).toBeTruthy(); + const params = options.body as FormData; + if (params.get) { + expect(params.get("f")).toEqual("json"); + expect(params.get("fileName")).toEqual("image/banner.png"); + expect(params.get("text")).toEqual("jumbotron"); + expect(params.get("access")).toEqual(null); + expect(params.get("token")).toEqual("fake-token"); + } done(); }) .catch(e => { @@ -235,10 +237,7 @@ describe("search", () => { }); it("should update a binary resource to an item", done => { - fetchMock.once("*", { - success: true - }); - + fetchMock.once("*", { success: true }); const file = attachmentFile(); updateItemResource({ @@ -279,18 +278,21 @@ describe("search", () => { content: "jumbotron", ...MOCK_USER_REQOPTS }) - .then(response => { + .then(() => { const [url, options]: [string, RequestInit] = fetchMock.lastCall("*"); expect(url).toEqual( "https://myorg.maps.arcgis.com/sharing/rest/content/users/casey/items/3ef/updateResources" ); expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain( - encodeParam("fileName", "image/banner.png") - ); - expect(options.body).toContain(encodeParam("text", "jumbotron")); - expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body instanceof FormData).toBeTruthy(); + const params = options.body as FormData; + if (params.get) { + expect(params.get("f")).toEqual("json"); + expect(params.get("fileName")).toEqual("image/banner.png"); + expect(params.get("text")).toEqual("jumbotron"); + expect(params.get("access")).toEqual(null); + expect(params.get("token")).toEqual("fake-token"); + } done(); }) .catch(e => { @@ -315,14 +317,16 @@ describe("search", () => { "https://myorg.maps.arcgis.com/sharing/rest/content/users/casey/items/3ef/updateResources" ); expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain( - encodeParam("fileName", "image/banner.png") - ); - expect(options.body).toContain("resourcesPrefix=foolder"); - expect(options.body).toContain(encodeParam("text", "jumbotron")); - expect(options.body).toContain(encodeParam("token", "fake-token")); - expect(options.body).not.toContain(encodeParam("access", "inherit")); + expect(options.body instanceof FormData).toBeTruthy(); + const params = options.body as FormData; + if (params.get) { + expect(params.get("f")).toEqual("json"); + expect(params.get("fileName")).toEqual("image/banner.png"); + expect(params.get("resourcesPrefix")).toEqual("foolder"); + expect(params.get("text")).toEqual("jumbotron"); + expect(params.get("access")).toEqual(null); + expect(params.get("token")).toEqual("fake-token"); + } done(); }) .catch(e => { @@ -335,7 +339,6 @@ describe("search", () => { updateItemResource({ id: "3ef", name: "image/banner.png", - content: "jumbotron", private: true, ...MOCK_USER_REQOPTS }) @@ -345,13 +348,14 @@ describe("search", () => { "https://myorg.maps.arcgis.com/sharing/rest/content/users/casey/items/3ef/updateResources" ); expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain( - encodeParam("fileName", "image/banner.png") - ); - expect(options.body).toContain(encodeParam("text", "jumbotron")); - expect(options.body).toContain(encodeParam("token", "fake-token")); - expect(options.body).toContain(encodeParam("access", "private")); + expect(options.body instanceof FormData).toBeTruthy(); + const params = options.body as FormData; + if (params.get) { + expect(params.get("f")).toEqual("json"); + expect(params.get("fileName")).toEqual("image/banner.png"); + expect(params.get("access")).toEqual("private"); + expect(params.get("token")).toEqual("fake-token"); + } done(); }) .catch(e => { @@ -374,13 +378,15 @@ describe("search", () => { "https://myorg.maps.arcgis.com/sharing/rest/content/users/casey/items/3ef/updateResources" ); expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain( - encodeParam("fileName", "image/banner.png") - ); - expect(options.body).toContain(encodeParam("text", "jumbotron")); - expect(options.body).toContain(encodeParam("token", "fake-token")); - expect(options.body).toContain(encodeParam("access", "inherit")); + expect(options.body instanceof FormData).toBeTruthy(); + const params = options.body as FormData; + if (params.get) { + expect(params.get("f")).toEqual("json"); + expect(params.get("fileName")).toEqual("image/banner.png"); + expect(params.get("text")).toEqual("jumbotron"); + expect(params.get("access")).toEqual("inherit"); + expect(params.get("token")).toEqual("fake-token"); + } done(); }) .catch(e => { diff --git a/packages/arcgis-rest-request/src/request.ts b/packages/arcgis-rest-request/src/request.ts index 95a2f9ffd9..fb7663430e 100644 --- a/packages/arcgis-rest-request/src/request.ts +++ b/packages/arcgis-rest-request/src/request.ts @@ -186,8 +186,13 @@ export function request( } } + /* updateResources currently requires FormData even when the input parameters dont warrant it. + https://developers.arcgis.com/rest/users-groups-and-items/update-resources.htm + see https://github.com/Esri/arcgis-rest-js/pull/500 for more info. */ + const forceFormData = new RegExp("/items/.+/updateResources").test(url); + if (fetchOptions.method === "POST") { - fetchOptions.body = encodeFormData(params); + fetchOptions.body = encodeFormData(params, forceFormData); } // Mixin headers from request options @@ -201,7 +206,7 @@ export function request( } /* istanbul ignore else blob responses are difficult to make cross platform we will just have to trust the isomorphic fetch will do its job */ - if (!requiresFormData(params)) { + if (!requiresFormData(params) && !forceFormData) { fetchOptions.headers["Content-Type"] = "application/x-www-form-urlencoded"; } diff --git a/packages/arcgis-rest-request/src/utils/encode-form-data.ts b/packages/arcgis-rest-request/src/utils/encode-form-data.ts index 9a4e6f9ff2..305e318778 100644 --- a/packages/arcgis-rest-request/src/utils/encode-form-data.ts +++ b/packages/arcgis-rest-request/src/utils/encode-form-data.ts @@ -9,8 +9,12 @@ import { encodeQueryString } from "./encode-query-string"; * @param params An object to be encoded. * @returns The complete [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object. */ -export function encodeFormData(params: any): FormData | string { - const useFormData = requiresFormData(params); +export function encodeFormData( + params: any, + forceFormData?: boolean +): FormData | string { + // see https://github.com/Esri/arcgis-rest-js/issues/499 for more info. + const useFormData = requiresFormData(params) || forceFormData; const newParams = processParams(params); if (useFormData) { const formData = new FormData(); diff --git a/packages/arcgis-rest-request/src/utils/process-params.ts b/packages/arcgis-rest-request/src/utils/process-params.ts index df2c90dfa2..6dc378d777 100644 --- a/packages/arcgis-rest-request/src/utils/process-params.ts +++ b/packages/arcgis-rest-request/src/utils/process-params.ts @@ -1,5 +1,5 @@ /* Copyright (c) 2017 Environmental Systems Research Institute, Inc. -* Apache-2.0 */ + * Apache-2.0 */ /** * Checks parameters to see if we should use FormData to send the request diff --git a/packages/arcgis-rest-request/test/utils/process-params.test.ts b/packages/arcgis-rest-request/test/utils/process-params.test.ts index a3399dba8f..199822a036 100644 --- a/packages/arcgis-rest-request/test/utils/process-params.test.ts +++ b/packages/arcgis-rest-request/test/utils/process-params.test.ts @@ -52,7 +52,7 @@ describe("processParams", () => { expect(processParams(params)).toEqual(expected); }); - it("should stringify arrays of objects", () => { + it("should stringify arrays of objects", () => { const params = { foo: [ {