Skip to content

Commit 972a618

Browse files
committed
Create Retention BC from the notifications module of the Mooc BC
1 parent 2bdb81f commit 972a618

25 files changed

+223
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { EmailSender } from '../../domain/EmailSender';
2+
import { EmailAddress } from '../../domain/EmailAddress';
3+
import { WelcomeUserEmail } from '../../domain/WelcomeUserEmail';
4+
import { WelcomeUserEmailError } from '../../domain/WelcomeUserEmailError';
5+
6+
export default class SendWelcomeUserEmail {
7+
constructor(private emailSender: EmailSender) {}
8+
9+
async run(userEmailAddress: EmailAddress): Promise<void> {
10+
const welcomeUserEmail = new WelcomeUserEmail(userEmailAddress);
11+
try {
12+
await this.emailSender.send(welcomeUserEmail);
13+
} catch (error) {
14+
throw new WelcomeUserEmailError(userEmailAddress);
15+
}
16+
}
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { DomainEventSubscriber } from '../../../../Shared/domain/DomainEventSubscriber';
2+
import { UserRegisteredDomainEvent } from '../../domain/UserRegisteredDomainEvent';
3+
import { DomainEventClass } from '../../../../Shared/domain/DomainEvent';
4+
import SendWelcomeUserEmail from './SendWelcomeUserEmail';
5+
import { EmailAddress } from '../../domain/EmailAddress';
6+
7+
export default class SendWelcomeUserEmailOnUserRegistered implements DomainEventSubscriber<UserRegisteredDomainEvent> {
8+
constructor(private sendWelcomeUserEmail: SendWelcomeUserEmail) {}
9+
10+
subscribedTo(): DomainEventClass[] {
11+
return [UserRegisteredDomainEvent];
12+
}
13+
14+
async on(domainEvent: UserRegisteredDomainEvent): Promise<void> {
15+
const userEmailAddress = new EmailAddress(domainEvent.userEmailAddress);
16+
await this.sendWelcomeUserEmail.run(userEmailAddress);
17+
}
18+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { EmailAddress } from './EmailAddress';
2+
import { EmailId } from './EmailId';
3+
import { Uuid } from '../../../Shared/domain/value-object/Uuid';
4+
5+
type ConstructorParams = {
6+
id?: EmailId;
7+
from: EmailAddress;
8+
to: EmailAddress;
9+
subject: string;
10+
body: string;
11+
};
12+
13+
export class Email {
14+
readonly id: EmailId;
15+
readonly from: EmailAddress;
16+
readonly to: EmailAddress;
17+
readonly subject: string;
18+
readonly body: string;
19+
20+
constructor(params: ConstructorParams) {
21+
this.id = params.id || new EmailId(Uuid.random().value);
22+
this.from = params.from;
23+
this.to = params.to;
24+
this.subject = params.subject;
25+
this.body = params.body;
26+
}
27+
28+
equals(otherEmail: Email): boolean {
29+
return (
30+
this.id.value === otherEmail.id.value &&
31+
this.from.value === otherEmail.from.value &&
32+
this.to.value === otherEmail.to.value &&
33+
this.subject === otherEmail.subject &&
34+
this.body === otherEmail.body
35+
);
36+
}
37+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { StringValueObject } from '../../../Shared/domain/value-object/StringValueObject';
2+
3+
export class EmailAddress extends StringValueObject {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Uuid } from '../../../Shared/domain/value-object/Uuid';
2+
3+
export class EmailId extends Uuid {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Email } from './Email';
2+
3+
export interface EmailSender {
4+
send(email: Email): Promise<void>;
5+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { DomainEvent } from '../../../Shared/domain/DomainEvent';
2+
3+
type UserRegisteredDomainEventBody = { userEmailAddress: string };
4+
5+
export class UserRegisteredDomainEvent extends DomainEvent {
6+
static readonly EVENT_NAME = 'user.registered';
7+
readonly userEmailAddress: string;
8+
9+
constructor(data: { id: string; userEmailAddress: string; eventId?: string; occurredOn?: Date }) {
10+
const { id, eventId, occurredOn, userEmailAddress } = data;
11+
super(UserRegisteredDomainEvent.EVENT_NAME, id, eventId, occurredOn);
12+
this.userEmailAddress = userEmailAddress;
13+
}
14+
15+
toPrimitive(): Object {
16+
return { userEmailAddress: this.userEmailAddress };
17+
}
18+
19+
static fromPrimitives(
20+
aggregateId: string,
21+
body: UserRegisteredDomainEventBody,
22+
eventId: string,
23+
occurredOn: Date
24+
): DomainEvent {
25+
return new UserRegisteredDomainEvent({
26+
id: aggregateId,
27+
userEmailAddress: body.userEmailAddress,
28+
eventId,
29+
occurredOn
30+
});
31+
}
32+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Email } from './Email';
2+
import { EmailAddress } from './EmailAddress';
3+
4+
export class WelcomeUserEmail extends Email {
5+
constructor(to: EmailAddress) {
6+
super({
7+
from: new EmailAddress('[email protected]'),
8+
to,
9+
subject: 'Welcome',
10+
body: 'Welcome to our platform'
11+
});
12+
}
13+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { EmailAddress } from './EmailAddress';
2+
3+
export class WelcomeUserEmailError extends Error {
4+
constructor(userEmailAddress: EmailAddress) {
5+
super(`Error sending WelcomeUser email to ${userEmailAddress.value}`);
6+
}
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { EmailSender } from '../domain/EmailSender';
2+
import { Email } from '../domain/Email';
3+
4+
export default class FakeEmailSender implements EmailSender {
5+
async send(email: Email): Promise<void> {
6+
// do nothing
7+
}
8+
}

0 commit comments

Comments
 (0)