add filtering and sorting features; enhance events and articles pages with URL state persistence

This commit is contained in:
ImBenji
2026-04-23 23:03:11 +01:00
parent bec6763191
commit 194442ec4c
8 changed files with 274 additions and 16 deletions
+54 -5
View File
@@ -224,7 +224,7 @@ async function adminRoutes(fastify) {
return rows.map(r => r.source);
});
// events
// events — supports keyword / date range / min-article-count / sort
fastify.get('/admin/api/events', async (request, reply) => {
if (!checkAuth(request, reply)) return;
@@ -232,17 +232,66 @@ async function adminRoutes(fastify) {
const limit = Math.min(parseInt(q.limit, 10) || 50, 200);
const offset = parseInt(q.offset, 10) || 0;
const total = db.prepare(`SELECT COUNT(*) as n FROM events`).get().n;
const where = [];
const whereParams = [];
if (q.keyword) {
where.push('e.title LIKE ?');
whereParams.push(`%${q.keyword}%`);
}
if (q.from) {
where.push('e.created_at >= ?');
whereParams.push(q.from);
}
if (q.to) {
where.push('e.created_at <= ?');
whereParams.push(q.to);
}
// having filters operate on the aggregate count
const having = [];
const havingParams = [];
if (q.min_articles) {
const n = parseInt(q.min_articles, 10);
if (!isNaN(n)) { having.push('article_count >= ?'); havingParams.push(n); }
}
// whitelist sort columns + direction so user input cant break the query
const sortMap = {
created_desc: 'e.created_at DESC',
created_asc: 'e.created_at ASC',
articles_desc: 'article_count DESC',
articles_asc: 'article_count ASC',
};
const orderBy = sortMap[q.sort] || sortMap.created_desc;
const whereClause = where.length ? `WHERE ${where.join(' AND ')}` : '';
const havingClause = having.length ? `HAVING ${having.join(' AND ')}` : '';
// total count has to respect the HAVING clause too, so wrap the grouped query
const totalRow = db.prepare(`
SELECT COUNT(*) as n FROM (
SELECT e.id, COUNT(a.id) as article_count
FROM events e
LEFT JOIN articles a ON a.event_id = e.id
${whereClause}
GROUP BY e.id
${havingClause}
)
`).get(...whereParams, ...havingParams);
const rows = db.prepare(`
SELECT e.id, e.title, e.created_at, COUNT(a.id) as article_count
FROM events e
LEFT JOIN articles a ON a.event_id = e.id
${whereClause}
GROUP BY e.id
ORDER BY e.created_at DESC
${havingClause}
ORDER BY ${orderBy}
LIMIT ? OFFSET ?
`).all(limit, offset);
`).all(...whereParams, ...havingParams, limit, offset);
return { total, rows };
return { total: totalRow.n, rows };
});
fastify.delete('/admin/api/events/:id', async (request, reply) => {