85 lines
4.9 KiB
JavaScript
85 lines
4.9 KiB
JavaScript
// ═══════════════════════════════════════════════════════════════════════════════
|
|
// V2 — CRUD API-слой
|
|
//
|
|
// ЭТО: чистые функции — API между фронтендами и БД.
|
|
// НЕ: Express, HTTP, req/res, сессии.
|
|
//
|
|
// ЗАЧЕМ:
|
|
// 1. Фронтенды (user/, admin/, test/) не знают про SQL, транзакции, companyId.
|
|
// 2. Валидация вызывается ОДИН раз здесь, не дублируется в каждом фронтенде.
|
|
// 3. clientId (W-номер) → companyId (внутренний ID БД) резолвится здесь.
|
|
// 4. Каждую функцию можно тестировать изолированно, без Express.
|
|
//
|
|
// КОНТРАКТ:
|
|
// list(clientId) → { entries, used, limit }
|
|
// add(clientId, cidr, ...) → { entry, wasNormalized }
|
|
// edit(entryId, clientId, ...) → { entry, wasNormalized }
|
|
// remove(entryId, clientId, ...) → void
|
|
//
|
|
// Вход: clientId — W-номер компании (строка вида "WZ10001").
|
|
// email — почта юзера (для аудита).
|
|
// impBy — почта админа при имперсонации (null если нет).
|
|
//
|
|
// Ошибки: throw — валидация, лимит, дубликат, пересечение.
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
|
|
const q = require('../db/queries');
|
|
const { validate } = require('../validators');
|
|
|
|
// ── resolve(clientId) → company (внутренний хелпер) ──────────────────────────
|
|
// Атомарный upsert: если компании с таким W-номером нет — создаст.
|
|
// Возвращает { id, client_id, name, custom_limit }.
|
|
// Вызывается из list/add/edit/remove перед каждой операцией.
|
|
async function resolve(clientId) {
|
|
return q.getOrCreateCompany(clientId, clientId);
|
|
}
|
|
|
|
// ── list(clientId, includeDeleted?) → { entries, used, limit } ──────────────
|
|
// Всегда возвращает лимит и счётчик активных записей.
|
|
// used — только неудалённые (deleted_at IS NULL).
|
|
async function list(clientId, includeDeleted = false) {
|
|
const co = await resolve(clientId);
|
|
const entries = await q.listEntries(co.id, includeDeleted);
|
|
const limit = await q.getLimit(co);
|
|
const used = entries.filter(e => !e.deleted_at).length;
|
|
return { entries, used, limit };
|
|
}
|
|
|
|
// ── add(clientId, cidr, comment, email, impBy) → { entry, wasNormalized } ───
|
|
// ПОРЯДОК:
|
|
// 1. validate(rawCidr) — проверка ТЗ (маска, диапазоны, нормализация).
|
|
// 2. resolve(clientId) — получить/создать компанию.
|
|
// 3. db.createEntry() — транзакция: лимит, дубликаты, INSERT + аудит.
|
|
// Если validate() бросает — до БД не доходим.
|
|
async function add(clientId, cidr, comment, email, impBy) {
|
|
const { cidr: validated, wasNormalized } = validate(cidr);
|
|
const co = await resolve(clientId);
|
|
return q.createEntry(co.id, validated, comment, email, impBy, wasNormalized);
|
|
}
|
|
|
|
// ── edit(entryId, clientId, cidr, comment, email, impBy) → { entry, wasNormalized }
|
|
// Аналогично add, но для существующей записи.
|
|
// entryId — id из v2_entries (число).
|
|
async function edit(entryId, clientId, cidr, comment, email, impBy) {
|
|
const { cidr: validated, wasNormalized } = validate(cidr);
|
|
const co = await resolve(clientId);
|
|
return q.updateEntry(entryId, co.id, validated, comment, email, impBy, wasNormalized);
|
|
}
|
|
|
|
// ── remove(entryId, clientId, email, impBy) → void ──────────────────────────
|
|
// Soft delete: ставит deleted_at, записывает аудит.
|
|
// Запись остаётся в БД, но не показывается в list().
|
|
async function remove(entryId, clientId, email, impBy) {
|
|
const co = await resolve(clientId);
|
|
return q.deleteEntry(entryId, co.id, email, impBy);
|
|
}
|
|
|
|
// ── restore(entryId, clientId, email, impBy) → void ─────────────────────────
|
|
// Восстановление удалённой записи.
|
|
async function restore(entryId, clientId, email, impBy) {
|
|
const co = await resolve(clientId);
|
|
return q.restoreEntry(entryId, co.id, email, impBy);
|
|
}
|
|
|
|
module.exports = { list, add, edit, remove, restore };
|