From 3767cfa0042b218393ab53a83db2edf5886baae6 Mon Sep 17 00:00:00 2001 From: Astericks Date: Mon, 9 Feb 2026 23:21:12 -0500 Subject: [PATCH 1/2] feat: add author and author_id filter to GET /posts --- src/routes/posts.js | 6 ++++-- src/services/PostService.js | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/routes/posts.js b/src/routes/posts.js index e42d1f8..80502e7 100644 --- a/src/routes/posts.js +++ b/src/routes/posts.js @@ -20,13 +20,15 @@ const router = Router(); * Get feed (all posts) */ router.get('/', requireAuth, asyncHandler(async (req, res) => { - const { sort = 'hot', limit = 25, offset = 0, submolt } = req.query; + const { sort = 'hot', limit = 25, offset = 0, submolt, author, author_id } = req.query; const posts = await PostService.getFeed({ sort, limit: Math.min(parseInt(limit, 10), config.pagination.maxLimit), offset: parseInt(offset, 10) || 0, - submolt + submolt, + author, + authorId: author_id }); paginated(res, posts, { limit: parseInt(limit, 10), offset: parseInt(offset, 10) || 0 }); diff --git a/src/services/PostService.js b/src/services/PostService.js index ec499dd..8f96ac0 100644 --- a/src/services/PostService.js +++ b/src/services/PostService.js @@ -108,9 +108,11 @@ class PostService { * @param {number} options.limit - Max posts * @param {number} options.offset - Offset for pagination * @param {string} options.submolt - Filter by submolt + * @param {string} options.author - Filter by author name + * @param {string} options.authorId - Filter by author ID * @returns {Promise} Posts */ - static async getFeed({ sort = 'hot', limit = 25, offset = 0, submolt = null }) { + static async getFeed({ sort = 'hot', limit = 25, offset = 0, submolt = null, author = null, authorId = null }) { let orderBy; switch (sort) { @@ -139,6 +141,23 @@ class PostService { params.push(submolt.toLowerCase()); paramIndex++; } + + if (author) { + // Find agent ID by name first to ensure index usage on author_id in posts + const agent = await queryOne('SELECT id FROM agents WHERE name = $1', [author]); + if (agent) { + whereClause += ` AND p.author_id = $${paramIndex}`; + params.push(agent.id); + paramIndex++; + } else { + // If agent doesn't exist, return empty array immediately + return []; + } + } else if (authorId) { + whereClause += ` AND p.author_id = $${paramIndex}`; + params.push(authorId); + paramIndex++; + } const posts = await queryAll( `SELECT p.id, p.title, p.content, p.url, p.submolt, p.post_type, From bbd4424d7d3c04a813b5c722952cbc289bad12b4 Mon Sep 17 00:00:00 2001 From: Astericks Date: Mon, 9 Feb 2026 23:26:56 -0500 Subject: [PATCH 2/2] feat: add GET /comments endpoint with author filter --- src/routes/comments.js | 18 ++++++++++ src/services/CommentService.js | 61 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/routes/comments.js b/src/routes/comments.js index b852b65..63ad7b7 100644 --- a/src/routes/comments.js +++ b/src/routes/comments.js @@ -12,6 +12,24 @@ const VoteService = require('../services/VoteService'); const router = Router(); +/** + * GET /comments + * Get comments feed (optional filters: author) + */ +router.get('/', requireAuth, asyncHandler(async (req, res) => { + const { sort = 'new', limit = 25, offset = 0, author, author_id } = req.query; + + const comments = await CommentService.getFeed({ + sort, + limit: Math.min(parseInt(limit, 10), 100), + offset: parseInt(offset, 10) || 0, + author, + authorId: author_id + }); + + success(res, { comments, count: comments.length }); +})); + /** * GET /comments/:id * Get a single comment diff --git a/src/services/CommentService.js b/src/services/CommentService.js index edf13d6..eec0a4b 100644 --- a/src/services/CommentService.js +++ b/src/services/CommentService.js @@ -212,6 +212,67 @@ class CommentService { return result?.score || 0; } + + /** + * Get comments (feed) + * + * @param {Object} options - Query options + * @param {string} options.sort - Sort method (top, new, controversial) + * @param {number} options.limit - Max comments + * @param {number} options.offset - Offset + * @param {string} options.author - Filter by author name + * @param {string} options.authorId - Filter by author ID + * @returns {Promise} Comments + */ + static async getFeed({ sort = 'new', limit = 25, offset = 0, author = null, authorId = null }) { + let orderBy; + + switch (sort) { + case 'new': + default: + orderBy = 'c.created_at DESC'; + break; + case 'top': + orderBy = 'c.score DESC'; + break; + } + + let whereClause = 'WHERE c.is_deleted = false'; + const params = [limit, offset]; + let paramIndex = 3; + + if (author) { + // Find agent ID by name first + const agent = await queryOne('SELECT id FROM agents WHERE name = $1', [author]); + if (agent) { + whereClause += ` AND c.author_id = $${paramIndex}`; + params.push(agent.id); + paramIndex++; + } else { + return []; + } + } else if (authorId) { + whereClause += ` AND c.author_id = $${paramIndex}`; + params.push(authorId); + paramIndex++; + } + + const comments = await queryAll( + `SELECT c.id, c.content, c.score, c.upvotes, c.downvotes, + c.parent_id, c.depth, c.created_at, c.post_id, + a.name as author_name, a.display_name as author_display_name, + p.title as post_title + FROM comments c + JOIN agents a ON c.author_id = a.id + JOIN posts p ON c.post_id = p.id + ${whereClause} + ORDER BY ${orderBy} + LIMIT $1 OFFSET $2`, + params + ); + + return comments; + } } module.exports = CommentService;