From 826461a1da6483828f2b39c5376cbf5d24b9600f Mon Sep 17 00:00:00 2001 From: Krystian Date: Mon, 25 Oct 2021 20:01:12 +0200 Subject: [PATCH 1/6] Initial --- .../user-registration-was-completed.event-handler.service.ts | 0 ...then-register-current-edition-course-user-automation.module.ts | 0 ...on-completed-then-register-current-edition-course-user.spec.ts | 0 ...leted-then-register-current-edition-course-user.test-module.ts | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts create mode 100644 packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module.ts create mode 100644 packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts create mode 100644 packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts new file mode 100644 index 00000000..e69de29b From fcac223e11d22597fa96d21d1e7c8aa47b4ecb95 Mon Sep 17 00:00:00 2001 From: Krystian Date: Mon, 1 Nov 2021 16:34:57 +0100 Subject: [PATCH 2/6] Add automation module --- ...ion-was-completed.event-handler.service.ts | 50 +++++++++++++++++++ ...t-edition-course-user-automation.module.ts | 11 ++++ ...current-edition-course-user.test-module.ts | 7 +++ .../shared/commands/register-course-user.ts | 5 ++ .../application-command.factory.ts | 7 ++- 5 files changed, 78 insertions(+), 2 deletions(-) diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts index e69de29b..7c87cbf1 100644 --- a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts +++ b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts @@ -0,0 +1,50 @@ +import { Injectable, OnApplicationBootstrap, OnModuleDestroy } from '@nestjs/common'; +import { CommandBus } from '@nestjs/cqrs'; + +import { ApplicationEvent } from '@/module/application-command-events'; +import { RegisterCourseUserCommand } from '@/module/commands/register-course-user'; +import { RequestEmailConfirmationApplicationCommand } from '@/module/commands/request-email-conformation'; +import { UserRegistrationWasCompleted } from '@/module/events/user-registration-was-completed.domain-event'; +import { env } from '@/shared/env'; +import { ApplicationCommandFactory } from '@/write/shared/application/application-command.factory'; +import { EventsSubscription } from '@/write/shared/application/events-subscription/events-subscription'; +import { EventsSubscriptionsRegistry } from '@/write/shared/application/events-subscription/events-subscriptions-registry'; + +@Injectable() +export class UserRegistrationWasCompletedEventHandler implements OnApplicationBootstrap, OnModuleDestroy { + private eventsSubscription: EventsSubscription; + + constructor( + private readonly commandBus: CommandBus, + private readonly commandFactory: ApplicationCommandFactory, + private readonly eventsSubscriptionsFactory: EventsSubscriptionsRegistry, + ) {} + + async onApplicationBootstrap() { + this.eventsSubscription = this.eventsSubscriptionsFactory + .subscription('WhenUserRegistrationWasCompletedThenRegisterCourseUser_Automation_v1') + .onEvent('UserRegistrationWasCompleted', (event) => + this.onUserRegistrationWasCompleted(event), + ) + .build(); + await this.eventsSubscription.start(); + } + + async onModuleDestroy() { + await this.eventsSubscription.stop(); + } + + async onUserRegistrationWasCompleted(event: ApplicationEvent) { + const command = this.commandFactory.applicationCommand((idGenerator) => ({ + class: RequestEmailConfirmationApplicationCommand, + ...RegisterCourseUserCommand({ + userId: event.data.userId, + courseUserId: idGenerator.generate(), + courseId: env.CURRENT_COURSE_ID, + }), + metadata: { correlationId: event.metadata.correlationId, causationId: event.id }, + })); + + await this.commandBus.execute(command); + } +} diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module.ts index e69de29b..0d52cf51 100644 --- a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module.ts +++ b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { SharedModule } from '@/write/shared/shared.module'; + +import { UserRegistrationWasCompletedEventHandler } from './user-registration-was-completed.event-handler.service'; + +@Module({ + imports: [SharedModule], + providers: [UserRegistrationWasCompletedEventHandler], +}) +export class WhenRegistrationCompletedThenRegisterCurrentUserAutomationModule {} diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts index e69de29b..476b2369 100644 --- a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts +++ b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts @@ -0,0 +1,7 @@ +import { WhenRegistrationCompletedThenRegisterCurrentUserAutomationModule } from '@/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module'; +import { initAutomationTestModule } from '@/shared/test-utils'; +import { ID_GENERATOR, IdGenerator } from '@/write/shared/application/id-generator'; + +export async function whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule() { + return initAutomationTestModule([WhenRegistrationCompletedThenRegisterCurrentUserAutomationModule]); +} diff --git a/packages/api/src/module/shared/commands/register-course-user.ts b/packages/api/src/module/shared/commands/register-course-user.ts index 7aa13fab..2a5a447b 100644 --- a/packages/api/src/module/shared/commands/register-course-user.ts +++ b/packages/api/src/module/shared/commands/register-course-user.ts @@ -9,4 +9,9 @@ export type RegisterCourseUser = { }; }; +export const RegisterCourseUserCommand = (data: RegisterCourseUser['data']): RegisterCourseUser => ({ + type: 'RegisterCourseUser', + data, +}); + export class RegisterCourseUserApplicationCommand extends AbstractApplicationCommand {} diff --git a/packages/api/src/module/write/shared/application/application-command.factory.ts b/packages/api/src/module/write/shared/application/application-command.factory.ts index 097e05f6..d6616569 100644 --- a/packages/api/src/module/write/shared/application/application-command.factory.ts +++ b/packages/api/src/module/write/shared/application/application-command.factory.ts @@ -28,14 +28,17 @@ export class ApplicationCommandFactory { const generateId = () => this.idGenerator.generate(); const currentTime = () => this.timeProvider.currentTime(); + const id = generateId(); + const correlationId = generateId(); + const command = builder(this.idGenerator); return plainToClass(command.class, { type: command.type, - id: generateId(), + id, issuedAt: currentTime(), data: command.data, - metadata: { correlationId: generateId(), ...command.metadata }, + metadata: { correlationId, ...command.metadata }, }); } } From 8c57b75f3edcff25376dde8ff35a1a3bf71ac155 Mon Sep 17 00:00:00 2001 From: Krystian Date: Mon, 1 Nov 2021 16:35:14 +0100 Subject: [PATCH 3/6] add test to added automation module --- ...gister-current-edition-course-user.spec.ts | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts index e69de29b..58803b7b 100644 --- a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts +++ b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts @@ -0,0 +1,43 @@ +import { AsyncReturnType } from 'type-fest'; +import { v4 as uuid } from 'uuid'; + +import { RegisterCourseUser, RegisterCourseUserCommand } from '@/module/commands/register-course-user'; +import { userRegistrationWasCompletedEvent } from '@/module/events/user-registration-was-completed.domain-event'; +import { EventStreamName } from '@/write/shared/application/event-stream-name.value-object'; + +import { whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule } from './when-registration-completed-then-register-current-edition-course-user.test-module'; + +describe('RegisterCourseUser when registrationWasCompleted', () => { + let moduleUnderTest: AsyncReturnType< + typeof whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule + >; + + beforeEach(async () => { + moduleUnderTest = await whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule(); + }); + + afterEach(async () => { + await moduleUnderTest.close(); + }); + + it('test', async () => { + // Given + // console.log('env', env); + + const courseId = process.env.CURRENT_COURSE_ID ?? ''; + // const courseUserId = moduleUnderTest.lastGeneratedId(); + + const userId = 'ca63d023-4cbd-40ca-9f53-f19dbb19b0ab'; + const fullName = 'test user'; + const emailAddress = 'testUser@test.pl'; + const hashedPassword = '41c2c1fc8f6cdc15.d5ee8246071726582172f83d569287951a0d727c94dfc35e291fe17abec789c2'; + + const event = userRegistrationWasCompletedEvent({ userId, fullName, emailAddress, hashedPassword }); + + await moduleUnderTest.eventOccurred(EventStreamName.from('UserRegistration', userId), event); + + await moduleUnderTest.expectCommandExecutedLastly({ + ...RegisterCourseUserCommand({ courseId, userId, courseUserId: moduleUnderTest.lastGeneratedId() }), + }); + }); +}); From 72799e23298730569dbe73ceacdabac18e06ac30 Mon Sep 17 00:00:00 2001 From: Krystian Date: Mon, 1 Nov 2021 16:36:15 +0100 Subject: [PATCH 4/6] clean unused variables --- ...completed-then-register-current-edition-course-user.spec.ts | 3 --- ...ed-then-register-current-edition-course-user.test-module.ts | 1 - 2 files changed, 4 deletions(-) diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts index 58803b7b..4a779ce8 100644 --- a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts +++ b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts @@ -1,5 +1,4 @@ import { AsyncReturnType } from 'type-fest'; -import { v4 as uuid } from 'uuid'; import { RegisterCourseUser, RegisterCourseUserCommand } from '@/module/commands/register-course-user'; import { userRegistrationWasCompletedEvent } from '@/module/events/user-registration-was-completed.domain-event'; @@ -22,10 +21,8 @@ describe('RegisterCourseUser when registrationWasCompleted', () => { it('test', async () => { // Given - // console.log('env', env); const courseId = process.env.CURRENT_COURSE_ID ?? ''; - // const courseUserId = moduleUnderTest.lastGeneratedId(); const userId = 'ca63d023-4cbd-40ca-9f53-f19dbb19b0ab'; const fullName = 'test user'; diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts index 476b2369..b0d11086 100644 --- a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts +++ b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.test-module.ts @@ -1,6 +1,5 @@ import { WhenRegistrationCompletedThenRegisterCurrentUserAutomationModule } from '@/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module'; import { initAutomationTestModule } from '@/shared/test-utils'; -import { ID_GENERATOR, IdGenerator } from '@/write/shared/application/id-generator'; export async function whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule() { return initAutomationTestModule([WhenRegistrationCompletedThenRegisterCurrentUserAutomationModule]); From 622e2900548cb1ac04253aee033fbc98e541d634 Mon Sep 17 00:00:00 2001 From: Krystian Date: Mon, 1 Nov 2021 19:59:59 +0100 Subject: [PATCH 5/6] Correct ApplicationCommand class --- ...er-registration-was-completed.event-handler.service.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts index 7c87cbf1..0fcc57db 100644 --- a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts +++ b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/user-registration-was-completed.event-handler.service.ts @@ -2,8 +2,10 @@ import { Injectable, OnApplicationBootstrap, OnModuleDestroy } from '@nestjs/com import { CommandBus } from '@nestjs/cqrs'; import { ApplicationEvent } from '@/module/application-command-events'; -import { RegisterCourseUserCommand } from '@/module/commands/register-course-user'; -import { RequestEmailConfirmationApplicationCommand } from '@/module/commands/request-email-conformation'; +import { + RegisterCourseUserApplicationCommand, + RegisterCourseUserCommand, +} from '@/module/commands/register-course-user'; import { UserRegistrationWasCompleted } from '@/module/events/user-registration-was-completed.domain-event'; import { env } from '@/shared/env'; import { ApplicationCommandFactory } from '@/write/shared/application/application-command.factory'; @@ -36,7 +38,7 @@ export class UserRegistrationWasCompletedEventHandler implements OnApplicationBo async onUserRegistrationWasCompleted(event: ApplicationEvent) { const command = this.commandFactory.applicationCommand((idGenerator) => ({ - class: RequestEmailConfirmationApplicationCommand, + class: RegisterCourseUserApplicationCommand, ...RegisterCourseUserCommand({ userId: event.data.userId, courseUserId: idGenerator.generate(), From 9a4d831a14ba793d3e30377e79d58e327297d475 Mon Sep 17 00:00:00 2001 From: Krystian Date: Wed, 3 Nov 2021 21:02:24 +0100 Subject: [PATCH 6/6] correct test naming --- ...ompleted-then-register-current-edition-course-user.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts index 4a779ce8..2760b429 100644 --- a/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts +++ b/packages/api/src/module/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user.spec.ts @@ -19,7 +19,7 @@ describe('RegisterCourseUser when registrationWasCompleted', () => { await moduleUnderTest.close(); }); - it('test', async () => { + it('publishes registerCourseUser command when userRegistrationWasCompletedEvent occurred', async () => { // Given const courseId = process.env.CURRENT_COURSE_ID ?? ''; @@ -31,8 +31,10 @@ describe('RegisterCourseUser when registrationWasCompleted', () => { const event = userRegistrationWasCompletedEvent({ userId, fullName, emailAddress, hashedPassword }); + // When await moduleUnderTest.eventOccurred(EventStreamName.from('UserRegistration', userId), event); + // Then await moduleUnderTest.expectCommandExecutedLastly({ ...RegisterCourseUserCommand({ courseId, userId, courseUserId: moduleUnderTest.lastGeneratedId() }), });