From 8ea10f1e373f9177eac2863bf560cc1b99e5ee13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Tue, 2 Jun 2026 11:20:51 +0300 Subject: [PATCH] =?UTF-8?q?v0.5.4:=20fix=20multi-company=20API=20=E2=80=94?= =?UTF-8?q?=20client=5Fid=20validation,=20export=20isolation,=20121=20test?= =?UTF-8?q?s=20PASS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/routes/entries.js | 20 +++++++++++++++----- tests/api.js | 7 ++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/api/routes/entries.js b/src/api/routes/entries.js index b8b7346..20210cf 100644 --- a/src/api/routes/entries.js +++ b/src/api/routes/entries.js @@ -49,9 +49,16 @@ function createEntriesRouter({ q }) { if (!c) throw Object.assign(new Error('Company not found'), { status: 404 }); return c; } - // Мульти-компания: если передан client_id — использовать его - const effectiveClientId = req.query.client_id || req.user.clientId; - return q.getOrCreateCompany(effectiveClientId, req.user.companyName); + // Мульти-компания: client_id разрешён только если есть в allClientIds пользователя + const requestedId = (req.query.client_id || '').trim(); + const effectiveClientId = (requestedId && req.user.allClientIds && req.user.allClientIds.includes(requestedId)) + ? requestedId + : req.user.clientId; + // companyName: для переключённой компании — clientId как имя по умолчанию + const effectiveName = effectiveClientId === req.user.clientId + ? req.user.companyName + : effectiveClientId; + return q.getOrCreateCompany(effectiveClientId, effectiveName); } // GET /api/v1/entries — список записей + лимит @@ -75,8 +82,11 @@ function createEntriesRouter({ q }) { try { let companyId = null; if (!req.user.isAdmin) { - const effectiveClientId = req.query.client_id || req.user.clientId; - const company = await q.getOrCreateCompany(effectiveClientId, req.user.companyName); + const requestedId = (req.query.client_id || '').trim(); + const effectiveClientId = (requestedId && req.user.allClientIds && req.user.allClientIds.includes(requestedId)) + ? requestedId + : req.user.clientId; + const company = await q.getOrCreateCompany(effectiveClientId, effectiveClientId); companyId = company.id; } else if (req.query.company) { const id = parseInt(req.query.company, 10); diff --git a/tests/api.js b/tests/api.js index 62edc53..0ed8a30 100644 --- a/tests/api.js +++ b/tests/api.js @@ -973,11 +973,12 @@ async function cleanup() { } } - // O7: несуществующий ?client_id= → upsert-ит новую компанию (безопасно) + // O7: несуществующий ?client_id= → игнорируется, фоллбек на WZ01325 (безопасность) { const r = await req.get('/api/v1/entries?client_id=NONEXISTENT').set(bearer(tokenMulti)); - log(r.status === 200, 'O7: GET ?client_id=NONEXISTENT → 200 (создаёт пустую компанию)', `status=${r.status}`); - log(json(r).entries?.length === 0, 'O7b: новая компания без записей'); + log(r.status === 200, 'O7: GET ?client_id=NONEXISTENT → 200 (игнор, фоллбек)', `status=${r.status}`); + // NONEXISTENT не в allClientIds → фоллбек на WZ01325 → записи ЕСТЬ + log(json(r).entries?.length > 0, 'O7b: фоллбек на WZ01325 — записи есть'); } // O8: admin передаёт ?client_id= → использует свою компанию (игнор)