mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Implemented soft delete for comments
refs https://github.com/TryGhost/Team/issues/1664 - comments are marked as deleted, rather than deleted completely
This commit is contained in:
parent
d4c8660323
commit
78c15933e6
2 changed files with 122 additions and 3 deletions
|
@ -5,7 +5,8 @@ const tpl = require('@tryghost/tpl');
|
|||
|
||||
const messages = {
|
||||
commentNotFound: 'Comment could not be found',
|
||||
notYourComment: 'You may only edit your own comments'
|
||||
notYourCommentToEdit: 'You may only edit your own comments',
|
||||
notYourCommentToDestroy: 'You may only delete your own comments'
|
||||
};
|
||||
|
||||
const Comment = ghostBookshelf.Model.extend({
|
||||
|
@ -40,6 +41,23 @@ const Comment = ghostBookshelf.Model.extend({
|
|||
model.emitChange('added', options);
|
||||
}
|
||||
}, {
|
||||
destroy: function destroy(unfilteredOptions) {
|
||||
let options = this.filterOptions(unfilteredOptions, 'destroy', {extraAllowedProperties: ['id']});
|
||||
|
||||
const softDelete = () => {
|
||||
return ghostBookshelf.Model.edit.call(this, {status: 'deleted'}, options);
|
||||
};
|
||||
|
||||
if (!options.transacting) {
|
||||
return ghostBookshelf.transaction((transacting) => {
|
||||
options.transacting = transacting;
|
||||
return softDelete();
|
||||
});
|
||||
}
|
||||
|
||||
return softDelete();
|
||||
},
|
||||
|
||||
async permissible(commentModelOrId, action, context, unsafeAttrs, loadedPermissions, hasUserPermission, hasApiKeyPermission, hasMemberPermission) {
|
||||
const self = this;
|
||||
|
||||
|
@ -64,9 +82,15 @@ const Comment = ghostBookshelf.Model.extend({
|
|||
});
|
||||
}
|
||||
|
||||
if ((action === 'edit' || action === 'destroy') && commentModelOrId.get('member_id') !== context.member.id) {
|
||||
if (action === 'edit' && commentModelOrId.get('member_id') !== context.member.id) {
|
||||
return Promise.reject(new errors.NoPermissionError({
|
||||
message: tpl(messages.notYourComment)
|
||||
message: tpl(messages.notYourCommentToEdit)
|
||||
}));
|
||||
}
|
||||
|
||||
if (action === 'destroy' && commentModelOrId.get('member_id') !== context.member.id) {
|
||||
return Promise.reject(new errors.NoPermissionError({
|
||||
message: tpl(messages.notYourCommentToDestroy)
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
95
test/unit/server/models/comment.test.js
Normal file
95
test/unit/server/models/comment.test.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
const sinon = require('sinon');
|
||||
const models = require('../../../../core/server/models');
|
||||
const testUtils = require('../../../utils');
|
||||
|
||||
describe('Unit: models/comment', function () {
|
||||
before(function () {
|
||||
models.init();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('permissible', function () {
|
||||
function getCommentModel(id, memberId) {
|
||||
const obj = {
|
||||
id: id,
|
||||
member_id: memberId
|
||||
};
|
||||
|
||||
return {
|
||||
id: obj.id,
|
||||
get: sinon.stub().callsFake((prop) => {
|
||||
return obj[prop];
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
it('user can do all', async function () {
|
||||
const comment = getCommentModel(1, 'member_123');
|
||||
const context = {user: 1};
|
||||
|
||||
const response = await models.Comment.permissible(comment, 'destroy', context, {}, testUtils.permissions.owner, true, true, true);
|
||||
response.should.eql(true);
|
||||
});
|
||||
|
||||
it('can only edit own comments', async function () {
|
||||
const comment = getCommentModel(1, 'member_123');
|
||||
const context = {
|
||||
member: {
|
||||
id: 'other_member'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await models.Comment.permissible(comment, 'edit', context, {}, null, false, true, true);
|
||||
response.should.eql(true);
|
||||
} catch (err) {
|
||||
err.message.should.eql('You may only edit your own comments');
|
||||
return;
|
||||
}
|
||||
throw new Error('Should throw');
|
||||
});
|
||||
|
||||
it('can edit own comments', async function () {
|
||||
const comment = getCommentModel(1, 'member_123');
|
||||
const context = {
|
||||
member: {
|
||||
id: 'member_123'
|
||||
}
|
||||
};
|
||||
|
||||
await models.Comment.permissible(comment, 'edit', context, {}, null, false, true, true);
|
||||
});
|
||||
|
||||
it('can only destroy own comments', async function () {
|
||||
const comment = getCommentModel(1, 'member_123');
|
||||
const context = {
|
||||
member: {
|
||||
id: 'other_member'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await models.Comment.permissible(comment, 'destroy', context, {}, null, false, true, true);
|
||||
response.should.eql(true);
|
||||
} catch (err) {
|
||||
err.message.should.eql('You may only delete your own comments');
|
||||
return;
|
||||
}
|
||||
throw new Error('Should throw');
|
||||
});
|
||||
|
||||
it('can edit destroy comments', async function () {
|
||||
const comment = getCommentModel(1, 'member_123');
|
||||
const context = {
|
||||
member: {
|
||||
id: 'member_123'
|
||||
}
|
||||
};
|
||||
|
||||
await models.Comment.permissible(comment, 'destroy', context, {}, null, false, true, true);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue