diff --git a/app/api/entities/entities.js b/app/api/entities/entities.js index 73099ce7b4..fd3f35e94d 100644 --- a/app/api/entities/entities.js +++ b/app/api/entities/entities.js @@ -17,6 +17,7 @@ import ID from 'shared/uniqueID'; import { denormalizeMetadata, denormalizeRelated } from './denormalize'; import model from './entitiesModel'; +import { EntityCreatedEvent } from './events/EntityCreatedEvent'; import { EntityUpdatedEvent } from './events/EntityUpdatedEvent'; import { EntityDeletedEvent } from './events/EntityDeletedEvent'; import { saveSelections } from './metadataExtraction/saveSelections'; @@ -149,7 +150,7 @@ async function updateEntity(entity, _template, unrestricted = false) { await applicationEventsBus.emit( new EntityUpdatedEvent({ before: docLanguages, - after: result, + after: await model.get({ sharedId: entity.sharedId }), targetLanguageKey: entity.language, }) ); @@ -157,7 +158,7 @@ async function updateEntity(entity, _template, unrestricted = false) { return result; } -async function createEntity(doc, languages, sharedId, docTemplate) { +async function createEntity(doc, [currentLanguage, languages], sharedId, docTemplate) { if (!docTemplate) docTemplate = await templates.getById(doc.template); const thesauriByKey = await templates.getRelatedThesauri(docTemplate); @@ -203,6 +204,14 @@ async function createEntity(doc, languages, sharedId, docTemplate) { await updateNewRelationships(v2RelationshipsUpdates); await Promise.all(result.map(r => denormalizeAfterEntityCreation(r))); + + await applicationEventsBus.emit( + new EntityCreatedEvent({ + entities: await model.get({ sharedId }), + targetLanguageKey: currentLanguage, + }) + ); + return result; } @@ -410,7 +419,12 @@ export default { docTemplate = defaultTemplate; } doc.metadata = doc.metadata || {}; - await this.createEntity(this.sanitize(doc, docTemplate), languages, sharedId, docTemplate); + await this.createEntity( + this.sanitize(doc, docTemplate), + [language, languages], + sharedId, + docTemplate + ); } const [entity] = includeDocuments diff --git a/app/api/entities/events/EntityCreatedEvent.ts b/app/api/entities/events/EntityCreatedEvent.ts new file mode 100644 index 0000000000..12d561a6ec --- /dev/null +++ b/app/api/entities/events/EntityCreatedEvent.ts @@ -0,0 +1,11 @@ +import { AbstractEvent } from 'api/eventsbus'; +import { EntitySchema } from 'shared/types/entityType'; + +interface EntityCreatedData { + entities: EntitySchema[]; + targetLanguageKey: string; +} + +class EntityCreatedEvent extends AbstractEvent {} + +export { EntityCreatedEvent }; diff --git a/app/api/entities/specs/entities.spec.js b/app/api/entities/specs/entities.spec.js index 5ea4daa2fb..6e28939018 100644 --- a/app/api/entities/specs/entities.spec.js +++ b/app/api/entities/specs/entities.spec.js @@ -2,6 +2,8 @@ /* eslint-disable max-nested-callbacks,max-statements */ import Ajv from 'ajv'; +// eslint-disable-next-line node/no-restricted-import +import fs from 'fs/promises'; import entitiesModel from 'api/entities/entitiesModel'; import { spyOnEmit } from 'api/eventsbus/eventTesting'; @@ -11,10 +13,9 @@ import { search } from 'api/search'; import date from 'api/utils/date.js'; import db from 'api/utils/testing_db'; import { UserInContextMockFactory } from 'api/utils/testingUserInContext'; -// eslint-disable-next-line node/no-restricted-import -import fs from 'fs/promises'; import { UserRole } from 'shared/types/userSchema'; +import { applicationEventsBus } from 'api/eventsbus'; import fixtures, { adminId, batmanFinishesId, @@ -32,6 +33,7 @@ import fixtures, { import entities from '../entities.js'; import { EntityUpdatedEvent } from '../events/EntityUpdatedEvent'; import { EntityDeletedEvent } from '../events/EntityDeletedEvent'; +import { EntityCreatedEvent } from '../events/EntityCreatedEvent'; describe('entities', () => { const userFactory = new UserInContextMockFactory(); @@ -509,22 +511,61 @@ describe('entities', () => { }); describe('events', () => { + let emitSpy; + + beforeEach(() => { + emitSpy = jest.spyOn(applicationEventsBus, 'emit'); + emitSpy.mockClear(); + }); + + it('should emit an event when an entity is created', async () => { + const newEntity = { + template: templateId, + title: 'New Super Hero', + metadata: { + text: [{ value: 'New Text' }], + property1: [{ value: 'value1' }], + property2: [{ value: 'value2' }], + description: [{ value: 'ew Description' }], + friends: [{ icon: null, label: 'shared2title', type: 'entity', value: 'shared2' }], + enemies: [{ icon: null, label: 'shared2title', type: 'entity', value: 'shared2' }], + select: [], + }, + }; + + const savedEntity = await entities.save(newEntity, { + user: { _id: adminId }, + language: 'en', + }); + + const afterAllLanguages = await entities.getAllLanguages(savedEntity.sharedId); + + expect(emitSpy.mock.calls[0][0]).toBeInstanceOf(EntityCreatedEvent); + expect(emitSpy).toHaveBeenCalledWith( + new EntityCreatedEvent({ + entities: afterAllLanguages, + targetLanguageKey: 'en', + }) + ); + }); + it('should emit an event when an entity is updated', async () => { - const emitSpy = spyOnEmit(); const before = fixtures.entities.find(e => e._id === batmanFinishesId); - const beforeAllLanguages = fixtures.entities.filter(e => e.sharedId === before.sharedId); + const beforeAllLanguages = await entities.getAllLanguages(before.sharedId); const after = { ...before, title: 'new title' }; await entities.save(after, { language: 'en' }); const afterAllLanguages = await entities.getAllLanguages(before.sharedId); - emitSpy.expectToEmitEvent(EntityUpdatedEvent, { - before: beforeAllLanguages, - after: afterAllLanguages, - targetLanguageKey: 'en', - }); - emitSpy.restore(); + expect(emitSpy.mock.calls[0][0]).toBeInstanceOf(EntityUpdatedEvent); + expect(emitSpy).toHaveBeenCalledWith( + new EntityUpdatedEvent({ + before: beforeAllLanguages, + after: afterAllLanguages, + targetLanguageKey: 'en', + }) + ); }); }); });