74 lines
3.1 KiB
JavaScript
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;
|