mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-06 22:40:14 -05:00
Fixed sorting by best Comment with pagination (#21506)
ref PLG-220 - Added an `orderAttributes` override method to be able to pass `count__likes` to the `findPage` DB helper. - Unknowingly, without that override method in the model, it would strip all 'non-default' queries. - Adding that means we could remove our custom database queries and use the regular `findPage` helper that also handles pagination.
This commit is contained in:
parent
8f9a89c1a5
commit
6742b20215
2 changed files with 54 additions and 37 deletions
|
@ -94,6 +94,12 @@ const Comment = ghostBookshelf.Model.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
orderAttributes: function orderAttributes() {
|
||||||
|
let keys = ghostBookshelf.Model.prototype.orderAttributes.call(this, arguments);
|
||||||
|
keys.push('count__likes');
|
||||||
|
return keys;
|
||||||
|
},
|
||||||
|
|
||||||
onCreated: function onCreated(model, options) {
|
onCreated: function onCreated(model, options) {
|
||||||
ghostBookshelf.Model.prototype.onCreated.apply(this, arguments);
|
ghostBookshelf.Model.prototype.onCreated.apply(this, arguments);
|
||||||
|
|
||||||
|
@ -202,31 +208,14 @@ const Comment = ghostBookshelf.Model.extend({
|
||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
|
|
||||||
async findMostLikedComment(options = {}) {
|
|
||||||
let query = ghostBookshelf.knex('comments')
|
|
||||||
.select('comments.*')
|
|
||||||
.count('comment_likes.id as count__likes') // Counting likes for sorting
|
|
||||||
.leftJoin('comment_likes', 'comments.id', 'comment_likes.comment_id')
|
|
||||||
.groupBy('comments.id') // Group by comment ID to aggregate likes count
|
|
||||||
.orderBy('count__likes', 'desc') // Order by likes in descending order (most likes first)
|
|
||||||
.limit(1); // Limit to just 1 result
|
|
||||||
// Execute the query and get the result
|
|
||||||
const result = await query.first(); // Fetch the single top comment
|
|
||||||
const id = result && result.id;
|
|
||||||
// Fetch the comment model by ID
|
|
||||||
return this.findOne({id}, options);
|
|
||||||
},
|
|
||||||
|
|
||||||
async findPage(options) {
|
async findPage(options) {
|
||||||
const {withRelated} = this.defaultRelations('findPage', options);
|
const {withRelated} = this.defaultRelations('findPage', options);
|
||||||
|
|
||||||
const relationsToLoadIndividually = [
|
const relationsToLoadIndividually = [
|
||||||
'replies',
|
'replies',
|
||||||
'replies.member',
|
'replies.member',
|
||||||
'replies.count.likes',
|
'replies.count.likes',
|
||||||
'replies.count.liked'
|
'replies.count.liked'
|
||||||
].filter(relation => withRelated.includes(relation));
|
].filter(relation => withRelated.includes(relation));
|
||||||
|
|
||||||
const result = await ghostBookshelf.Model.findPage.call(this, options);
|
const result = await ghostBookshelf.Model.findPage.call(this, options);
|
||||||
|
|
||||||
for (const model of result.data) {
|
for (const model of result.data) {
|
||||||
|
|
|
@ -510,38 +510,66 @@ describe('Comments API', function () {
|
||||||
should.not.exist(response.body.comments[0].unsubscribe_url);
|
should.not.exist(response.body.comments[0].unsubscribe_url);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can show most liked comment first when order param = best', async function () {
|
it('can show most liked comment first when order param = best followed by most recent', async function () {
|
||||||
await setupBrowseCommentsData();
|
// await setupBrowseCommentsData();
|
||||||
const data = await membersAgent
|
// add another comment
|
||||||
.get(`/api/comments/post/${postId}`);
|
await dbFns.addComment({
|
||||||
|
html: 'This is the newest comment',
|
||||||
|
member_id: fixtureManager.get('members', 2).id,
|
||||||
|
created_at: new Date('2024-08-18')
|
||||||
|
});
|
||||||
|
|
||||||
|
const secondBest = await dbFns.addComment({
|
||||||
|
member_id: fixtureManager.get('members', 0).id,
|
||||||
|
html: 'This will be the second best comment',
|
||||||
|
created_at: new Date('2022-01-01')
|
||||||
|
});
|
||||||
|
|
||||||
|
await dbFns.addComment({
|
||||||
|
member_id: fixtureManager.get('members', 1).id,
|
||||||
|
created_at: new Date('2023-01-01')
|
||||||
|
});
|
||||||
|
|
||||||
|
const bestComment = await dbFns.addComment({
|
||||||
|
member_id: fixtureManager.get('members', 2).id,
|
||||||
|
html: 'This will be the best comment',
|
||||||
|
created_at: new Date('2021-01-01')
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldestComment = await dbFns.addComment({
|
||||||
|
member_id: fixtureManager.get('members', 1).id,
|
||||||
|
html: 'ancient comment',
|
||||||
|
created_at: new Date('2019-01-01')
|
||||||
|
});
|
||||||
|
|
||||||
await dbFns.addLike({
|
await dbFns.addLike({
|
||||||
comment_id: data.body.comments[1].id,
|
comment_id: secondBest.id,
|
||||||
member_id: loggedInMember.id
|
member_id: loggedInMember.id
|
||||||
});
|
});
|
||||||
|
|
||||||
const data2 = await membersAgent
|
|
||||||
.get(`/api/comments/post/${postId}/?order=best`)
|
|
||||||
.expectStatus(200);
|
|
||||||
|
|
||||||
should(data2.body.comments[0].id).eql(data.body.comments[1].id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not most liked comment first when order param and keeps normal order', async function () {
|
|
||||||
await setupBrowseCommentsData();
|
|
||||||
const data = await membersAgent
|
|
||||||
.get(`/api/comments/post/${postId}`);
|
|
||||||
|
|
||||||
await dbFns.addLike({
|
await dbFns.addLike({
|
||||||
comment_id: data.body.comments[1].id,
|
comment_id: bestComment.id,
|
||||||
member_id: loggedInMember.id
|
member_id: loggedInMember.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await dbFns.addLike({
|
||||||
|
comment_id: bestComment.id,
|
||||||
|
member_id: fixtureManager.get('members', 0).id
|
||||||
|
});
|
||||||
|
|
||||||
|
await dbFns.addLike({
|
||||||
|
comment_id: bestComment.id,
|
||||||
|
member_id: fixtureManager.get('members', 1).id
|
||||||
|
});
|
||||||
|
|
||||||
const data2 = await membersAgent
|
const data2 = await membersAgent
|
||||||
.get(`/api/comments/post/${postId}/`)
|
.get(`/api/comments/post/${postId}/?page=1&order=count__likes%20desc%2C%20created_at%20desc`)
|
||||||
.expectStatus(200);
|
.expectStatus(200);
|
||||||
|
|
||||||
should(data2.body.comments[0].id).not.eql(data.body.comments[1].id);
|
// get the LAST comment from data2
|
||||||
|
let lastComment = data2.body.comments[data2.body.comments.length - 1];
|
||||||
|
|
||||||
|
should(lastComment.id).eql(oldestComment.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Can reply to your own comment', async function () {
|
it('Can reply to your own comment', async function () {
|
||||||
|
|
Loading…
Reference in a new issue