mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Added model event to domain event bridge
refs https://github.com/TryGhost/Team/issues/3169 - To make the coupling to Ghost's model events as loose as possible added a bridge that maps model events to domain events. These domain events it what the collections module can subscribe to to make necessary updates.
This commit is contained in:
parent
2eb7f7dd25
commit
e7a0462877
7 changed files with 78 additions and 38 deletions
|
@ -28,6 +28,7 @@
|
|||
"typescript": "5.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/domain-events": "0.0.0",
|
||||
"@tryghost/errors": "^1.2.25",
|
||||
"@tryghost/in-memory-repository": "0.0.0",
|
||||
"@tryghost/tpl": "^0.1.25",
|
||||
|
|
|
@ -3,6 +3,7 @@ import {CollectionResourceChangeEvent} from './CollectionResourceChangeEvent';
|
|||
import {CollectionRepository} from './CollectionRepository';
|
||||
import tpl from '@tryghost/tpl';
|
||||
import {MethodNotAllowedError, NotFoundError} from '@tryghost/errors';
|
||||
import DomainEvents from '@tryghost/domain-events';
|
||||
|
||||
const messages = {
|
||||
cannotDeleteBuiltInCollectionError: {
|
||||
|
@ -132,6 +133,15 @@ export class CollectionsService {
|
|||
return mappedDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Subscribes to Domain events to update collections when posts are added, updated or deleted
|
||||
*/
|
||||
subscribeToEvents() {
|
||||
DomainEvents.subscribe(CollectionResourceChangeEvent, async (event: CollectionResourceChangeEvent) => {
|
||||
await this.updateCollections(event);
|
||||
});
|
||||
}
|
||||
|
||||
async createCollection(data: CollectionInputDTO): Promise<CollectionDTO> {
|
||||
const collection = await Collection.create({
|
||||
title: data.title,
|
||||
|
|
1
ghost/collections/src/libraries.d.ts
vendored
1
ghost/collections/src/libraries.d.ts
vendored
|
@ -1,2 +1,3 @@
|
|||
declare module '@tryghost/errors';
|
||||
declare module '@tryghost/tpl';
|
||||
declare module '@tryghost/domain-events'
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import assert from 'assert';
|
||||
import assert from 'assert/strict';
|
||||
import sinon from 'sinon';
|
||||
import DomainEvents from '@tryghost/domain-events';
|
||||
import {
|
||||
CollectionsService,
|
||||
CollectionsRepositoryInMemory,
|
||||
|
@ -259,6 +261,24 @@ describe('CollectionsService', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('subscribeToEvents', function () {
|
||||
it('Subscribes to Domain Events', function () {
|
||||
const updateCollectionsSpy = sinon.spy(collectionsService, 'updateCollections');
|
||||
const collectionChangeEvent = CollectionResourceChangeEvent.create('post.added', {
|
||||
id: 'test-id',
|
||||
resource: 'post'
|
||||
});
|
||||
|
||||
DomainEvents.dispatch(collectionChangeEvent);
|
||||
assert.equal(updateCollectionsSpy.calledOnce, false, 'updateCollections should not be called yet');
|
||||
|
||||
collectionsService.subscribeToEvents();
|
||||
|
||||
DomainEvents.dispatch(collectionChangeEvent);
|
||||
assert.equal(updateCollectionsSpy.calledOnce, true, 'updateCollections should be called');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Automatic Collections', function () {
|
||||
it('Can create an automatic collection', async function () {
|
||||
const collection = await collectionsService.createCollection({
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const {
|
||||
CollectionsService,
|
||||
CollectionsRepositoryInMemory,
|
||||
CollectionResourceChangeEvent
|
||||
CollectionsRepositoryInMemory
|
||||
} = require('@tryghost/collections');
|
||||
const labs = require('../../../shared/labs');
|
||||
|
||||
|
@ -26,8 +25,7 @@ class CollectionsServiceWrapper {
|
|||
return;
|
||||
}
|
||||
|
||||
const events = require('../../lib/common/events');
|
||||
|
||||
const translateModelEventsToDomainEvents = require('./model-to-domain-events-bridge');
|
||||
const existingBuiltins = await this.api.getAll({filter: 'slug:featured'});
|
||||
|
||||
if (!existingBuiltins.data.length) {
|
||||
|
@ -50,24 +48,8 @@ class CollectionsServiceWrapper {
|
|||
});
|
||||
}
|
||||
|
||||
const ghostModelUpdateEvents = require('./update-events');
|
||||
|
||||
const collectionListener = (event, data) => {
|
||||
const change = Object.assign({}, {
|
||||
id: data.id,
|
||||
resource: event.split('.')[0]
|
||||
}, data._changed);
|
||||
const collectionResourceChangeEvent = CollectionResourceChangeEvent.create(event, change);
|
||||
// @NOTE: to avoid race conditions we need a queue here to make sure updates happen
|
||||
// one by one and not in parallel
|
||||
this.api.updateCollections(collectionResourceChangeEvent);
|
||||
};
|
||||
|
||||
for (const event of ghostModelUpdateEvents) {
|
||||
if (!events.hasRegisteredListener(event, 'collectionListener')) {
|
||||
events.on(event, data => collectionListener(event, data));
|
||||
}
|
||||
}
|
||||
this.api.subscribeToEvents();
|
||||
translateModelEventsToDomainEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
const DomainEvents = require('@tryghost/domain-events');
|
||||
const {
|
||||
CollectionResourceChangeEvent
|
||||
} = require('@tryghost/collections');
|
||||
|
||||
const domainEventDispatcher = (modelEventName, data) => {
|
||||
const change = Object.assign({}, {
|
||||
id: data.id,
|
||||
resource: modelEventName.split('.')[0]
|
||||
}, data._changed);
|
||||
const collectionResourceChangeEvent = CollectionResourceChangeEvent.create(modelEventName, change);
|
||||
|
||||
DomainEvents.dispatch(collectionResourceChangeEvent);
|
||||
};
|
||||
|
||||
const translateModelEventsToDomainEvents = () => {
|
||||
const events = require('../../lib/common/events');
|
||||
const ghostModelUpdateEvents = [
|
||||
'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'
|
||||
];
|
||||
|
||||
for (const modelEvent of ghostModelUpdateEvents) {
|
||||
if (!events.hasRegisteredListener(modelEvent, 'collectionListener')) {
|
||||
events.on(modelEvent, data => domainEventDispatcher(modelEvent, data));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = translateModelEventsToDomainEvents;
|
|
@ -1,15 +0,0 @@
|
|||
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'
|
||||
];
|
Loading…
Add table
Reference in a new issue