feat: REST API v1 (Bearer JWT, CRUD entries + admin companies)

This commit is contained in:
2026-05-30 18:04:27 +03:00
parent 09bb56c6f4
commit 87216389e3
5 changed files with 181 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
'use strict';
const express = require('express');
function createEntriesRouter({ q }) {
const router = express.Router();
const json = express.json({ limit: '32kb' });
// ── Хелпер: маппинг сообщений ошибок на HTTP-коды ───────────────────────
function handleQueryError(e, res) {
const msg = e.message || '';
if (
msg.includes('Лимит исчерпан') ||
msg.includes('Такой адрес уже существует') ||
msg.includes('Пересечение с существующей записью')
) {
return res.status(409).json({ error: msg });
}
if (msg.includes('Запись не найдена')) {
return res.status(404).json({ error: msg });
}
return res.status(500).json({ error: msg });
}
// GET /api/v1/entries — список записей текущей компании
router.get('/', async (req, res) => {
try {
const company = await q.getOrCreateCompany(req.user.clientId, req.user.companyName);
const entries = await q.listEntries(company.id);
res.json({ entries });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
// POST /api/v1/entries — создать запись
router.post('/', json, async (req, res) => {
const { value, comment } = req.body || {};
if (!value) return res.status(400).json({ error: 'value required' });
try {
const company = await q.getOrCreateCompany(req.user.clientId, req.user.companyName);
const { entry, wasNormalized } = await q.createEntry(company.id, value, comment || '', req.user.email);
res.status(201).json({ entry, wasNormalized });
} catch (e) {
handleQueryError(e, res);
}
});
// PATCH /api/v1/entries/:id — обновить запись
router.patch('/:id', json, async (req, res) => {
const { value, comment } = req.body || {};
if (!value) return res.status(400).json({ error: 'value required' });
try {
const company = await q.getOrCreateCompany(req.user.clientId, req.user.companyName);
const { entry, wasNormalized } = await q.updateEntry(req.params.id, company.id, value, comment ?? '', req.user.email);
res.json({ entry, wasNormalized });
} catch (e) {
handleQueryError(e, res);
}
});
// DELETE /api/v1/entries/:id — удалить запись
router.delete('/:id', async (req, res) => {
try {
const company = await q.getOrCreateCompany(req.user.clientId, req.user.companyName);
await q.deleteEntry(req.params.id, company.id, req.user.email);
res.status(204).send();
} catch (e) {
handleQueryError(e, res);
}
});
return router;
}
module.exports = { createEntriesRouter };