Files
zeropost-engine/src/routes/notes.js
T
Alexey Pavlov bc2d311e59 feat: editor_notes + /api/stats/live + tokens в getArticleBySlug
- БД: таблица editor_notes (title/content/author/tags/is_pinned/is_published)
- routes/notes.js: CRUD заметок редактора
- /api/stats/live: latest article, processing job, активность за 7 дней
- getArticleBySlug: JOIN с generation_jobs для tokens_in/out
2026-05-31 10:05:28 +03:00

90 lines
2.8 KiB
JavaScript

const express = require('express');
const router = express.Router();
const { query } = require('../config/db');
// GET /api/notes — публичный список заметок
router.get('/', async (req, res) => {
try {
const limit = Math.min(parseInt(req.query.limit) || 20, 100);
const { rows } = await query(
`SELECT id, title, content, author, tags, is_pinned, created_at, updated_at
FROM editor_notes
WHERE is_published=true
ORDER BY is_pinned DESC, created_at DESC LIMIT $1`,
[limit]
);
res.json(rows);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// GET /api/notes/:id
router.get('/:id', async (req, res) => {
try {
const { rows } = await query(
`SELECT * FROM editor_notes WHERE id=$1 AND is_published=true`,
[req.params.id]
);
if (!rows.length) return res.status(404).json({ error: 'Not found' });
res.json(rows[0]);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// POST /api/notes — создать (требует auth, для админа через app.zeropost.ru)
router.post('/', async (req, res) => {
try {
const { title, content, author, tags = [], is_pinned = false } = req.body;
if (!content) return res.status(400).json({ error: 'content required' });
const { rows } = await query(
`INSERT INTO editor_notes (title, content, author, tags, is_pinned)
VALUES ($1,$2,$3,$4,$5) RETURNING *`,
[title || null, content, author || 'Редактор', JSON.stringify(tags), is_pinned]
);
res.json(rows[0]);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// PATCH /api/notes/:id
router.patch('/:id', async (req, res) => {
try {
const { title, content, author, tags, is_pinned, is_published } = req.body;
const { rows } = await query(
`UPDATE editor_notes SET
title=COALESCE($1, title),
content=COALESCE($2, content),
author=COALESCE($3, author),
tags=COALESCE($4::jsonb, tags),
is_pinned=COALESCE($5, is_pinned),
is_published=COALESCE($6, is_published),
updated_at=NOW()
WHERE id=$7 RETURNING *`,
[
title, content, author,
tags !== undefined ? JSON.stringify(tags) : null,
is_pinned, is_published, req.params.id,
]
);
if (!rows.length) return res.status(404).json({ error: 'Not found' });
res.json(rows[0]);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// DELETE /api/notes/:id
router.delete('/:id', async (req, res) => {
try {
await query(`DELETE FROM editor_notes WHERE id=$1`, [req.params.id]);
res.json({ ok: true });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
module.exports = router;