feat: admin-роль (isAdmin, requireAdmin), getCompanyById, getAllCompanies, setLimit, getAudit с JOIN
This commit is contained in:
+64
-3
@@ -141,6 +141,58 @@ async function deleteEntry(entryId, companyId, userEmail) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Admin: компании ──
|
||||
|
||||
/**
|
||||
* Получить одну компанию по числовому id (primary key).
|
||||
* Используется когда admin работает с чужой компанией:
|
||||
* нам не нужно getOrCreateCompany (которая привязывается к clientId пользователя).
|
||||
*
|
||||
* @param {number} id — companies.id
|
||||
* @returns {object|null} строка из таблицы companies или null
|
||||
*/
|
||||
async function getCompanyById(id) {
|
||||
const res = await pool.query('SELECT * FROM companies WHERE id = $1', [id]);
|
||||
return res.rows[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить все компании с количеством активных записей каждой.
|
||||
* Используется на странице администратора: список компаний + статистика.
|
||||
* LEFT JOIN гарантирует присутствие компаний с нулём записей.
|
||||
*
|
||||
* @returns {object[]} строки companies с доп. полем active_count
|
||||
*/
|
||||
async function getAllCompanies() {
|
||||
const res = await pool.query(`
|
||||
SELECT c.*,
|
||||
COUNT(e.id)::int AS active_count
|
||||
FROM companies c
|
||||
LEFT JOIN whitelist_entries e
|
||||
ON e.company_id = c.id AND e.deleted_at IS NULL
|
||||
GROUP BY c.id
|
||||
ORDER BY c.name, c.client_id
|
||||
`);
|
||||
return res.rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Задать индивидуальный лимит для компании.
|
||||
* newLimit = null → сброс на глобальный дефолт (DEFAULT_LIMIT из .env / 15).
|
||||
* newLimit = число → индивидуальный лимит, переопределяет глобальный.
|
||||
*
|
||||
* ТЗ 4.5: «снижение лимита не удаляет существующие записи, но блокирует создание новых».
|
||||
*
|
||||
* @param {number} companyId — companies.id
|
||||
* @param {number|null} newLimit — новый лимит или null для сброса
|
||||
*/
|
||||
async function setLimit(companyId, newLimit) {
|
||||
await pool.query(
|
||||
'UPDATE companies SET custom_limit = $1, updated_at = NOW() WHERE id = $2',
|
||||
[newLimit, companyId]
|
||||
);
|
||||
}
|
||||
|
||||
// ── Export ──
|
||||
|
||||
async function getExportCIDRs(companyId = null) {
|
||||
@@ -165,13 +217,20 @@ async function logAudit(userEmail, companyId, action, oldValue, newValue, entryI
|
||||
}
|
||||
|
||||
async function getAudit(companyId = null) {
|
||||
let sql = 'SELECT * FROM audit_log';
|
||||
// JOIN с companies чтобы выводить human-readable название компании в UI.
|
||||
// Лимит 500 строк — достаточно для оперативного мониторинга.
|
||||
// В проде можно добавить пагинацию.
|
||||
let sql = `
|
||||
SELECT a.*, c.name AS company_name, c.client_id
|
||||
FROM audit_log a
|
||||
JOIN companies c ON c.id = a.company_id
|
||||
`;
|
||||
const params = [];
|
||||
if (companyId) {
|
||||
sql += ' WHERE company_id = $1';
|
||||
sql += ' WHERE a.company_id = $1';
|
||||
params.push(companyId);
|
||||
}
|
||||
sql += ' ORDER BY created_at DESC LIMIT 500';
|
||||
sql += ' ORDER BY a.created_at DESC LIMIT 500';
|
||||
return (await pool.query(sql, params)).rows;
|
||||
}
|
||||
|
||||
@@ -180,4 +239,6 @@ module.exports = {
|
||||
listEntries, createEntry, updateEntry, deleteEntry,
|
||||
getExportCIDRs,
|
||||
getAudit,
|
||||
// admin
|
||||
getCompanyById, getAllCompanies, setLimit,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user