0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Added automatic collection recalculation

closes https://github.com/TryGhost/Team/issues/3170

- When resources that are related to automatic collection filter are updated the posts in collections should be updated as well.
- This change adds a super-basic way to track changes in post/tag/author resources and updated all automatic collections when any of those resources change. In the future we can optimize the update process to be more performant, but it's good enough for current needs
This commit is contained in:
Naz 2023-06-05 18:33:04 +07:00
parent 4d3c7d3177
commit 2390afc6f1
No known key found for this signature in database
5 changed files with 82 additions and 10 deletions

View file

@ -6,7 +6,8 @@ export class CollectionsRepositoryInMemory extends InMemoryRepository<string, Co
return {
title: entity.title,
description: entity.description,
feature_image: entity.featureImage
feature_image: entity.featureImage,
type: entity.type
};
}
}

View file

@ -139,6 +139,33 @@ export class CollectionsService {
return this.toDTO(collection);
}
async #updateAutomaticCollectionItems(collection: Collection, filter?:string) {
const collectionFilter = filter || collection.filter;
if (collectionFilter) {
const posts = await this.postsRepository.getAll({
filter: collectionFilter
});
collection.removeAllPosts();
for (const post of posts) {
collection.addPost(post);
}
}
}
async updateAutomaticCollections() {
const collections = await this.collectionsRepository.getAll({
filter: 'type:automatic'
});
for (const collection of collections) {
await this.#updateAutomaticCollectionItems(collection);
await this.collectionsRepository.save(collection);
}
}
async edit(data: any): Promise<CollectionDTO | null> {
const collection = await this.collectionsRepository.getById(data.id);
@ -153,15 +180,7 @@ export class CollectionsService {
}
if ((collection.type === 'automatic' || data.type === 'automatic') && data.filter) {
const posts = await this.postsRepository.getAll({
filter: data.filter
});
collection.removeAllPosts();
for (const post of posts) {
collection.addPost(post);
}
await this.#updateAutomaticCollectionItems(collection, data.filter);
}
const collectionData = this.fromDTO(data);

View file

@ -225,5 +225,30 @@ describe('CollectionsService', function () {
assert.equal(updatedCollection?.posts.length, 1, 'Collection should have one post');
assert.equal(updatedCollection?.posts[0].id, 'post-2', 'Collection should have the correct post');
});
// @NOTE: add a more comprehensive test as this one is too basic
it('Updates all automatic collections', async function () {
let collection1 = await collectionsService.createCollection({
title: 'Featured Collection 1',
description: 'testing automatic collection',
type: 'automatic',
filter: 'featured:true'
});
let collection2 = await collectionsService.createCollection({
title: 'Featured Collection 2',
description: 'testing automatic collection',
type: 'automatic',
filter: 'featured:true'
});
assert.equal(collection1.posts.length, 2);
assert.equal(collection2.posts.length, 2);
await collectionsService.updateAutomaticCollections();
assert.equal(collection1.posts.length, 2);
assert.equal(collection2.posts.length, 2);
});
});
});

View file

@ -8,6 +8,7 @@ class CollectionsServiceWrapper {
constructor() {
const models = require('../../models');
const events = require('../../lib/common/events');
const collectionsRepositoryInMemory = new CollectionsRepositoryInMemory();
const collectionsService = new CollectionsService({
@ -22,6 +23,17 @@ class CollectionsServiceWrapper {
}
});
// @NOTE: these should be reworked to use the "Event" classes
// instead of Bookshelf model events
const updateEvents = require('./update-events');
// @NOTE: naive update implementation to keep things simple for the first version
for (const event of updateEvents) {
events.on(event, () => {
collectionsService.updateAutomaticCollections();
});
}
this.api = {
browse: collectionsService.getAll.bind(collectionsService),
read: collectionsService.getById.bind(collectionsService),

View file

@ -0,0 +1,15 @@
module.exports = [
'post.published',
'post.published.edited',
'post.unpublished',
'tag.added',
'tag.edited',
'tag.attached',
'tag.detached',
'tag.deleted',
'user.activated',
'user.activated.edited',
'user.attached',
'user.detached',
'user.deleted'
];