mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Fixed hidden/deleted replies in getCommentByID
(#21707)
ref PLG-270 - Updated the getCommentByID service to filter out hidden and deleted replies. - Ensured all replies are loaded before applying the filter. - Simplified logic to handle non-paginated routes by directly removing unwanted replies. - Wired up new Admin Endpoint that shows hidden replies but not deleted replies. - Updated comments-ui client.
This commit is contained in:
parent
7cfb755bbd
commit
31a80cf9b8
8 changed files with 200 additions and 4 deletions
|
@ -100,7 +100,7 @@ async function addReply({state, api, data: {reply, parent}}: {state: EditableApp
|
|||
}
|
||||
|
||||
async function hideComment({state, data: comment}: {state: EditableAppContext, adminApi: any, data: {id: string}}) {
|
||||
if (state.adminApi) {
|
||||
if (state.admin && state.adminApi && state.labs.commentImprovements) {
|
||||
await state.adminApi.hideComment(comment.id);
|
||||
}
|
||||
return {
|
||||
|
@ -134,8 +134,8 @@ async function hideComment({state, data: comment}: {state: EditableAppContext, a
|
|||
}
|
||||
|
||||
async function showComment({state, api, data: comment}: {state: EditableAppContext, api: GhostApi, adminApi: any, data: {id: string}}) {
|
||||
if (state.adminApi) {
|
||||
await state.adminApi.showComment(comment.id);
|
||||
if (state.admin && state.adminApi && state.labs.commentImprovements) {
|
||||
await state.adminApi.read({commentId: comment.id});
|
||||
}
|
||||
// We need to refetch the comment, to make sure we have an up to date HTML content
|
||||
// + all relations are loaded as the current member (not the admin)
|
||||
|
|
|
@ -105,6 +105,11 @@ export function setupAdminAPI({adminUrl}: {adminUrl: string}) {
|
|||
|
||||
const response = await callApi('getReplies', {commentId, params: params.toString()});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
async read({commentId}: {commentId: string}) {
|
||||
const response = await callApi('readComment', {commentId});
|
||||
return response;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -49,6 +49,19 @@ window.addEventListener('message', async function (event) {
|
|||
}
|
||||
}
|
||||
|
||||
if (data.action === 'readComment') {
|
||||
try {
|
||||
const {commentId} = data;
|
||||
const res = await fetch(
|
||||
adminUrl + `/comments/${commentId}/}`
|
||||
);
|
||||
const json = await res.json();
|
||||
respond(null, json);
|
||||
} catch (err) {
|
||||
respond(err, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.action === 'getUser') {
|
||||
try {
|
||||
const res = await fetch(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// This is a new endpoint for the admin API to return replies to a comment with pagination
|
||||
const ALLOWED_INCLUDES = ['member', 'replies', 'replies.member', 'replies.count.likes', 'replies.liked', 'count.replies', 'count.likes', 'liked', 'post', 'parent'];
|
||||
|
||||
const commentsService = require('../../services/comments');
|
||||
|
||||
|
@ -30,6 +31,27 @@ const controller = {
|
|||
query(frame) {
|
||||
return commentsService.controller.adminReplies(frame);
|
||||
}
|
||||
}, read: {
|
||||
headers: {
|
||||
cacheInvalidate: false
|
||||
},
|
||||
options: [
|
||||
'include'
|
||||
],
|
||||
data: [
|
||||
'id',
|
||||
'email'
|
||||
],
|
||||
validation: {
|
||||
options: {
|
||||
include: ALLOWED_INCLUDES
|
||||
}
|
||||
},
|
||||
permissions: true,
|
||||
query(frame) {
|
||||
frame.options.isAdmin = true;
|
||||
return commentsService.controller.read(frame);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ const tpl = require('@tryghost/tpl');
|
|||
const errors = require('@tryghost/errors');
|
||||
const {MemberCommentEvent} = require('@tryghost/member-events');
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
const labs = require('../../../shared/labs');
|
||||
|
||||
const messages = {
|
||||
commentNotFound: 'Comment could not be found',
|
||||
|
@ -208,6 +209,29 @@ class CommentsService {
|
|||
});
|
||||
}
|
||||
|
||||
if (labs.isSet('commentImprovements')) {
|
||||
const replies = model.related('replies'); // Get the loaded replies relation
|
||||
await replies.fetch(); // Ensure all replies are loaded
|
||||
|
||||
if (replies && replies.length > 0) {
|
||||
// Filter out deleted replies for all, and hidden replies for non-admins
|
||||
replies.remove(
|
||||
replies.filter((reply) => {
|
||||
const status = reply.get('status');
|
||||
if (status === 'deleted') {
|
||||
return true;
|
||||
} // Always remove deleted replies
|
||||
if (!options.isAdmin && status === 'hidden') {
|
||||
return true;
|
||||
} // Remove hidden replies for non-admins
|
||||
return false; // Keep others
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// this route does not need need to handle pagination, so we can remove hidden/deleted replies here
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ module.exports = function apiRoutes() {
|
|||
router.get('/comments/:id/replies', mw.authAdminApi, http(api.commentReplies.browse));
|
||||
router.get('/comments/post/:post_id', mw.authAdminApi, http(api.comments.browse));
|
||||
router.put('/comments/:id', mw.authAdminApi, http(api.comments.edit));
|
||||
router.get('/comments/:id', mw.authAdminApi, http(api.commentReplies.read));
|
||||
|
||||
// ## Pages
|
||||
router.get('/pages', mw.authAdminApi, http(api.pages.browse));
|
||||
|
|
|
@ -458,6 +458,89 @@ describe('Admin Comments API', function () {
|
|||
assert.equal(res2.body.comments[0].html, 'Reply 4');
|
||||
});
|
||||
|
||||
it('Does not return deleted replies', async function () {
|
||||
const post = fixtureManager.get('posts', 1);
|
||||
await mockManager.mockLabsEnabled('commentImprovements');
|
||||
const {parent} = await dbFns.addCommentWithReplies({
|
||||
post_id: post.id,
|
||||
member_id: fixtureManager.get('members', 0).id,
|
||||
replies: [{
|
||||
member_id: fixtureManager.get('members', 1).id,
|
||||
status: 'hidden'
|
||||
}, {
|
||||
member_id: fixtureManager.get('members', 2).id,
|
||||
status: 'deleted'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 3).id,
|
||||
status: 'hidden'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 4).id,
|
||||
status: 'published'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const res = await adminApi.get(`/comments/${parent.get('id')}/`);
|
||||
res.body.comments[0].replies.length.should.eql(3);
|
||||
});
|
||||
|
||||
it('Does return published replies', async function () {
|
||||
const post = fixtureManager.get('posts', 1);
|
||||
await mockManager.mockLabsEnabled('commentImprovements');
|
||||
const {parent} = await dbFns.addCommentWithReplies({
|
||||
post_id: post.id,
|
||||
member_id: fixtureManager.get('members', 0).id,
|
||||
replies: [{
|
||||
member_id: fixtureManager.get('members', 1).id,
|
||||
status: 'published'
|
||||
}, {
|
||||
member_id: fixtureManager.get('members', 2).id,
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 3).id,
|
||||
status: 'published'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const res = await adminApi.get(`/comments/${parent.get('id')}/`);
|
||||
res.body.comments[0].replies.length.should.eql(3);
|
||||
});
|
||||
|
||||
it('Does return published and hidden replies but not deleted', async function () {
|
||||
const post = fixtureManager.get('posts', 1);
|
||||
await mockManager.mockLabsEnabled('commentImprovements');
|
||||
const {parent} = await dbFns.addCommentWithReplies({
|
||||
post_id: post.id,
|
||||
member_id: fixtureManager.get('members', 0).id,
|
||||
replies: [{
|
||||
member_id: fixtureManager.get('members', 1).id,
|
||||
status: 'published'
|
||||
}, {
|
||||
member_id: fixtureManager.get('members', 2).id,
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 3).id,
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 4).id,
|
||||
status: 'hidden'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 5).id,
|
||||
status: 'deleted'
|
||||
}
|
||||
]
|
||||
});
|
||||
const res = await adminApi.get(`/comments/${parent.get('id')}/`);
|
||||
res.body.comments[0].replies.length.should.eql(4);
|
||||
});
|
||||
|
||||
it('ensure replies are always ordered from oldest to newest', async function () {
|
||||
const post = fixtureManager.get('posts', 1);
|
||||
const {parent} = await dbFns.addCommentWithReplies({
|
||||
|
|
|
@ -447,7 +447,7 @@ describe('Comments API', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('shows hidden and deleted comment where there is a reply', async function () {
|
||||
it('shows hidden and deleted parent comment where there is a reply', async function () {
|
||||
await mockManager.mockLabsEnabled('commentImprovements');
|
||||
await setupBrowseCommentsData();
|
||||
const hiddenComment = await dbFns.addComment({
|
||||
|
@ -504,6 +504,54 @@ describe('Comments API', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('Does not return deleted or hidden replies', async function () {
|
||||
await mockManager.mockLabsEnabled('commentImprovements');
|
||||
const {parent} = await dbFns.addCommentWithReplies({
|
||||
member_id: fixtureManager.get('members', 0).id,
|
||||
replies: [{
|
||||
member_id: fixtureManager.get('members', 1).id,
|
||||
status: 'hidden'
|
||||
}, {
|
||||
member_id: fixtureManager.get('members', 2).id,
|
||||
status: 'deleted'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 3).id,
|
||||
status: 'hidden'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 4).id,
|
||||
status: 'published'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const res = await membersAgent.get(`/api/comments/${parent.get('id')}/`);
|
||||
res.body.comments[0].replies.length.should.eql(1);
|
||||
});
|
||||
|
||||
it('Does return published replies', async function () {
|
||||
await mockManager.mockLabsEnabled('commentImprovements');
|
||||
const {parent} = await dbFns.addCommentWithReplies({
|
||||
member_id: fixtureManager.get('members', 0).id,
|
||||
replies: [{
|
||||
member_id: fixtureManager.get('members', 1).id,
|
||||
status: 'published'
|
||||
}, {
|
||||
member_id: fixtureManager.get('members', 2).id,
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
member_id: fixtureManager.get('members', 3).id,
|
||||
status: 'published'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const res = await membersAgent.get(`/api/comments/${parent.get('id')}/`);
|
||||
res.body.comments[0].replies.length.should.eql(3);
|
||||
});
|
||||
|
||||
it('Returns nothing if both parent and reply are hidden', async function () {
|
||||
await mockManager.mockLabsEnabled('commentImprovements');
|
||||
const hiddenComment = await dbFns.addComment({
|
||||
|
|
Loading…
Add table
Reference in a new issue