v0.5.102: единый интерфейс /v2/app для юзеров и админов

This commit is contained in:
2026-06-15 13:30:12 +04:00
parent 2f151f4cdf
commit a31b3e61f2
6 changed files with 371 additions and 93 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
// ═══════════════════════════════════════════════════════════════════════════════
module.exports = {
version: '0.5.98',
version: '0.5.99',
// ── IAM ──────────────────────────────────────────────────────────────────
iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user',
+65 -16
View File
@@ -1,15 +1,22 @@
// ═══════════════════════════════════════════════════════════════════════════════
// V2 — Фронтенд пользователя (Express + EJS)
// V2 — Единый фронтенд (Express + EJS) — юзеры и админы
//
// ЭТО: Express-роутер, рендерит EJS-шаблоны.
// ЭТО: Express-роутер, рендерит EJS-шаблон views/v2/user.ejs.
// НЕ: работа с БД (только через crud/).
//
// ШАБЛОН: views/v2/user.ejs — данные: entries, limit, used, companies,
// activeClientId, user, includeDeleted, version.
// ОДИН ИНТЕРФЕЙС для юзеров и админов:
// - Юзер: dropdown = свои профили из IAM, CRUD внутри выбранной компании.
// - Админ: dropdown = все компании из БД, CRUD внутри выбранной.
// - По умолчанию: активный профиль (is_active_profile=true).
//
// ПЕРЕКЛЮЧЕНИЕ КОМПАНИИ: ?switchTo=W*** → обновляет activeClientId в сессии.
// - Юзер: только свои профили.
// - Админ: любая компания.
// ═══════════════════════════════════════════════════════════════════════════════
const express = require('express');
const crud = require('../crud');
const q = require('../db/queries');
const config = require('../config');
function createUserRouter() {
@@ -18,29 +25,71 @@ function createUserRouter() {
// ── GET / — список записей + форма ──────────────────────────────────
router.get('/', async (req, res) => {
try {
const isAdmin = req.isAdmin;
const clId = req.clientId;
const allCompanies = req.profiles.length > 0
? req.profiles
: [{ client_id: clId, company_name: req.companyName || clId }];
// ── Переключение компании ──────────────────────────────────────
if (req.query.switchTo) {
const targetId = req.query.switchTo;
if (isAdmin) {
// Админ может переключиться на любую компанию
req.session.user.activeClientId = targetId;
req.session.save(() => res.redirect('/v2/app'));
return;
} else {
// Юзер — только свои профили
const allowed = (req.profiles || []).find(p => p.client_id === targetId);
if (allowed) {
req.session.user.activeClientId = targetId;
req.session.save(() => res.redirect('/v2/app'));
return;
}
}
}
// ── Компании для dropdown ───────────────────────────────────────
let companies;
if (isAdmin) {
const all = await q.getAllCompanies();
companies = all.map(c => ({
client_id: c.client_id,
name: c.name || c.client_id,
active_count: c.active_count,
}));
} else {
companies = (req.profiles && req.profiles.length > 0)
? req.profiles.map(p => ({
client_id: p.client_id,
name: p.company_name || p.client_id,
is_active: p.is_active_profile,
}))
: [{ client_id: clId, name: req.companyName || clId, is_active: true }];
}
// ── Записи ──────────────────────────────────────────────────────
const includeDeleted = req.query.deleted === '1';
const { entries, used, limit } = await crud.list(clId, includeDeleted);
// Переключение компании
if (req.query.switchTo && allCompanies.find(c => c.client_id === req.query.switchTo)) {
req.session.user.activeClientId = req.query.switchTo;
return res.redirect('/v2/app');
}
// ── Данные пользователя для шаблона ────────────────────────────
const sessionUser = req.session && req.session.user ? req.session.user : {};
const templateUser = {
email: req.email,
fio: sessionUser.fio || null,
isAdmin: req.canAdmin || false,
adminMode: isAdmin,
isImpersonated: req.isImpersonated || false,
originalUserEmail: sessionUser.originalUserEmail || '',
originalUserFullName: sessionUser.originalUserFullName || '',
originalUserCompany: sessionUser.originalUserCompany || '',
};
res.render('v2/user', {
entries, limit, used,
companies: allCompanies,
companies,
activeClientId: clId,
user: req.user || {},
user: templateUser,
includeDeleted,
version: config.version,
canAdmin: req.canAdmin || false,
adminMode: req.adminMode || false,
});
} catch (e) {
res.status(500).send('<h2>Ошибка</h2><pre>' + e.message + '</pre><a href="/v2/app">Назад</a>');