0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Added default comment relations

refs https://github.com/TryGhost/Team/issues/1664
This commit is contained in:
Simon Backx 2022-07-06 16:44:20 +02:00 committed by Simon Backx
parent ef989ed55c
commit 54e7a6cec3
6 changed files with 46 additions and 7 deletions

View file

@ -2,7 +2,7 @@ const Promise = require('bluebird');
const tpl = require('@tryghost/tpl'); const tpl = require('@tryghost/tpl');
const errors = require('@tryghost/errors'); const errors = require('@tryghost/errors');
const models = require('../../models'); const models = require('../../models');
const ALLOWED_INCLUDES = ['post', 'member']; const ALLOWED_INCLUDES = ['post', 'member', 'likes'];
const UNSAFE_ATTRS = ['status']; const UNSAFE_ATTRS = ['status'];
const messages = { const messages = {

View file

@ -26,5 +26,14 @@ module.exports = (model, frame) => {
response.member = null; response.member = null;
} }
if (jsonModel.likes) {
response.likes_count = jsonModel.likes.length;
} else {
response.likes_count = 0;
}
// todo
response.liked = false;
return response; return response;
}; };

View file

@ -31,6 +31,10 @@ const Comment = ghostBookshelf.Model.extend({
return this.belongsTo('Comment', 'parent_id'); return this.belongsTo('Comment', 'parent_id');
}, },
likes() {
return this.hasMany('CommentLike', 'comment_id');
},
emitChange: function emitChange(event, options) { emitChange: function emitChange(event, options) {
const eventToTrigger = 'comment' + '.' + event; const eventToTrigger = 'comment' + '.' + event;
ghostBookshelf.Model.prototype.emitChange.bind(this)(this, eventToTrigger, options); ghostBookshelf.Model.prototype.emitChange.bind(this)(this, eventToTrigger, options);
@ -100,6 +104,21 @@ const Comment = ghostBookshelf.Model.extend({
} }
return hasMemberPermission; return hasMemberPermission;
},
/**
* We have to ensure consistency. If you listen on model events (e.g. `member.added`), you can expect that you always
* receive all fields including relations. Otherwise you can't rely on a consistent flow. And we want to avoid
* that event listeners have to re-fetch a resource. This function is used in the context of inserting
* and updating resources. We won't return the relations by default for now.
*/
defaultRelations: function defaultRelations(methodName, options) {
// @todo: the default relations are not working for 'add' when we add it below
if (['findAll', 'findPage', 'edit'].indexOf(methodName) !== -1) {
options.withRelated = _.union(['member', 'likes'], options.withRelated || []);
}
return options;
} }
}); });

View file

@ -8,6 +8,8 @@ Object {
"edited_at": null, "edited_at": null,
"html": "<p>First.</p>", "html": "<p>First.</p>",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"liked": Any<Boolean>,
"likes_count": Any<Number>,
"member": Object { "member": Object {
"avatar_image": null, "avatar_image": null,
"bio": null, "bio": null,
@ -21,6 +23,8 @@ Object {
"edited_at": null, "edited_at": null,
"html": "<p>Really original</p>", "html": "<p>Really original</p>",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"liked": Any<Boolean>,
"likes_count": Any<Number>,
"member": Object { "member": Object {
"avatar_image": null, "avatar_image": null,
"bio": null, "bio": null,
@ -34,6 +38,8 @@ Object {
"edited_at": null, "edited_at": null,
"html": "This is a message", "html": "This is a message",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"liked": Any<Boolean>,
"likes_count": Any<Number>,
"member": Object { "member": Object {
"avatar_image": null, "avatar_image": null,
"bio": null, "bio": null,
@ -60,7 +66,7 @@ exports[`Comments API when authenticated Can browse all comments of a post 2: [h
Object { Object {
"access-control-allow-origin": "*", "access-control-allow-origin": "*",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "782", "content-length": "872",
"content-type": "application/json; charset=utf-8", "content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Encoding", "vary": "Accept-Encoding",
@ -76,6 +82,8 @@ Object {
"edited_at": null, "edited_at": null,
"html": "This is a message", "html": "This is a message",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"liked": false,
"likes_count": 0,
"member": null, "member": null,
"status": "published", "status": "published",
}, },
@ -87,7 +95,7 @@ exports[`Comments API when authenticated Can comment on a post 2: [headers] 1`]
Object { Object {
"access-control-allow-origin": "*", "access-control-allow-origin": "*",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "167", "content-length": "197",
"content-type": "application/json; charset=utf-8", "content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/comments\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,

View file

@ -1,5 +1,5 @@
const {agentProvider, mockManager, fixtureManager, matchers} = require('../../utils/e2e-framework'); const {agentProvider, mockManager, fixtureManager, matchers} = require('../../utils/e2e-framework');
const {anyEtag, anyObjectId, anyLocationFor, anyISODateTime, anyUuid} = matchers; const {anyEtag, anyObjectId, anyLocationFor, anyISODateTime, anyUuid, anyNumber, anyBoolean} = matchers;
let membersAgent, membersService, postId, commentId; let membersAgent, membersService, postId, commentId;
@ -13,7 +13,9 @@ const commentMatcherWithMember = {
created_at: anyISODateTime, created_at: anyISODateTime,
member: { member: {
id: anyObjectId id: anyObjectId
} },
likes_count: anyNumber,
liked: anyBoolean
}; };
describe('Comments API', function () { describe('Comments API', function () {
@ -58,8 +60,8 @@ describe('Comments API', function () {
}); });
it('Can browse all comments of a post', async function () { it('Can browse all comments of a post', async function () {
await membersAgent const {body} = await membersAgent
.get(`/api/comments/?filter=post_id:${postId}&include=member`) .get(`/api/comments/?filter=post_id:${postId}`)
.expectStatus(200) .expectStatus(200)
.matchHeaderSnapshot({ .matchHeaderSnapshot({
etag: anyEtag etag: anyEtag

View file

@ -313,6 +313,7 @@ module.exports = {
} }
}, },
matchers: { matchers: {
anyBoolean: any(Boolean),
anyString: any(String), anyString: any(String),
anyArray: any(Array), anyArray: any(Array),
anyNumber: any(Number), anyNumber: any(Number),