Skip to content

Commit

Permalink
Added new endpoint for loading replies as Admin (#21676)
Browse files Browse the repository at this point in the history
ref PLG-227

- Wired up a new endpoint that would be able to paginate replies as an
admin user.
- The difference compared to the members-api endpoint is that this
includes hidden comments and includes the html string which is normally
hidden from non-admin users
  • Loading branch information
ronaldlangeveld authored Nov 21, 2024
1 parent f0dab9d commit d800587
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 3 deletions.
36 changes: 36 additions & 0 deletions ghost/core/core/server/api/endpoints/comment-replies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// This is a new endpoint for the admin API to return replies to a comment with pagination

const commentsService = require('../../services/comments');

/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'comments',
browse: {
headers: {
cacheInvalidate: false
},
options: [
'include',
'page',
'limit',
'fields',
'filter',
'order',
'debug',
'id'
],
validation: {
options: {
id: {
required: true
}
}
},
permissions: true,
query(frame) {
return commentsService.controller.adminReplies(frame);
}
}
};

module.exports = controller;
1 change: 0 additions & 1 deletion ghost/core/core/server/api/endpoints/comments.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const models = require('../../models');
const commentsService = require('../../services/comments');

function handleCacheHeaders(model, frame) {
if (model) {
const postId = model.get('post_id');
Expand Down
4 changes: 4 additions & 0 deletions ghost/core/core/server/api/endpoints/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ module.exports = {
return apiFramework.pipeline(require('./comments'), localUtils);
},

get commentReplies() {
return apiFramework.pipeline(require('./comment-replies'), localUtils);
},

get links() {
return apiFramework.pipeline(require('./links'), localUtils);
},
Expand Down
3 changes: 1 addition & 2 deletions ghost/core/core/server/models/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,7 @@ const Comment = ghostBookshelf.Model.extend({
*/
permittedOptions: function permittedOptions(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 and isAdmin option
options.push('parentId');
options.push('isAdmin');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ module.exports = class CommentsController {
return this.service.getReplies(frame.options.id, _.omit(frame.options, 'id'));
}

/**
* @param {Frame} frame
*/
async adminReplies(frame) {
frame.options.isAdmin = true;
return this.service.getReplies(frame.options.id, _.omit(frame.options, 'id'));
}

/**
* @param {Frame} frame
*/
Expand Down
1 change: 1 addition & 0 deletions ghost/core/core/server/web/api/endpoints/admin/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module.exports = function apiRoutes() {

router.get('/mentions', mw.authAdminApi, http(api.mentions.browse));

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));

Expand Down
187 changes: 187 additions & 0 deletions ghost/core/test/e2e-api/admin/comments.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,5 +268,192 @@ describe('Admin Comments API', function () {
const item = res.body.comments.find(cmt => parent.id === cmt.id);
assert.equal(item.count.replies, 2);
});

it('can load additional replies as an admin', async function () {
const post = fixtureManager.get('posts', 1);
const {parent} = await dbFns.addCommentWithReplies({
member_id: fixtureManager.get('members', 0).id,
post_id: post.id,
html: 'Comment 1',
status: 'published',
replies: [
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 1',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 2',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 3',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 4',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 5',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 6',
status: 'published'
}
]
});

const res = await adminApi.get('/comments/post/' + post.id + '/');
const item = res.body.comments.find(cmt => parent.id === cmt.id);
const lastReply = item.replies[item.replies.length - 1];
const filter = encodeURIComponent(`id:>'${lastReply.id}'`);
const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`);
assert.equal(res2.body.comments.length, 3);
});

it('can load additional replies and includes hidden replies as an admin', async function () {
const post = fixtureManager.get('posts', 1);
const {parent} = await dbFns.addCommentWithReplies({
member_id: fixtureManager.get('members', 0).id,
post_id: post.id,
html: 'Comment 1',
status: 'published',
replies: [
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 1',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 2',
status: 'hidden'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 3',
status: 'hidden'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 4',
status: 'hidden'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 5',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 6',
status: 'published'
}
]
});

const res = await adminApi.get('/comments/post/' + post.id + '/');
const item = res.body.comments.find(cmt => parent.id === cmt.id);
const lastReply = item.replies[item.replies.length - 1];
const filter = encodeURIComponent(`id:>'${lastReply.id}'`);
const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`);
assert.equal(res2.body.comments.length, 3);
});

it('does not return deleted replies as an admin', async function () {
const post = fixtureManager.get('posts', 1);
const {parent} = await dbFns.addCommentWithReplies({
member_id: fixtureManager.get('members', 0).id,
post_id: post.id,
html: 'Comment 1',
status: 'published',
replies: [
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 1',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 2',
status: 'hidden'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 3',
status: 'hidden'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 4',
status: 'hidden'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 5',
status: 'deleted'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 6',
status: 'deleted'
}
]
});

const res = await adminApi.get('/comments/post/' + post.id + '/');
const item = res.body.comments.find(cmt => parent.id === cmt.id);
const lastReply = item.replies[item.replies.length - 1];
const filter = encodeURIComponent(`id:>'${lastReply.id}'`);
const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`);
assert.equal(res2.body.comments.length, 1);
});

it('includes html string of replies as an admin', async function () {
const post = fixtureManager.get('posts', 1);
const {parent} = await dbFns.addCommentWithReplies({
member_id: fixtureManager.get('members', 0).id,
post_id: post.id,
html: 'Comment 1',
status: 'published',
replies: [
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 1',
status: 'published'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 2',
status: 'hidden'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 3',
status: 'hidden'
},
{
member_id: fixtureManager.get('members', 0).id,
html: 'Reply 4',
status: 'hidden'
}
]
});

const res = await adminApi.get('/comments/post/' + post.id + '/');
const item = res.body.comments.find(cmt => parent.id === cmt.id);
const lastReply = item.replies[item.replies.length - 1];
const filter = encodeURIComponent(`id:>'${lastReply.id}'`);
const res2 = await adminApi.get(`/comments/${parent.id}/replies?limit=5&filter=${filter}`);
assert.equal(res2.body.comments.length, 1);
assert.equal(res2.body.comments[0].html, 'Reply 4');
});
});
});

0 comments on commit d800587

Please sign in to comment.