quorlasocial/connector/test/odoo-settings.test.mjs
metatroncubeswdev 7c596ec6d5 Settings on the site instead of .env; Odoo in Connections
- Server settings (Settings page): SMTP, AI, publishing, Meta, platform keys and,
  on the control centre only, Stripe/billing. Stored sealed in data/settings.json and
  applied over .env in every process; hosted agency workspaces don't see our email,
  platform keys or billing.
- Odoo connection per workspace in Connections (login checked before saving).
- provision-tenants.sh marks agency containers with QUORLA_HOSTED_TENANT=true.
- docs/wildcard-subdomains.html: one-time setup for automatic agency subdomains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 19:49:15 -04:00

37 lines
2.2 KiB
JavaScript

// Odoo settings from Connections: login checked before saving, stored encrypted, key never returned, env fallback.
import { test } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "quorla-odoo-"));
const FILE = path.join(TMP, "connections.json");
Object.assign(process.env, { QUORLA_CONNECTIONS_FILE: FILE, DASHBOARD_SECRET: "s".repeat(32), QUORLA_DASHBOARD_DATA: path.join(TMP, "dash"), ODOO_URL: "", ODOO_API_KEY: "" });
const odoo = await import("../../dashboard/server/odoo.js");
test("save checks the login, stores it sealed and hides the key; disconnect clears it", async () => {
const realFetch = globalThis.fetch;
const calls = [];
globalThis.fetch = async (url, init) => {
const { params } = JSON.parse(init.body);
calls.push({ url: String(url), params });
const ok = params.args[2] === "good-key";
return new Response(JSON.stringify({ result: params.method === "login" ? (ok ? 7 : false) : null }));
};
try {
assert.equal(odoo.settings().configured, false);
const form = { url: "https://acme.odoo.com/odoo/action-1", db: "acme", username: "ops@acme.test", allowWrites: true };
await assert.rejects(odoo.saveSettings({ ...form, apiKey: "bad-key" }, "Ana"), /rejected the login/);
await assert.rejects(odoo.saveSettings({ ...form, apiKey: "" }, "Ana"), /required/);
const s = await odoo.saveSettings({ ...form, apiKey: "good-key" }, "Ana");
assert.equal(calls.at(-1).url, "https://acme.odoo.com/jsonrpc", "address trimmed to the site root");
assert.deepEqual([s.configured, s.source, s.url, s.allowWrites, s.updatedBy], [true, "settings", "https://acme.odoo.com", true, "Ana"]);
assert.equal(JSON.stringify(s).includes("good-key"), false);
assert.equal(fs.readFileSync(FILE, "utf8").includes("good-key"), false, "key encrypted at rest");
const again = await odoo.saveSettings({ ...form, apiKey: "", allowWrites: false }, "Ana");
assert.equal(again.allowWrites, false, "empty key keeps the stored one");
assert.equal(odoo.removeSettings().configured, false);
} finally { globalThis.fetch = realFetch; }
});