mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Fixed collection cards not re-rendering when posts were bulk-edited
no issue - bulk edit actions bypass the Bookshelf model hooks which meant our page reset behaviour in `onSaving` and `onDestroyed` was not being hit - added overrides to `bulkEdit` and `bulkDestroy` to add the same page-reset behaviour any time we have a bulk edit or destroy
This commit is contained in:
parent
6e46e8b5ba
commit
d541991046
2 changed files with 78 additions and 2 deletions
|
@ -1367,6 +1367,24 @@ Post = ghostBookshelf.Model.extend({
|
||||||
return editPost();
|
return editPost();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
bulkEdit: async function bulkEdit(ids, tableName, options) {
|
||||||
|
if (tableName === this.prototype.tableName) {
|
||||||
|
const result = await ghostBookshelf.Model.bulkEdit.call(this, ids, tableName, options);
|
||||||
|
|
||||||
|
if (labs.isSet('collectionsCard')) {
|
||||||
|
// reset all page HTML so collection cards can be re-rendered with updated posts
|
||||||
|
// NOTE: we can't check for only published edits here as we don't have access to previous values
|
||||||
|
// to see if a previously published post has been unpublished, so we just reset all pages
|
||||||
|
const pageResetQuery = ghostBookshelf.knex.raw('UPDATE posts set html = NULL WHERE type = "page" AND lexical IS NOT NULL');
|
||||||
|
await (options.transacting ? pageResetQuery.transacting(options.transacting) : pageResetQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return ghostBookshelf.Model.bulkEdit.call(this, ids, tableName, options);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ### Add
|
* ### Add
|
||||||
* @extends ghostBookshelf.Model.add to handle returning the full object
|
* @extends ghostBookshelf.Model.add to handle returning the full object
|
||||||
|
@ -1413,6 +1431,34 @@ Post = ghostBookshelf.Model.extend({
|
||||||
return destroyPost();
|
return destroyPost();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
bulkDestroy: async function bulkDestroy(ids, tableName, options) {
|
||||||
|
if (tableName === this.prototype.tableName) {
|
||||||
|
if (labs.isSet('collectionsCard')) {
|
||||||
|
// get count of published posts to be destroyed before they no longer exist to count
|
||||||
|
const deletedPublishedCount = await this.query((qb) => {
|
||||||
|
qb.where('type', 'post')
|
||||||
|
.where('status', 'published')
|
||||||
|
.whereIn('id', ids);
|
||||||
|
}).count({transacting: options.transacting});
|
||||||
|
|
||||||
|
const result = await ghostBookshelf.Model.bulkDestroy.call(this, ids, tableName, options);
|
||||||
|
|
||||||
|
// if we've deleted any published posts, we need to reset the html for all pages so dynamic collection
|
||||||
|
// card content can be re-rendered
|
||||||
|
if (deletedPublishedCount > 0) {
|
||||||
|
const pageResetQuery = ghostBookshelf.knex.raw('UPDATE posts set html = NULL WHERE type = "page" AND lexical IS NOT NULL');
|
||||||
|
await (options.transacting ? pageResetQuery.transacting(options.transacting) : pageResetQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return ghostBookshelf.Model.bulkDestroy.call(this, ids, tableName, options);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ghostBookshelf.Model.bulkDestroy.call(this, ids, tableName, options);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// NOTE: the `authors` extension is the parent of the post model. It also has a permissible function.
|
// NOTE: the `authors` extension is the parent of the post model. It also has a permissible function.
|
||||||
permissible: async function permissible(postModel, action, context, unsafeAttrs, loadedPermissions, hasUserPermission, hasApiKeyPermission) {
|
permissible: async function permissible(postModel, action, context, unsafeAttrs, loadedPermissions, hasUserPermission, hasApiKeyPermission) {
|
||||||
let isContributor;
|
let isContributor;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
const should = require('should');
|
||||||
const DomainEvents = require('@tryghost/domain-events');
|
const DomainEvents = require('@tryghost/domain-events');
|
||||||
|
const {mobiledocToLexical} = require('@tryghost/kg-converters');
|
||||||
const {agentProvider, fixtureManager, mockManager} = require('../../utils/e2e-framework');
|
const {agentProvider, fixtureManager, mockManager} = require('../../utils/e2e-framework');
|
||||||
const models = require('../../../core/server/models');
|
const models = require('../../../core/server/models');
|
||||||
const assert = require('assert/strict');
|
const assert = require('assert/strict');
|
||||||
|
@ -8,15 +10,26 @@ describe('Posts Bulk API', function () {
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
mockManager.mockLabsEnabled('collections');
|
mockManager.mockLabsEnabled('collections');
|
||||||
|
mockManager.mockLabsEnabled('collectionsCard');
|
||||||
|
|
||||||
agent = await agentProvider.getAdminAPIAgent();
|
agent = await agentProvider.getAdminAPIAgent();
|
||||||
|
|
||||||
// Note that we generate lots of fixtures here to test the bulk deletion correctly
|
// Note that we generate lots of fixtures here to test the bulk deletion correctly
|
||||||
await fixtureManager.init('posts', 'newsletters', 'members:newsletters', 'emails', 'redirects', 'clicks', 'comments', 'feedback', 'links', 'mentions');
|
await fixtureManager.init('posts', 'newsletters', 'members:newsletters', 'emails', 'redirects', 'clicks', 'comments', 'feedback', 'links', 'mentions');
|
||||||
await agent.loginAsOwner();
|
await agent.loginAsOwner();
|
||||||
|
|
||||||
|
// convert inserted pages to lexical so we can test page.html reset/re-render
|
||||||
|
const pages = await models.Post.where('type', 'page').fetchAll();
|
||||||
|
for (const page of pages) {
|
||||||
|
const lexical = mobiledocToLexical(page.get('mobiledoc'));
|
||||||
|
await models.Base.knex.raw('UPDATE posts SET mobiledoc=NULL, lexical=? where id=?', [lexical, page.id]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(async function () {
|
||||||
|
// give pages some HTML back to alleviate test interdependence when pages are reset on create/update/delete
|
||||||
|
await models.Base.knex.raw('UPDATE posts SET html = "<p>Testing</p>" WHERE type = \'page\' AND html IS NULL');
|
||||||
|
|
||||||
mockManager.restore();
|
mockManager.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -48,6 +61,13 @@ describe('Posts Bulk API', function () {
|
||||||
|
|
||||||
assert.equal(response.body.bulk.meta.stats.successful, amount, `Expect all matching posts (${amount}) to be changed`);
|
assert.equal(response.body.bulk.meta.stats.successful, amount, `Expect all matching posts (${amount}) to be changed`);
|
||||||
|
|
||||||
|
// Check page HTML was reset to enable re-render of collection cards
|
||||||
|
// Must be done before fetch all posts otherwise they will be re-rendered
|
||||||
|
const totalPageCount = await models.Post.where({type: 'page'}).count();
|
||||||
|
const emptyPageCount = await models.Post.where({html: null, type: 'page'}).count();
|
||||||
|
should.exist(emptyPageCount);
|
||||||
|
emptyPageCount.should.equal(totalPageCount, 'no. of render-queued pages after bulk edit');
|
||||||
|
|
||||||
// Fetch all posts and check if they are featured
|
// Fetch all posts and check if they are featured
|
||||||
const posts = await models.Post.findAll({filter, status: 'all'});
|
const posts = await models.Post.findAll({filter, status: 'all'});
|
||||||
assert.equal(posts.length, amount, `Expect all matching posts (${amount}) to be changed`);
|
assert.equal(posts.length, amount, `Expect all matching posts (${amount}) to be changed`);
|
||||||
|
@ -281,7 +301,7 @@ describe('Posts Bulk API', function () {
|
||||||
|
|
||||||
it('Can unpublish posts', async function () {
|
it('Can unpublish posts', async function () {
|
||||||
const filter = 'status:[published]';
|
const filter = 'status:[published]';
|
||||||
const changedPosts = await models.Post.findPage({filter, limit: 1, status: 'all'});
|
const changedPosts = await models.Post.findPage({filter, status: 'published'});
|
||||||
const amount = changedPosts.meta.pagination.total;
|
const amount = changedPosts.meta.pagination.total;
|
||||||
|
|
||||||
assert(amount > 0, 'Expect at least one post to be affected for this test to work');
|
assert(amount > 0, 'Expect at least one post to be affected for this test to work');
|
||||||
|
@ -301,6 +321,10 @@ describe('Posts Bulk API', function () {
|
||||||
// Fetch all posts and check if they are unpublished
|
// Fetch all posts and check if they are unpublished
|
||||||
const posts = await models.Post.findAll({filter, status: 'all'});
|
const posts = await models.Post.findAll({filter, status: 'all'});
|
||||||
assert.equal(posts.length, 0, `Expect all matching posts (${amount}) to be unpublished`);
|
assert.equal(posts.length, 0, `Expect all matching posts (${amount}) to be unpublished`);
|
||||||
|
|
||||||
|
// Re-publish the posts so we don't affect later tests
|
||||||
|
const postIds = changedPosts.data.map(post => post.id);
|
||||||
|
await models.Base.knex.raw(`UPDATE posts SET status = \'published\' WHERE id IN (${postIds.map(() => '?').join(',')})`, [...postIds]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -332,6 +356,12 @@ describe('Posts Bulk API', function () {
|
||||||
// Check if all posts were deleted
|
// Check if all posts were deleted
|
||||||
const posts = await models.Post.findPage({filter, status: 'all'});
|
const posts = await models.Post.findPage({filter, status: 'all'});
|
||||||
assert.equal(posts.meta.pagination.total, 0, `Expect all matching posts (${amount}) to be deleted`);
|
assert.equal(posts.meta.pagination.total, 0, `Expect all matching posts (${amount}) to be deleted`);
|
||||||
|
|
||||||
|
// Check page HTML was reset to enable re-render of collection cards
|
||||||
|
const totalPageCount = await models.Post.where({type: 'page'}).count();
|
||||||
|
const emptyPageCount = await models.Post.where({html: null, type: 'page'}).count();
|
||||||
|
should.exist(emptyPageCount);
|
||||||
|
emptyPageCount.should.equal(totalPageCount, 'no. of render-queued pages after bulk delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Can delete all posts', async function () {
|
it('Can delete all posts', async function () {
|
||||||
|
|
Loading…
Add table
Reference in a new issue