Files
dispatch/backend/routes/articles.js
T
2026-07-10 15:48:21 +02:00

74 lines
3.1 KiB
JavaScript

const express = require('express');
const router = express.Router();
const db = require('../db');
// GET /api/articles?feed_id=&folder_id=&status=unread|starred|all&search=&page=&limit=
router.get('/', (req, res) => {
const { feed_id, folder_id, status = 'all', search, page = 1, limit = 30 } = req.query;
const clauses = [];
const params = {};
if (feed_id) { clauses.push('a.feed_id = @feed_id'); params.feed_id = feed_id; }
if (folder_id) { clauses.push('f.folder_id = @folder_id'); params.folder_id = folder_id; }
if (status === 'unread') clauses.push('a.is_read = 0');
if (status === 'starred') clauses.push('a.is_starred = 1');
if (search) { clauses.push('(a.title LIKE @search OR a.summary LIKE @search)'); params.search = `%${search}%`; }
const where = clauses.length ? `WHERE ${clauses.join(' AND ')}` : '';
const offset = (Number(page) - 1) * Number(limit);
const articles = db.prepare(`
SELECT a.id, a.feed_id, a.title, a.link, a.author, a.summary, a.image_url,
a.published_at, a.is_read, a.is_starred,
f.title AS feed_title, f.favicon AS feed_favicon
FROM articles a
JOIN feeds f ON f.id = a.feed_id
${where}
ORDER BY a.published_at DESC
LIMIT @limit OFFSET @offset
`).all({ ...params, limit: Number(limit), offset });
const total = db.prepare(`
SELECT COUNT(*) AS count FROM articles a JOIN feeds f ON f.id = a.feed_id ${where}
`).get(params).count;
res.json({ articles, total, page: Number(page), limit: Number(limit) });
});
router.get('/:id', (req, res) => {
const article = db.prepare(`
SELECT a.*, f.title AS feed_title, f.site_url AS feed_site_url, f.favicon AS feed_favicon
FROM articles a JOIN feeds f ON f.id = a.feed_id WHERE a.id = ?
`).get(req.params.id);
if (!article) return res.status(404).json({ error: 'Article not found' });
res.json(article);
});
router.patch('/:id', (req, res) => {
const { is_read, is_starred } = req.body;
const sets = [];
const params = { id: req.params.id };
if (is_read !== undefined) { sets.push('is_read = @is_read'); params.is_read = is_read ? 1 : 0; }
if (is_starred !== undefined) { sets.push('is_starred = @is_starred'); params.is_starred = is_starred ? 1 : 0; }
if (!sets.length) return res.status(400).json({ error: 'Nothing to update' });
db.prepare(`UPDATE articles SET ${sets.join(', ')} WHERE id = @id`).run(params);
res.json(db.prepare('SELECT * FROM articles WHERE id = ?').get(req.params.id));
});
// Bulk mark-as-read for a feed/folder/all
router.post('/mark-read', (req, res) => {
const { feed_id, folder_id, all } = req.body;
if (all) {
db.prepare('UPDATE articles SET is_read = 1 WHERE is_read = 0').run();
} else if (feed_id) {
db.prepare('UPDATE articles SET is_read = 1 WHERE feed_id = ? AND is_read = 0').run(feed_id);
} else if (folder_id) {
db.prepare(`UPDATE articles SET is_read = 1 WHERE is_read = 0 AND feed_id IN (SELECT id FROM feeds WHERE folder_id = ?)`).run(folder_id);
} else {
return res.status(400).json({ error: 'Specify feed_id, folder_id, or all' });
}
res.json({ ok: true });
});
module.exports = router;