mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 22:11:09 +03:00
Added collections handling for PostsBulkUnpublishedEvent
refs https://github.com/TryGhost/Arch/issues/16 - When posts produce PostsBulkUnpublishedEvent the collections having a published_at filter should update the posts belonging to them
This commit is contained in:
parent
8c05d80b99
commit
8046c33194
@ -1,5 +1,9 @@
|
|||||||
import logging from '@tryghost/logging';
|
import logging from '@tryghost/logging';
|
||||||
import tpl from '@tryghost/tpl';
|
import tpl from '@tryghost/tpl';
|
||||||
|
import {Knex} from "knex";
|
||||||
|
import {
|
||||||
|
PostsBulkUnpublishedEvent,
|
||||||
|
} from "@tryghost/post-events";
|
||||||
import {Collection} from './Collection';
|
import {Collection} from './Collection';
|
||||||
import {CollectionRepository} from './CollectionRepository';
|
import {CollectionRepository} from './CollectionRepository';
|
||||||
import {CollectionPost} from './CollectionPost';
|
import {CollectionPost} from './CollectionPost';
|
||||||
@ -183,6 +187,11 @@ export class CollectionsService {
|
|||||||
await this.removePostsFromAllCollections(event.data);
|
await this.removePostsFromAllCollections(event.data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.DomainEvents.subscribe(PostsBulkUnpublishedEvent, async (event: PostsBulkUnpublishedEvent) => {
|
||||||
|
logging.info(`PostsBulkUnpublishedEvent received, updating collection posts ${event.data}`);
|
||||||
|
await this.updateUnpublishedPosts(event.data);
|
||||||
|
});
|
||||||
|
|
||||||
this.DomainEvents.subscribe(TagDeletedEvent, async (event: TagDeletedEvent) => {
|
this.DomainEvents.subscribe(TagDeletedEvent, async (event: TagDeletedEvent) => {
|
||||||
logging.info(`TagDeletedEvent received for ${event.data.id}, updating all collections`);
|
logging.info(`TagDeletedEvent received for ${event.data.id}, updating all collections`);
|
||||||
await this.updateAllAutomaticCollections();
|
await this.updateAllAutomaticCollections();
|
||||||
@ -334,6 +343,43 @@ export class CollectionsService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateUnpublishedPosts(postIds: string[]) {
|
||||||
|
return await this.collectionsRepository.createTransaction(async (transaction) => {
|
||||||
|
let collections = await this.collectionsRepository.getAll({
|
||||||
|
filter: 'type:automatic+slug:-latest+slug:-featured',
|
||||||
|
transaction
|
||||||
|
});
|
||||||
|
|
||||||
|
// only process collections that have a filter that includes published_at
|
||||||
|
collections = collections.filter((collection) => collection.filter?.includes('published_at'));
|
||||||
|
|
||||||
|
if (!collections.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updatePostsInCollections(postIds, collections, transaction);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePostsInCollections(postIds: string[], collections: Collection[], transaction: Knex.Transaction) {
|
||||||
|
const posts = await this.postsRepository.getBulk(postIds, transaction);
|
||||||
|
|
||||||
|
|
||||||
|
for (const collection of collections) {
|
||||||
|
for (const post of posts) {
|
||||||
|
if (collection.includesPost(post.id) && !collection.postMatchesFilter(post)) {
|
||||||
|
collection.removePost(post.id);
|
||||||
|
logging.info(`[Collections] Post ${post.id} was updated and removed from collection ${collection.id} with filter ${collection.filter}`);
|
||||||
|
} else if (!collection.includesPost(post.id) && collection.postMatchesFilter(post)) {
|
||||||
|
await collection.addPost(post);
|
||||||
|
logging.info(`[Collections] Post ${post.id} was unpublished and added to collection ${collection.id} with filter ${collection.filter}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.collectionsRepository.save(collection, {transaction});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
async edit(data: any): Promise<CollectionDTO | null> {
|
async edit(data: any): Promise<CollectionDTO | null> {
|
||||||
return await this.collectionsRepository.createTransaction(async (transaction) => {
|
return await this.collectionsRepository.createTransaction(async (transaction) => {
|
||||||
|
@ -8,7 +8,10 @@ import {
|
|||||||
PostEditedEvent,
|
PostEditedEvent,
|
||||||
TagDeletedEvent
|
TagDeletedEvent
|
||||||
} from '../src/index';
|
} from '../src/index';
|
||||||
import {PostsBulkDestroyedEvent} from '@tryghost/post-events';
|
import {
|
||||||
|
PostsBulkDestroyedEvent,
|
||||||
|
PostsBulkUnpublishedEvent
|
||||||
|
} from '@tryghost/post-events';
|
||||||
import {PostsRepositoryInMemory} from './fixtures/PostsRepositoryInMemory';
|
import {PostsRepositoryInMemory} from './fixtures/PostsRepositoryInMemory';
|
||||||
import {posts as postFixtures} from './fixtures/posts';
|
import {posts as postFixtures} from './fixtures/posts';
|
||||||
import {CollectionPost} from '../src/CollectionPost';
|
import {CollectionPost} from '../src/CollectionPost';
|
||||||
@ -22,7 +25,7 @@ const initPostsRepository = (posts: any): PostsRepositoryInMemory => {
|
|||||||
title: post.title,
|
title: post.title,
|
||||||
slug: post.slug,
|
slug: post.slug,
|
||||||
featured: post.featured,
|
featured: post.featured,
|
||||||
published_at: post.published_at,
|
published_at: post.published_at?.toISOString(),
|
||||||
tags: post.tags,
|
tags: post.tags,
|
||||||
deleted: false
|
deleted: false
|
||||||
};
|
};
|
||||||
@ -411,8 +414,8 @@ describe('CollectionsService', function () {
|
|||||||
|
|
||||||
collectionsService.subscribeToEvents();
|
collectionsService.subscribeToEvents();
|
||||||
const postDeletedEvent = PostsBulkDestroyedEvent.create([
|
const postDeletedEvent = PostsBulkDestroyedEvent.create([
|
||||||
posts[0].id,
|
postFixtures[0].id,
|
||||||
posts[1].id
|
postFixtures[1].id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
DomainEvents.dispatch(postDeletedEvent);
|
DomainEvents.dispatch(postDeletedEvent);
|
||||||
@ -423,6 +426,39 @@ describe('CollectionsService', function () {
|
|||||||
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 0);
|
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Updates collections with publish filter when PostsBulkUnpublishedEvent event is produced', async function () {
|
||||||
|
const publishedPostsCollection = await collectionsService.createCollection({
|
||||||
|
title: 'Published Posts',
|
||||||
|
slug: 'published-posts',
|
||||||
|
type: 'automatic',
|
||||||
|
filter: 'published_at:>=2023-05-00T00:00:00.000Z'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal((await collectionsService.getById(publishedPostsCollection.id))?.posts.length, 2, 'Only two post fixtures are published on the 5th month of 2023');
|
||||||
|
|
||||||
|
assert.equal((await collectionsService.getById(automaticFeaturedCollection.id))?.posts?.length, 2);
|
||||||
|
assert.equal((await collectionsService.getById(automaticNonFeaturedCollection.id))?.posts.length, 2);
|
||||||
|
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 2);
|
||||||
|
|
||||||
|
collectionsService.subscribeToEvents();
|
||||||
|
|
||||||
|
postsRepository.save(Object.assign(postFixtures[2], {
|
||||||
|
published_at: null
|
||||||
|
}));
|
||||||
|
const postsBulkUnpublishedEvent = PostsBulkUnpublishedEvent.create([
|
||||||
|
postFixtures[2].id
|
||||||
|
]);
|
||||||
|
|
||||||
|
DomainEvents.dispatch(postsBulkUnpublishedEvent);
|
||||||
|
await DomainEvents.allSettled();
|
||||||
|
|
||||||
|
assert.equal((await collectionsService.getById(publishedPostsCollection.id))?.posts.length, 1, 'Only one post left as published on the 5th month of 2023');
|
||||||
|
|
||||||
|
assert.equal((await collectionsService.getById(automaticFeaturedCollection.id))?.posts.length, 2, 'There should be no change to the featured filter collection');
|
||||||
|
assert.equal((await collectionsService.getById(automaticNonFeaturedCollection.id))?.posts.length, 2, 'There should be no change to the non-featured filter collection');
|
||||||
|
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 2, 'There should be no change to the manual collection');
|
||||||
|
});
|
||||||
|
|
||||||
it('Updates only index collection when a non-featured post is added', async function () {
|
it('Updates only index collection when a non-featured post is added', async function () {
|
||||||
assert.equal((await collectionsService.getById(automaticFeaturedCollection.id))?.posts?.length, 2);
|
assert.equal((await collectionsService.getById(automaticFeaturedCollection.id))?.posts?.length, 2);
|
||||||
assert.equal((await collectionsService.getById(automaticNonFeaturedCollection.id))?.posts.length, 2);
|
assert.equal((await collectionsService.getById(automaticNonFeaturedCollection.id))?.posts.length, 2);
|
||||||
@ -442,7 +478,7 @@ describe('CollectionsService', function () {
|
|||||||
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 2);
|
assert.equal((await collectionsService.getById(manualCollection.id))?.posts.length, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Moves post form featured to non featured collection when the featured attribute is changed', async function () {
|
it('Moves post from featured to non featured collection when the featured attribute is changed', async function () {
|
||||||
collectionsService.subscribeToEvents();
|
collectionsService.subscribeToEvents();
|
||||||
const newFeaturedPost: CollectionPost & {deleted: false} = {
|
const newFeaturedPost: CollectionPost & {deleted: false} = {
|
||||||
id: 'post-featured',
|
id: 'post-featured',
|
||||||
|
@ -10,4 +10,10 @@ export class PostsRepositoryInMemory extends InMemoryRepository<string, Collecti
|
|||||||
tags: entity.tags.map(tag => tag.slug)
|
tags: entity.tags.map(tag => tag.slug)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getBulk(ids: string[]) {
|
||||||
|
return this.getAll({
|
||||||
|
filter: `id:[${ids.join(',')}]`
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user