refactor: entries.js — remove 'own' hack, clean admin company routing + bump 0.4.7

This commit is contained in:
2026-05-31 07:25:42 +03:00
parent a355b34e4a
commit 5c286af43b
2 changed files with 38 additions and 41 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ipwhitelist", "name": "ipwhitelist",
"version": "0.4.6", "version": "0.4.7",
"description": "IP WhiteList microservice for cloud provider", "description": "IP WhiteList microservice for cloud provider",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
+37 -40
View File
@@ -4,8 +4,12 @@
* ui/routes/entries.js — главная страница: список записей + CRUD. * ui/routes/entries.js — главная страница: список записей + CRUD.
* *
* Данные из /api/v1/entries (Bearer token из сессии). * Данные из /api/v1/entries (Bearer token из сессии).
* Admin: поддержка ?company=<id> (числовой PK) для управления другой компанией. * Admin: ?company=<id> (числовой PK) для управления конкретной компанией.
* Формы с company_id скрытым полем → передаётся в API как ?company=<id>. * - Без параметра: ищем компанию admin в списке по clientId.
* Если не найдена (первый вход) — один GET /api/v1/entries создаёт её,
* потом редирект на числовой ID.
* - С параметром: грузим записи этой компании через admin-ветку API.
* User: без параметра, API сам определяет компанию по clientId из токена.
*/ */
const { Router } = require('express'); const { Router } = require('express');
@@ -14,19 +18,16 @@ const api = require('../api-client');
function createRouter() { function createRouter() {
const router = Router(); const router = Router();
// Вычислить URL для возврата (с учётом выбранной компании) // URL для возврата после CRUD — всегда с числовым company ID
function backUrl(req) { function backUrl(req) {
const companyId = req.query.company || (req.body && req.body.company_id); const id = req.query.company || (req.body && req.body.company_id);
if (!companyId || companyId === 'own') return '/?company=own'; return id ? '/?company=' + id : '/';
return '/?company=' + companyId;
} }
// Суффикс ?company=<id> для вызовов API // Суффикс ?company=<id> для API — только числовой ID или пусто
// 'own' = компания admin без ?company — API использует getOrCreateCompany
function companyQuery(req) { function companyQuery(req) {
const companyId = req.query.company || (req.body && req.body.company_id); const id = req.query.company || (req.body && req.body.company_id);
if (!companyId || companyId === 'own') return ''; return id ? '?company=' + id : '';
return '?company=' + companyId;
} }
// GET / — список записей // GET / — список записей
@@ -39,29 +40,25 @@ function createRouter() {
const cr = await api.get('/api/v1/companies', token); const cr = await api.get('/api/v1/companies', token);
companies = cr.data.companies || []; companies = cr.data.companies || [];
const companyParam = req.query.company || ''; const companyId = req.query.company ? parseInt(req.query.company, 10) : null;
const companyId = companyParam && companyParam !== 'own' ? parseInt(companyParam, 10) : null;
// Без параметра — редирект на свою компанию if (!companyId) {
if (!companyParam) { // Найти свою компанию admin по clientId
return res.redirect('/?company=own'); let ownCo = companies.find(c => c.client_id === req.user.clientId) || null;
if (!ownCo) {
// Компании нет — создаём через первый GET /entries (getOrCreateCompany внутри)
await api.get('/api/v1/entries', token);
const cr2 = await api.get('/api/v1/companies', token);
ownCo = (cr2.data.companies || []).find(c => c.client_id === req.user.clientId) || null;
}
return res.redirect('/?company=' + (ownCo ? ownCo.id : ''));
} }
if (companyParam === 'own') { selectedCompany = companies.find(c => c.id === companyId) || null;
// Создаём/получаем компанию admin через API (getOrCreateCompany) if (selectedCompany) {
await api.get('/api/v1/entries', token); const er = await api.get('/api/v1/entries?company=' + companyId, token);
// Перезагружаем список — теперь компания admin точно есть entries = er.data.entries || [];
const cr2 = await api.get('/api/v1/companies', token); limit = er.data.limit || 15;
const adminCo = (cr2.data.companies || []).find(c => c.client_id === req.user.clientId);
return res.redirect('/?company=' + (adminCo ? adminCo.id : ''));
} else {
selectedCompany = companyId ? companies.find(c => c.id === companyId) || null : null;
if (selectedCompany) {
const er = await api.get('/api/v1/entries?company=' + companyId, token);
entries = er.data.entries || [];
limit = er.data.limit || selectedCompany.custom_limit || selectedCompany.default_limit || 15;
}
} }
} else { } else {
const er = await api.get('/api/v1/entries', token); const er = await api.get('/api/v1/entries', token);
@@ -72,21 +69,21 @@ function createRouter() {
res.render('index', { res.render('index', {
entries, entries,
limit, limit,
used: entries.length, used: entries.length,
user: req.user, user: req.user,
isAdmin: req.user.isAdmin, isAdmin: req.user.isAdmin,
companies, companies,
selectedCompany, selectedCompany,
error: req.query.error || null, error: req.query.error || null,
success: req.query.success || null, success: req.query.success || null,
csrfToken: '', csrfToken: '',
}); });
} catch (e) { } catch (e) {
res.render('index', { res.render('index', {
entries: [], limit: 15, used: 0, entries: [], limit: 15, used: 0,
user: req.user, isAdmin: req.user.isAdmin, user: req.user, isAdmin: req.user.isAdmin,
companies: [], selectedCompany: null, companies: [], selectedCompany: null,
error: 'Ошибка загрузки данных: ' + e.message, error: 'Ошибка загрузки: ' + e.message,
success: null, csrfToken: '', success: null, csrfToken: '',
}); });
} }
@@ -106,7 +103,7 @@ function createRouter() {
: 'Запись добавлена'; : 'Запись добавлена';
return res.redirect(back + (back.includes('?') ? '&' : '?') + 'success=' + encodeURIComponent(msg)); return res.redirect(back + (back.includes('?') ? '&' : '?') + 'success=' + encodeURIComponent(msg));
} }
res.redirect(back + (back.includes('?') ? '&' : '?') + 'error=' + encodeURIComponent(r.data.error || 'Ошибка')); res.redirect(back + (back.includes('?') ? '&' : '?') + 'error=' + encodeURIComponent((r.data && r.data.error) || 'Ошибка'));
} catch (e) { } catch (e) {
res.redirect(back + (back.includes('?') ? '&' : '?') + 'error=' + encodeURIComponent(e.message)); res.redirect(back + (back.includes('?') ? '&' : '?') + 'error=' + encodeURIComponent(e.message));
} }
@@ -123,7 +120,7 @@ function createRouter() {
if (r.status === 200) { if (r.status === 200) {
return res.redirect(back + (back.includes('?') ? '&' : '?') + 'success=' + encodeURIComponent('Запись обновлена')); return res.redirect(back + (back.includes('?') ? '&' : '?') + 'success=' + encodeURIComponent('Запись обновлена'));
} }
res.redirect(back + (back.includes('?') ? '&' : '?') + 'error=' + encodeURIComponent(r.data.error || 'Ошибка')); res.redirect(back + (back.includes('?') ? '&' : '?') + 'error=' + encodeURIComponent((r.data && r.data.error) || 'Ошибка'));
} catch (e) { } catch (e) {
res.redirect(back + (back.includes('?') ? '&' : '?') + 'error=' + encodeURIComponent(e.message)); res.redirect(back + (back.includes('?') ? '&' : '?') + 'error=' + encodeURIComponent(e.message));
} }