0
Fork 0
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:
Hannah Wolfe 2022-07-05 16:55:40 +02:00 committed by Simon Backx
parent d4c8660323
commit 78c15933e6
2 changed files with 122 additions and 3 deletions

View file

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

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