Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.

Commit f89e126

Browse files
authored
feat(api): [automation | WhenRegistrationCompletedThenRegisterCurrentEditionCourseUser] implement slice (#406)
1 parent 9ff51b9 commit f89e126

File tree

6 files changed

+121
-2
lines changed

6 files changed

+121
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Injectable, OnApplicationBootstrap, OnModuleDestroy } from '@nestjs/common';
2+
import { CommandBus } from '@nestjs/cqrs';
3+
4+
import { ApplicationEvent } from '@/module/application-command-events';
5+
import {
6+
RegisterCourseUserApplicationCommand,
7+
RegisterCourseUserCommand,
8+
} from '@/module/commands/register-course-user';
9+
import { UserRegistrationWasCompleted } from '@/module/events/user-registration-was-completed.domain-event';
10+
import { env } from '@/shared/env';
11+
import { ApplicationCommandFactory } from '@/write/shared/application/application-command.factory';
12+
import { EventsSubscription } from '@/write/shared/application/events-subscription/events-subscription';
13+
import { EventsSubscriptionsRegistry } from '@/write/shared/application/events-subscription/events-subscriptions-registry';
14+
15+
@Injectable()
16+
export class UserRegistrationWasCompletedEventHandler implements OnApplicationBootstrap, OnModuleDestroy {
17+
private eventsSubscription: EventsSubscription;
18+
19+
constructor(
20+
private readonly commandBus: CommandBus,
21+
private readonly commandFactory: ApplicationCommandFactory,
22+
private readonly eventsSubscriptionsFactory: EventsSubscriptionsRegistry,
23+
) {}
24+
25+
async onApplicationBootstrap() {
26+
this.eventsSubscription = this.eventsSubscriptionsFactory
27+
.subscription('WhenUserRegistrationWasCompletedThenRegisterCourseUser_Automation_v1')
28+
.onEvent<UserRegistrationWasCompleted>('UserRegistrationWasCompleted', (event) =>
29+
this.onUserRegistrationWasCompleted(event),
30+
)
31+
.build();
32+
await this.eventsSubscription.start();
33+
}
34+
35+
async onModuleDestroy() {
36+
await this.eventsSubscription.stop();
37+
}
38+
39+
async onUserRegistrationWasCompleted(event: ApplicationEvent<UserRegistrationWasCompleted>) {
40+
const command = this.commandFactory.applicationCommand((idGenerator) => ({
41+
class: RegisterCourseUserApplicationCommand,
42+
...RegisterCourseUserCommand({
43+
userId: event.data.userId,
44+
courseUserId: idGenerator.generate(),
45+
courseId: env.CURRENT_COURSE_ID,
46+
}),
47+
metadata: { correlationId: event.metadata.correlationId, causationId: event.id },
48+
}));
49+
50+
await this.commandBus.execute(command);
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Module } from '@nestjs/common';
2+
3+
import { SharedModule } from '@/write/shared/shared.module';
4+
5+
import { UserRegistrationWasCompletedEventHandler } from './user-registration-was-completed.event-handler.service';
6+
7+
@Module({
8+
imports: [SharedModule],
9+
providers: [UserRegistrationWasCompletedEventHandler],
10+
})
11+
export class WhenRegistrationCompletedThenRegisterCurrentUserAutomationModule {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { AsyncReturnType } from 'type-fest';
2+
3+
import { RegisterCourseUser, RegisterCourseUserCommand } from '@/module/commands/register-course-user';
4+
import { userRegistrationWasCompletedEvent } from '@/module/events/user-registration-was-completed.domain-event';
5+
import { EventStreamName } from '@/write/shared/application/event-stream-name.value-object';
6+
7+
import { whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule } from './when-registration-completed-then-register-current-edition-course-user.test-module';
8+
9+
describe('RegisterCourseUser when registrationWasCompleted', () => {
10+
let moduleUnderTest: AsyncReturnType<
11+
typeof whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule
12+
>;
13+
14+
beforeEach(async () => {
15+
moduleUnderTest = await whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule();
16+
});
17+
18+
afterEach(async () => {
19+
await moduleUnderTest.close();
20+
});
21+
22+
it('publishes registerCourseUser command when userRegistrationWasCompletedEvent occurred', async () => {
23+
// Given
24+
25+
const courseId = process.env.CURRENT_COURSE_ID ?? '';
26+
27+
const userId = 'ca63d023-4cbd-40ca-9f53-f19dbb19b0ab';
28+
const fullName = 'test user';
29+
const emailAddress = 'testUser@test.pl';
30+
const hashedPassword = '41c2c1fc8f6cdc15.d5ee8246071726582172f83d569287951a0d727c94dfc35e291fe17abec789c2';
31+
32+
const event = userRegistrationWasCompletedEvent({ userId, fullName, emailAddress, hashedPassword });
33+
34+
// When
35+
await moduleUnderTest.eventOccurred(EventStreamName.from('UserRegistration', userId), event);
36+
37+
// Then
38+
await moduleUnderTest.expectCommandExecutedLastly<RegisterCourseUser>({
39+
...RegisterCourseUserCommand({ courseId, userId, courseUserId: moduleUnderTest.lastGeneratedId() }),
40+
});
41+
});
42+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { WhenRegistrationCompletedThenRegisterCurrentUserAutomationModule } from '@/automation/when-registration-completed-then-register-current-edition-course-user/when-registration-completed-then-register-current-edition-course-user-automation.module';
2+
import { initAutomationTestModule } from '@/shared/test-utils';
3+
4+
export async function whenUserRegistrationWasCompletedThenRegisterCurrentEditionCourseUserAutomationTestModule() {
5+
return initAutomationTestModule([WhenRegistrationCompletedThenRegisterCurrentUserAutomationModule]);
6+
}

packages/api/src/module/shared/commands/register-course-user.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,9 @@ export type RegisterCourseUser = {
99
};
1010
};
1111

12+
export const RegisterCourseUserCommand = (data: RegisterCourseUser['data']): RegisterCourseUser => ({
13+
type: 'RegisterCourseUser',
14+
data,
15+
});
16+
1217
export class RegisterCourseUserApplicationCommand extends AbstractApplicationCommand<RegisterCourseUser> {}

packages/api/src/module/write/shared/application/application-command.factory.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@ export class ApplicationCommandFactory {
2828
const generateId = () => this.idGenerator.generate();
2929
const currentTime = () => this.timeProvider.currentTime();
3030

31+
const id = generateId();
32+
const correlationId = generateId();
33+
3134
const command = builder(this.idGenerator);
3235

3336
return plainToClass(command.class, {
3437
type: command.type,
35-
id: generateId(),
38+
id,
3639
issuedAt: currentTime(),
3740
data: command.data,
38-
metadata: { correlationId: generateId(), ...command.metadata },
41+
metadata: { correlationId, ...command.metadata },
3942
});
4043
}
4144
}

0 commit comments

Comments
 (0)