From 5e7de624a5e05f6050d79d3fb6f349033d1a650f Mon Sep 17 00:00:00 2001 From: NoeBerdoz Date: Tue, 12 May 2026 15:52:06 +0200 Subject: [PATCH 1/4] [MIG] Odoo 18 backend integration - vite.config.js: server. proxy /auth and /xmlrpc -> VITE_DEV_PROXY_TARGET (default http://localhost:8069). Lets npm run dev work against a local Odoo without CORS hacks, v18's /xmlrpc/2/* declares no cors= attribute, so cross-origin XML-RPC fails preflight in the browser. The proxy makes the browser see same-origin requests instead. - .env: VITE_ODOO_URL default changed from a placeholder to "" with guidance, recommended setting both for local dev (proxy intercepts relative URLs) and for the production deployment where Odoo serves the SPA from static/tp/ (also same-origin). Added VITE_DEV_PROXY_TARGET. - README: added "Running against Odoo 18" section documenting the three deployment modes (Odoo-served, dev with Vite proxy, true cross-origin which requires an Odoo-side CORS patch). The legacy v12/v14 source-patch instructions are kept for historical reference. The webapp's RPC contracts already match the v18 auth_external controllers, no changes to OdooAPI.ts, the store, or any DAO. --- .env | 16 ++++++++++--- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++- vite.config.js | 14 +++++++++++ 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/.env b/.env index 4017935..ce329c5 100644 --- a/.env +++ b/.env @@ -11,8 +11,18 @@ SERVE_URL="/" # can be something like /sbc_translation/static/ in .env.productio # can be something like /sbc_translation/static/ in .env.production.local file VITE_WEB_URL="/" -# Odoo instance URL -VITE_ODOO_URL="yoyoyo" +# Odoo instance URL. Leave empty to call /auth/* and /xmlrpc/* on the +# current origin — the recommended setting for both: +# - local dev (npm run dev) when using the Vite proxy below +# - production where the SPA is served by Odoo from static/tp/ +# Set to a full URL only when the SPA is hosted on a different origin +# from Odoo (cross-origin); see README for the CORS caveat. +VITE_ODOO_URL="" # Odoo instance database name -VITE_ODOO_DBNAME="yoyoyo" \ No newline at end of file +VITE_ODOO_DBNAME="yoyoyo" + +# Where `npm run dev` proxies /auth/* and /xmlrpc/* to. Defaults to +# http://localhost:8069 if unset. Override if your Odoo runs on a +# different port or host. +VITE_DEV_PROXY_TARGET="http://localhost:8069" \ No newline at end of file diff --git a/README.md b/README.md index e52f9bf..cf43c4e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,63 @@ built with [Owl](https://github.com/odoo/owl) and [Vite](https://vitejs.dev/). I 2. Run `npm run build`, it will build static files in the `/dist` directory 3. Copy those files wherever you want +## Running against Odoo 18 + +The backend module is `auth_external` (in +`compassion-switzerland/compassion-switzerland/auth_external`). It +exposes: + +- `POST /auth/login {login, password, totp}` → `{user_id, auth_tokens: {access_token, refresh_token, expires_at}}` +- `POST /auth/refresh {refresh_token}` → rotated `auth_tokens` +- `POST /auth/logout {refresh_token}` → revoke family + +Subsequent XML-RPC calls authenticate via the `Authorization: Bearer +` header (set automatically by `OdooAPI.ts`) with +`password='None'` in the `execute_kw` arguments. The Odoo-side +`res.users.check` override in `auth_external` validates the header. + +### Deployment modes + +**1. Served by Odoo (production / staging).** Run `npm run build` and +copy `dist/*` into `sbc_translation/static/tp/`. The +`TranslationPlatformController` in `sbc_translation/controllers/main.py` +serves the SPA at `/translation-platform`. The SPA and the Odoo API +share the same origin, so no CORS concerns. + +Set in `.env.production.local`: + +``` +SERVE_URL="/translation-platform/" +VITE_ODOO_URL="" +VITE_ODOO_DBNAME="" +``` + +**2. `npm run dev` against a local Odoo (local development).** This +is the recommended dev workflow. The Vite dev server proxies the +`/auth/*` and `/xmlrpc/*` paths to your local Odoo, so the browser +sees same-origin requests and there is no CORS preflight to deal +with. + +Set in `.env.local`: + +``` +SERVE_URL="/" +VITE_ODOO_URL="" +VITE_ODOO_DBNAME="" +# Only override if Odoo isn't on the default port/host: +# VITE_DEV_PROXY_TARGET="http://localhost:8069" +``` + +Then `npm run dev` and open . + +**3. Cross-origin hosting (non-default).** If you genuinely need the +SPA to be served from a different host than Odoo, you have to enable +CORS on `/xmlrpc/2/*` (stock v18 declares `cors=` only on `/auth/*`). +The simplest in-tree fix is to add a re-declaration of the XMLRPC +routes inside `auth_external` (or another module you control) with +`cors="*"`; the legacy Odoo-source patch shown further down is the +manual equivalent on v14 and earlier. + ## Environment files Please read the [vite documentation](https://vitejs.dev/guide/env-and-mode.html#modes). Mainly, environment files are loaded based on their name given the running mode: @@ -86,7 +143,12 @@ Whenever a missing translation is found it will be logged to the browser's conso the various missing translations by running `dumpMissingTranslations()` in your browser console, which will log a JSON object containing them. -#### ODOO Dev environment and CORS requests +#### ODOO Dev environment and CORS requests (legacy v12/v14) + +> **For v18:** prefer the Vite dev proxy described in the "Running +> against Odoo 18" section above — it sidesteps CORS entirely without +> touching Odoo's source. The patch below is kept for historical +> reference and for v12/v14 setups only. When running the platform in dev environment, you will very probably run into a cross-origin requests problem. To fix it quick and dirty, edit the `/odoo/service/wsgi_server.py` in Odoo's source code. diff --git a/vite.config.js b/vite.config.js index a52146d..6e0d170 100644 --- a/vite.config.js +++ b/vite.config.js @@ -12,8 +12,22 @@ import { defineConfig, loadEnv } from "vite"; export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ""); + // VITE_DEV_PROXY_TARGET sets where `npm run dev` proxies the Odoo + // backend (`/auth/*` and `/xmlrpc/*`). When set, the webapp can + // leave VITE_ODOO_URL empty and call relative paths; the browser + // sees same-origin requests and the dev server forwards them. + // This avoids the Odoo-side CORS gap on `/xmlrpc/2/*` (which has + // no `cors=` declared in stock v18). + const devProxyTarget = env.VITE_DEV_PROXY_TARGET || "http://localhost:8069"; + return { base: env.SERVE_URL, + server: { + proxy: { + "/auth": { target: devProxyTarget, changeOrigin: true }, + "/xmlrpc": { target: devProxyTarget, changeOrigin: true }, + }, + }, build: { commonjsOptions: { ignoreTryCatch: (id) => id !== "stream", From ad47f386c8f1a21bf2ed74803ba31d4d73aed7e0 Mon Sep 17 00:00:00 2001 From: NoeBerdoz Date: Tue, 12 May 2026 16:58:57 +0200 Subject: [PATCH 2/4] [MIG] replace search() API by search_count() --- src/models/LetterDAO.ts | 3 ++- src/models/TranslatorDAO.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/models/LetterDAO.ts b/src/models/LetterDAO.ts index b0198ff..4ac2ae8 100644 --- a/src/models/LetterDAO.ts +++ b/src/models/LetterDAO.ts @@ -139,9 +139,10 @@ const LetterDAO: BaseDAO & LetterDAOApi = { // Add global state // @ts-ignore searchParams[0].push(['state', '=', 'Global Partner translation queue']); + const countParams = [searchParams[0]]; const [letterIds, total] = await Promise.all([ OdooAPI.execute_kw('correspondence', 'search', searchParams), - OdooAPI.execute_kw('correspondence', 'search', [...searchParams, true]) as Promise + OdooAPI.execute_kw('correspondence', 'search_count', countParams) as Promise, ]); const rawLetters = await OdooAPI.execute_kw('correspondence', 'list_letters', [letterIds]); diff --git a/src/models/TranslatorDAO.ts b/src/models/TranslatorDAO.ts index 0e62d43..d3355bf 100644 --- a/src/models/TranslatorDAO.ts +++ b/src/models/TranslatorDAO.ts @@ -71,9 +71,10 @@ const TranslatorDAO: BaseDAO & TranslatorDAOApi = { async list(params) { const searchParams = generateSearchQuery(params, translatorFieldsMapping); + const countParams = [searchParams[0]]; const [translatorIds, total] = await Promise.all([ OdooAPI.execute_kw('translation.user', 'search', searchParams), - OdooAPI.execute_kw('translation.user', 'search', [...searchParams, true]) as Promise + OdooAPI.execute_kw('translation.user', 'search_count', countParams) as Promise, ]); const rawTranslators = await OdooAPI.execute_kw('translation.user', 'list_users', [translatorIds]); From 693eff5fff9bf48ed5bb649d96398bfe292445a1 Mon Sep 17 00:00:00 2001 From: NoeBerdoz Date: Tue, 12 May 2026 16:59:15 +0200 Subject: [PATCH 3/4] [MIG] adapt cors guidance --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index cf43c4e..448cb84 100644 --- a/README.md +++ b/README.md @@ -63,13 +63,13 @@ VITE_ODOO_DBNAME="" Then `npm run dev` and open . -**3. Cross-origin hosting (non-default).** If you genuinely need the -SPA to be served from a different host than Odoo, you have to enable -CORS on `/xmlrpc/2/*` (stock v18 declares `cors=` only on `/auth/*`). -The simplest in-tree fix is to add a re-declaration of the XMLRPC -routes inside `auth_external` (or another module you control) with -`cors="*"`; the legacy Odoo-source patch shown further down is the -manual equivalent on v14 and earlier. +**3. Cross-origin hosting (non-default).** If you ever need the SPA +to live on a different host from Odoo, you have to enable CORS on +`/xmlrpc/2/*` (stock v18 declares `cors=` only on `/auth/*`). Do it +narrowly, set the `cors=` value to the exact origin of the SPA, not +`"*"`, and only on that endpoint. Neither of the two recommended +deployments above triggers a CORS preflight (both are same-origin), +so we don't ship such an override. ## Environment files Please read the [vite documentation](https://vitejs.dev/guide/env-and-mode.html#modes). Mainly, environment files are loaded based From 33178d06025060cdc64392859c0b982fce18902f Mon Sep 17 00:00:00 2001 From: NoeBerdoz Date: Mon, 18 May 2026 14:27:08 +0200 Subject: [PATCH 4/4] [MIG] add missing new line --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index ce329c5..2a4f5a8 100644 --- a/.env +++ b/.env @@ -25,4 +25,4 @@ VITE_ODOO_DBNAME="yoyoyo" # Where `npm run dev` proxies /auth/* and /xmlrpc/* to. Defaults to # http://localhost:8069 if unset. Override if your Odoo runs on a # different port or host. -VITE_DEV_PROXY_TARGET="http://localhost:8069" \ No newline at end of file +VITE_DEV_PROXY_TARGET="http://localhost:8069"