From 89693faebb29e40122b9ae42830f2d88ca070a13 Mon Sep 17 00:00:00 2001 From: "Michael (mcm)" Date: Tue, 3 Oct 2023 10:25:05 +0200 Subject: [PATCH] [FIX] web: fix http.post array params Since [1] an error was thrown when giving multiple files to http.post. This commit reverts changes in the function but the function now also allows to give a FormData instead of pojo. [1]: https://github.com/odoo/odoo/pull/136271 closes odoo/odoo#137421 Signed-off-by: Aaron Bohy (aab) --- .../static/src/core/network/http_service.js | 16 +++++- .../tests/core/network/http_service_tests.js | 56 +++++++++++++++++++ .../static/src/snippets/s_website_form/000.js | 7 ++- 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 addons/web/static/tests/core/network/http_service_tests.js diff --git a/addons/web/static/src/core/network/http_service.js b/addons/web/static/src/core/network/http_service.js index 560b524e831..2ca1c01c549 100644 --- a/addons/web/static/src/core/network/http_service.js +++ b/addons/web/static/src/core/network/http_service.js @@ -16,9 +16,19 @@ export async function get(route, readMethod = "json") { } export async function post(route, params = {}, readMethod = "json") { - const formData = new FormData(); - for (const key in params) { - formData.append(key, params[key]); + let formData = params; + if (!(formData instanceof FormData)) { + formData = new FormData(); + for (const key in params) { + const value = params[key]; + if (Array.isArray(value) && value.length) { + for (const val of value) { + formData.append(key, val); + } + } else { + formData.append(key, value); + } + } } const response = await browser.fetch(route, { body: formData, diff --git a/addons/web/static/tests/core/network/http_service_tests.js b/addons/web/static/tests/core/network/http_service_tests.js new file mode 100644 index 00000000000..3faf48df32e --- /dev/null +++ b/addons/web/static/tests/core/network/http_service_tests.js @@ -0,0 +1,56 @@ +/** @odoo-module **/ + +import { browser } from "@web/core/browser/browser"; +import { patchWithCleanup } from "../../helpers/utils"; +import { get, post } from "@web/core/network/http_service"; + +function onFetch(fetch) { + patchWithCleanup(browser, { + fetch: (route, params) => { + const result = fetch(route, params); + return result ?? new Response("{}"); + }, + }); +} + +QUnit.module("HTTP"); + +QUnit.test("method is correctly set", async (assert) => { + onFetch((_, { method }) => { + assert.step(method); + }); + await get("/call_get"); + assert.verifySteps(["GET"]); + await post("/call_post"); + assert.verifySteps(["POST"]); +}); + +QUnit.test("check status 502", async (assert) => { + onFetch(() => { + return new Response({}, { status: 502 }); + }); + try { + await get("/custom_route"); + assert.notOk(true); + } catch (e) { + assert.strictEqual(e.message, "Failed to fetch"); + } +}); + +QUnit.test("FormData is built by post", async (assert) => { + onFetch((_, { body }) => { + assert.ok(body instanceof FormData); + assert.strictEqual(body.get("s"), "1"); + assert.strictEqual(body.get("a"), "1"); + assert.deepEqual(body.getAll("a"), ["1", "2", "3"]); + }); + await post("/call_post", { s: 1, a: [1, 2, 3] }); +}); + +QUnit.test("FormData is given to post", async (assert) => { + onFetch((_, { body }) => { + assert.strictEqual(body, formData); + }); + const formData = new FormData(); + await post("/call_post", formData); +}); diff --git a/addons/website/static/src/snippets/s_website_form/000.js b/addons/website/static/src/snippets/s_website_form/000.js index cb151cefe44..a50c33df54a 100644 --- a/addons/website/static/src/snippets/s_website_form/000.js +++ b/addons/website/static/src/snippets/s_website_form/000.js @@ -356,8 +356,13 @@ const { DateTime } = luxon; form_values.csrf_token = odoo.csrf_token; } + const formData = new FormData(); + for (const [key, value] of Object.entries(form_values)) { + formData.append(key, value); + } + // Post form and handle result - post(this.$el.attr('action') + (this.$el.data('force_action') || this.$el.data('model_name')), form_values) + post(this.$el.attr('action') + (this.$el.data('force_action') || this.$el.data('model_name')), formData) .then(async function (result_data) { // Restore send button behavior self.$el.find('.s_website_form_send, .o_website_form_send')