From 78da6cf77d42d8ef230a5699ae760cb043915d5b Mon Sep 17 00:00:00 2001 From: Michael Barrett <991592+mike182uk@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:00:45 +0100 Subject: [PATCH] Removed post revision author id on user deletion (#16670) no issue When a user is deleted any post revisions created by the user are set to be owned by nobody (null) rather than deleting the post revisions associated with the user --- ghost/core/core/server/services/users.js | 16 +++++ ghost/post-revisions/lib/post-revisions.js | 31 ++++++++++ ghost/post-revisions/test/hello.test.js | 71 ++++++++++++++++++++++ 3 files changed, 118 insertions(+) diff --git a/ghost/core/core/server/services/users.js b/ghost/core/core/server/services/users.js index 3083c314cd..0b144358cf 100644 --- a/ghost/core/core/server/services/users.js +++ b/ghost/core/core/server/services/users.js @@ -1,6 +1,12 @@ // @ts-check const path = require('path'); +/** + * @TODO: pass these in as dependencies + */ +const PostRevisions = require('@tryghost/post-revisions'); +const labs = require('../../shared/labs'); + /** * @typedef {Object} IdbBackup * @prop {() => Promise} backup @@ -150,6 +156,16 @@ class Users { return this.models.Base.transaction(async (t) => { frameOptions.transacting = t; + if (labs.isSet('postHistory')) { + const postRevisions = new PostRevisions({ + model: this.models.PostRevision + }); + + await postRevisions.removeAuthorFromRevisions(frameOptions.id, { + transacting: frameOptions.transacting + }); + } + await this.assignTagToUserPosts({ id: frameOptions.id, context: frameOptions.context, diff --git a/ghost/post-revisions/lib/post-revisions.js b/ghost/post-revisions/lib/post-revisions.js index b6515bc66e..0e4ece033e 100644 --- a/ghost/post-revisions/lib/post-revisions.js +++ b/ghost/post-revisions/lib/post-revisions.js @@ -21,9 +21,11 @@ class PostRevisions { * @param {object} deps * @param {object} deps.config * @param {number} deps.config.max_revisions + * @param {object} deps.model */ constructor(deps) { this.config = deps.config; + this.model = deps.model; } /** @@ -77,6 +79,35 @@ class PostRevisions { title: input.title }; } + + /** + * @param {string} authorId + * @param {object} options + * @param {object} options.transacting + */ + async removeAuthorFromRevisions(authorId, options) { + const revisions = await this.model.findAll({ + filter: `author_id:${authorId}`, + columns: ['id'], + transacting: options.transacting + }); + + const revisionIds = revisions.toJSON() + .map(({id}) => id); + + if (revisionIds.length === 0) { + return; + } + + await this.model.bulkEdit(revisionIds, 'post_revisions', { + data: { + author_id: null + }, + column: 'id', + transacting: options.transacting, + throwErrors: true + }); + } } module.exports = PostRevisions; diff --git a/ghost/post-revisions/test/hello.test.js b/ghost/post-revisions/test/hello.test.js index ec11bec9cb..3f23107ee7 100644 --- a/ghost/post-revisions/test/hello.test.js +++ b/ghost/post-revisions/test/hello.test.js @@ -1,4 +1,5 @@ const assert = require('assert'); +const sinon = require('sinon'); const PostRevisions = require('../'); const config = { @@ -165,4 +166,74 @@ describe('PostRevisions', function () { assert.equal(actual.length, 2); }); }); + + describe('removeAuthor', function () { + it('removes the provided author from post revisions', async function () { + const authorId = 'abc123'; + const options = { + transacting: {} + }; + const revisions = [ + { + id: 'revision123', + post_id: 'post123', + author_id: 'author123' + }, + { + id: 'revision456', + post_id: 'post123', + author_id: 'author123' + }, + { + id: 'revision789', + post_id: 'post123', + author_id: 'author456' + } + ]; + const modelStub = { + findAll: sinon.stub().resolves({ + toJSON: () => revisions + }), + bulkEdit: sinon.stub().resolves() + }; + const postRevisions = new PostRevisions({ + model: modelStub + }); + + await postRevisions.removeAuthorFromRevisions(authorId, options); + + assert.equal(modelStub.bulkEdit.calledOnce, true); + + const bulkEditArgs = modelStub.bulkEdit.getCall(0).args; + + assert.deepEqual(bulkEditArgs[0], ['revision123', 'revision456', 'revision789']); + assert.equal(bulkEditArgs[1], 'post_revisions'); + assert.deepEqual(bulkEditArgs[2], { + data: { + author_id: null + }, + column: 'id', + transacting: options.transacting, + throwErrors: true + }); + }); + + it('does nothing if there are no post revisions by the provided author', async function () { + const modelStub = { + findAll: sinon.stub().resolves({ + toJSON: () => [] + }), + bulkEdit: sinon.stub().resolves() + }; + const postRevisions = new PostRevisions({ + model: modelStub + }); + + await postRevisions.removeAuthorFromRevisions('abc123', { + transacting: {} + }); + + assert.equal(modelStub.bulkEdit.calledOnce, false); + }); + }); });