diff --git a/.env b/.env index 4017935..2a4f5a8 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" diff --git a/README.md b/README.md index e52f9bf..448cb84 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 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 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/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]); 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",