mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
This reverts commit fd18a39238
.
This commit is contained in:
parent
fd18a39238
commit
87e24f6403
4 changed files with 35 additions and 194 deletions
|
@ -193,7 +193,7 @@ const Comment = ghostBookshelf.Model.extend({
|
||||||
// Relations
|
// Relations
|
||||||
'member', 'count.replies', 'count.likes', 'count.liked',
|
'member', 'count.replies', 'count.likes', 'count.liked',
|
||||||
// Replies (limited to 3)
|
// Replies (limited to 3)
|
||||||
'replies', 'replies.member', 'replies.count.likes', 'replies.count.liked'
|
'replies', 'replies.member' , 'replies.count.likes', 'replies.count.liked'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,24 +202,19 @@ const Comment = ghostBookshelf.Model.extend({
|
||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
|
|
||||||
async commentCount(options) {
|
async findMostLikedComment(options = {}) {
|
||||||
const query = this.forge().query();
|
let query = ghostBookshelf.knex('comments')
|
||||||
|
.select('comments.*')
|
||||||
if (options.postId) {
|
.count('comment_likes.id as count__likes') // Counting likes for sorting
|
||||||
query.where('post_id', options.postId);
|
.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)
|
||||||
if (options.status) {
|
.limit(1); // Limit to just 1 result
|
||||||
query.where('status', options.status);
|
// Execute the query and get the result
|
||||||
}
|
const result = await query.first(); // Fetch the single top comment
|
||||||
|
const id = result && result.id;
|
||||||
return query.count('id as count').then((result) => {
|
// Fetch the comment model by ID
|
||||||
return Number(result[0].count) || 0;
|
return this.findOne({id}, options);
|
||||||
}).catch((err) => {
|
|
||||||
throw new errors.InternalServerError({
|
|
||||||
err: err
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async findPage(options) {
|
async findPage(options) {
|
||||||
|
@ -238,6 +233,16 @@ const Comment = ghostBookshelf.Model.extend({
|
||||||
await model.load(relationsToLoadIndividually, _.omit(options, 'withRelated'));
|
await model.load(relationsToLoadIndividually, _.omit(options, 'withRelated'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if options.order === 'best', we findMostLikedComment
|
||||||
|
// then we remove it from the result set and add it as the first element
|
||||||
|
if (options.order === 'best' && options.page === '1') {
|
||||||
|
const mostLikedComment = await this.findMostLikedComment(options);
|
||||||
|
if (mostLikedComment) {
|
||||||
|
result.data = result.data.filter(comment => comment.id !== mostLikedComment.id);
|
||||||
|
result.data.unshift(mostLikedComment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -284,8 +289,10 @@ const Comment = ghostBookshelf.Model.extend({
|
||||||
*/
|
*/
|
||||||
permittedOptions: function permittedOptions(methodName) {
|
permittedOptions: function permittedOptions(methodName) {
|
||||||
let options = ghostBookshelf.Model.permittedOptions.call(this, methodName);
|
let options = ghostBookshelf.Model.permittedOptions.call(this, methodName);
|
||||||
|
|
||||||
// The comment model additionally supports having a parentId option
|
// The comment model additionally supports having a parentId option
|
||||||
options.push('parentId');
|
options.push('parentId');
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -51,11 +51,6 @@ module.exports = class CommentsController {
|
||||||
frame.options.filter = `post_id:${frame.options.post_id}`;
|
frame.options.filter = `post_id:${frame.options.post_id}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.options.order === 'best') {
|
|
||||||
return this.service.getBestComments(frame.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.service.getComments(frame.options);
|
return this.service.getComments(frame.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,60 +173,6 @@ class CommentsService {
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBestComments(options) {
|
|
||||||
this.checkEnabled();
|
|
||||||
const postId = options.post_id;
|
|
||||||
|
|
||||||
const allOrderedComments = await this.models.Comment.query()
|
|
||||||
.where('comments.post_id', postId) // Filter by postId
|
|
||||||
.select('comments.id')
|
|
||||||
.count('comment_likes.id as count__likes')
|
|
||||||
.leftJoin('comment_likes', 'comments.id', 'comment_likes.comment_id')
|
|
||||||
.groupBy('comments.id')
|
|
||||||
.orderByRaw(`
|
|
||||||
count__likes DESC,
|
|
||||||
comments.created_at DESC
|
|
||||||
`);
|
|
||||||
|
|
||||||
const totalComments = allOrderedComments.length;
|
|
||||||
|
|
||||||
if (totalComments === 0) {
|
|
||||||
const page = await this.models.Comment.findPage({...options, parentId: null});
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
const limit = Number(options.limit) || 15;
|
|
||||||
const currentPage = Number(options.page) || 1;
|
|
||||||
|
|
||||||
const orderedIds = allOrderedComments
|
|
||||||
.slice((options.page - 1) * limit, currentPage * limit)
|
|
||||||
.map(comment => comment.id);
|
|
||||||
|
|
||||||
const findPageOptions = {
|
|
||||||
...options,
|
|
||||||
filter: `id:[${orderedIds.join(',')}]`,
|
|
||||||
withRelated: options.withRelated
|
|
||||||
};
|
|
||||||
|
|
||||||
const page = await this.models.Comment.findPage(findPageOptions);
|
|
||||||
|
|
||||||
page.data = orderedIds
|
|
||||||
.map(id => page.data.find(comment => comment && comment.id === id))
|
|
||||||
.filter(comment => comment !== undefined);
|
|
||||||
|
|
||||||
page.meta.pagination = {
|
|
||||||
page: currentPage,
|
|
||||||
limit: limit,
|
|
||||||
pages: Math.ceil(totalComments / limit),
|
|
||||||
total: totalComments,
|
|
||||||
next: currentPage < Math.ceil(totalComments / limit) ? currentPage + 1 : null,
|
|
||||||
prev: currentPage > 1 ? currentPage - 1 : null
|
|
||||||
};
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} id - The ID of the Comment to get replies from
|
* @param {string} id - The ID of the Comment to get replies from
|
||||||
* @param {any} options
|
* @param {any} options
|
||||||
|
|
|
@ -7,7 +7,6 @@ const moment = require('moment-timezone');
|
||||||
const settingsCache = require('../../../core/shared/settings-cache');
|
const settingsCache = require('../../../core/shared/settings-cache');
|
||||||
const sinon = require('sinon');
|
const sinon = require('sinon');
|
||||||
const DomainEvents = require('@tryghost/domain-events');
|
const DomainEvents = require('@tryghost/domain-events');
|
||||||
const {forEach} = require('lodash');
|
|
||||||
|
|
||||||
let membersAgent, membersAgent2, postId, postAuthorEmail, postTitle;
|
let membersAgent, membersAgent2, postId, postAuthorEmail, postTitle;
|
||||||
|
|
||||||
|
@ -27,7 +26,6 @@ const dbFns = {
|
||||||
* @typedef {Object} AddCommentReplyData
|
* @typedef {Object} AddCommentReplyData
|
||||||
* @property {string} member_id
|
* @property {string} member_id
|
||||||
* @property {string} [html='This is a reply']
|
* @property {string} [html='This is a reply']
|
||||||
* @property {date} [created_at]
|
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @typedef {AddCommentData & {replies: AddCommentReplyData[]}} AddCommentWithRepliesData
|
* @typedef {AddCommentData & {replies: AddCommentReplyData[]}} AddCommentWithRepliesData
|
||||||
|
@ -42,8 +40,7 @@ const dbFns = {
|
||||||
post_id: data.post_id || postId,
|
post_id: data.post_id || postId,
|
||||||
member_id: data.member_id,
|
member_id: data.member_id,
|
||||||
parent_id: data.parent_id,
|
parent_id: data.parent_id,
|
||||||
html: data.html || '<p>This is a comment</p>',
|
html: data.html || '<p>This is a comment</p>'
|
||||||
created_at: data.created_at
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -514,124 +511,20 @@ describe('Comments API', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can show most liked comment first when order param = best', async function () {
|
it('can show most liked comment first when order param = best', async function () {
|
||||||
// await setupBrowseCommentsData();
|
await setupBrowseCommentsData();
|
||||||
// add another comment
|
|
||||||
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({
|
|
||||||
comment_id: secondBest.id,
|
|
||||||
member_id: loggedInMember.id
|
|
||||||
});
|
|
||||||
|
|
||||||
await dbFns.addLike({
|
|
||||||
comment_id: bestComment.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
|
|
||||||
.get(`/api/comments/post/${postId}/?page=1&order=best`)
|
|
||||||
.expectStatus(200);
|
|
||||||
|
|
||||||
should(data2.body.comments[0].id).eql(bestComment.id);
|
|
||||||
|
|
||||||
// check oldest comment
|
|
||||||
should(data2.body.comments[4].id).eql(oldestComment.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('checks that pagination is working when order param = best', async function () {
|
|
||||||
// create 20 comments
|
|
||||||
const postId2 = fixtureManager.get('posts', 1).id;
|
|
||||||
forEach(new Array(12).fill(0), async (item, index) => {
|
|
||||||
await dbFns.addComment({
|
|
||||||
member_id: fixtureManager.get('members', 1).id,
|
|
||||||
html: `This is comment ${index}`,
|
|
||||||
created_at: new Date(`2021-01-${index + 1}`)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const comment = await dbFns.addComment({
|
|
||||||
member_id: fixtureManager.get('members', 0).id,
|
|
||||||
html: 'This is the best comment',
|
|
||||||
created_at: new Date('2021-01-10')
|
|
||||||
});
|
|
||||||
|
|
||||||
await dbFns.addLike({
|
|
||||||
comment_id: comment.id,
|
|
||||||
member_id: loggedInMember.id
|
|
||||||
});
|
|
||||||
|
|
||||||
await dbFns.addLike({
|
|
||||||
comment_id: comment.id,
|
|
||||||
member_id: fixtureManager.get('members', 1).id
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await membersAgent
|
const data = await membersAgent
|
||||||
.get(`/api/comments/post/${postId}/?limit=5&page=1&order=best`)
|
.get(`/api/comments/post/${postId}`);
|
||||||
.expectStatus(200);
|
|
||||||
|
|
||||||
should(data.body.comments.length).eql(5);
|
await dbFns.addLike({
|
||||||
should(data.body.meta.pagination.total).eql(13);
|
comment_id: data.body.comments[1].id,
|
||||||
should(data.body.meta.pagination.pages).eql(3);
|
member_id: loggedInMember.id
|
||||||
should(data.body.meta.pagination.next).eql(2);
|
|
||||||
should(data.body.meta.pagination.prev).eql(null);
|
|
||||||
should(data.body.meta.pagination.limit).eql(5);
|
|
||||||
should(data.body.comments[0].id).eql(comment.id);
|
|
||||||
|
|
||||||
const data2 = await membersAgent
|
|
||||||
.get(`/api/comments/post/${postId}/?limit=5&page=2&order=best`)
|
|
||||||
.expectStatus(200);
|
|
||||||
|
|
||||||
should(data2.body.meta.pagination.next).eql(3);
|
|
||||||
should(data2.body.meta.pagination.prev).eql(1);
|
|
||||||
|
|
||||||
// ensure data2 does not contain any of the comments from data
|
|
||||||
const ids = data.body.comments.map(com => com.id);
|
|
||||||
data2.body.comments.forEach((com) => {
|
|
||||||
should(ids.includes(com.id)).eql(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const data3 = await membersAgent
|
const data2 = await membersAgent
|
||||||
.get(`/api/comments/post/${postId2}/?limit=5&page=1&order=best`)
|
.get(`/api/comments/post/${postId}/?order=best`)
|
||||||
.expectStatus(200);
|
.expectStatus(200);
|
||||||
|
|
||||||
should(data3.body.comments.length).eql(0);
|
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 () {
|
it('does not most liked comment first when order param and keeps normal order', async function () {
|
||||||
|
|
Loading…
Add table
Reference in a new issue