From da10d067f809c6859fbdb7af4338b475c261fb60 Mon Sep 17 00:00:00 2001 From: Tria Date: Wed, 3 Jun 2026 16:17:36 +0300 Subject: [PATCH] multiple notification strategies --- apps/edr-freight-api/package.json | 5 ++-- .../notifications/notifications.module.ts | 9 +++++-- .../notifications/notifications.service.ts | 27 ++++++++++++++++--- .../strategies/notification.email.strategy.ts | 12 +++++++++ .../strategies/notification.sms.strategy.ts | 25 +++++++++++++++++ .../strategies/notification.strategy.ts | 6 +++++ pnpm-lock.yaml | 5 +++- 7 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 apps/edr-freight-api/src/modules/notifications/strategies/notification.email.strategy.ts create mode 100644 apps/edr-freight-api/src/modules/notifications/strategies/notification.sms.strategy.ts create mode 100644 apps/edr-freight-api/src/modules/notifications/strategies/notification.strategy.ts diff --git a/apps/edr-freight-api/package.json b/apps/edr-freight-api/package.json index 5114e20da..41c570010 100644 --- a/apps/edr-freight-api/package.json +++ b/apps/edr-freight-api/package.json @@ -15,6 +15,7 @@ "dependencies": { "@edr/api-common": "workspace:*", "@edr/types": "workspace:*", + "@nestjs/axios": "^4.0.1", "@nestjs/common": "^11.0.0", "@nestjs/config": "^4.0.0", "@nestjs/core": "^11.0.0", @@ -27,7 +28,7 @@ "@tria-plc/iamapi-common": "^0.1.6", "amqp-connection-manager": "^5.0.0", "amqplib": "^2.0.1", - "axios": "^1.7.7", + "axios": "^1.16.1", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "dotenv": "^17.4.2", @@ -76,4 +77,4 @@ "coverageDirectory": "../coverage", "testEnvironment": "node" } -} +} \ No newline at end of file diff --git a/apps/edr-freight-api/src/modules/notifications/notifications.module.ts b/apps/edr-freight-api/src/modules/notifications/notifications.module.ts index 39fe1b5c7..2ff2f9727 100644 --- a/apps/edr-freight-api/src/modules/notifications/notifications.module.ts +++ b/apps/edr-freight-api/src/modules/notifications/notifications.module.ts @@ -1,9 +1,14 @@ import { Module } from "@nestjs/common"; import { NotificationsService } from "./notifications.service"; +import { EmailNotificationStrategy } from "./strategies/notification.email.strategy"; +import { SmsNotificationStrategy } from "./strategies/notification.sms.strategy"; +import { HttpModule } from "@nestjs/axios"; @Module({ - providers: [NotificationsService], + imports: [HttpModule], + controllers: [], + providers: [EmailNotificationStrategy, SmsNotificationStrategy, NotificationsService], exports: [NotificationsService], }) -export class NotificationsModule {} +export class NotificationsModule { } diff --git a/apps/edr-freight-api/src/modules/notifications/notifications.service.ts b/apps/edr-freight-api/src/modules/notifications/notifications.service.ts index c17250264..35e8ff07d 100644 --- a/apps/edr-freight-api/src/modules/notifications/notifications.service.ts +++ b/apps/edr-freight-api/src/modules/notifications/notifications.service.ts @@ -1,14 +1,35 @@ -import { Injectable, Logger } from "@nestjs/common"; +import { Injectable, Logger, NotFoundException } from "@nestjs/common"; +import { EmailNotificationStrategy } from "./strategies/notification.email.strategy"; +import { NotificationStrategy } from "./strategies/notification.strategy"; +import { SmsNotificationStrategy } from "./strategies/notification.sms.strategy"; + + +type StrategyMethod = "sms" | "email" @Injectable() export class NotificationsService { private readonly logger = new Logger(NotificationsService.name); + private readonly strategies: Map + constructor(private readonly email: EmailNotificationStrategy, private readonly sms: SmsNotificationStrategy) { + this.strategies = new Map([ + ["sms", this.sms as NotificationStrategy], + ["email", this.email as NotificationStrategy] + ]) + } /** * Dispatch a notification to an operator or customer. * TODO: wire to email/SMS provider (SendGrid, SMS API, etc.) via a mailer service. */ - async send(recipient: string, subject: string, body: string): Promise { - this.logger.log(`[notify] ${recipient} :: ${subject} :: ${body}`); + + async directSend(method: StrategyMethod, recipient: string, message: string) { + const strategy = this.strategies.get(method); + if (!strategy) { + throw new NotFoundException(); + } + const sent = await strategy.send(recipient, message) + this.logger.log(`is sent - ${sent}`) } + + } diff --git a/apps/edr-freight-api/src/modules/notifications/strategies/notification.email.strategy.ts b/apps/edr-freight-api/src/modules/notifications/strategies/notification.email.strategy.ts new file mode 100644 index 000000000..57873639b --- /dev/null +++ b/apps/edr-freight-api/src/modules/notifications/strategies/notification.email.strategy.ts @@ -0,0 +1,12 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { NotificationStrategy } from "./notification.strategy"; + +@Injectable() +export class EmailNotificationStrategy implements NotificationStrategy { + private readonly logger = new Logger(EmailNotificationStrategy.name); + constructor() { } + async send(recipient: string, message: string): Promise { + this.logger.log(`${recipient}, ${message}`) + return false; + } +} \ No newline at end of file diff --git a/apps/edr-freight-api/src/modules/notifications/strategies/notification.sms.strategy.ts b/apps/edr-freight-api/src/modules/notifications/strategies/notification.sms.strategy.ts new file mode 100644 index 000000000..2f8916845 --- /dev/null +++ b/apps/edr-freight-api/src/modules/notifications/strategies/notification.sms.strategy.ts @@ -0,0 +1,25 @@ +import { Injectable} from "@nestjs/common"; +import { NotificationStrategy } from "./notification.strategy"; +import { HttpService } from '@nestjs/axios'; +import { ConfigService } from "@nestjs/config"; +import { firstValueFrom } from 'rxjs'; + +@Injectable() +export class SmsNotificationStrategy implements NotificationStrategy { + constructor(private readonly httpService: HttpService, private readonly configService: ConfigService) { } + async send(recipient: string, message: string) { + const url = this.configService.get("OZIKING_SMS_URL") + const body = { + to: recipient, + text: message + } + const response = await firstValueFrom( + this.httpService.post( + url, + body, + ), + ); + + return response.status === 201; + } +} diff --git a/apps/edr-freight-api/src/modules/notifications/strategies/notification.strategy.ts b/apps/edr-freight-api/src/modules/notifications/strategies/notification.strategy.ts new file mode 100644 index 000000000..2bc53120c --- /dev/null +++ b/apps/edr-freight-api/src/modules/notifications/strategies/notification.strategy.ts @@ -0,0 +1,6 @@ +import { Injectable } from "@nestjs/common"; + +@Injectable() +export abstract class NotificationStrategy { + abstract send(recipient: string, message: string): Promise +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9b737e64..8c735c36c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: '@edr/types': specifier: workspace:* version: link:../../packages/types + '@nestjs/axios': + specifier: ^4.0.1 + version: 4.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.1)(rxjs@7.8.2) '@nestjs/common': specifier: ^11.0.0 version: 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -81,7 +84,7 @@ importers: specifier: ^2.0.1 version: 2.0.1 axios: - specifier: ^1.7.7 + specifier: ^1.16.1 version: 1.16.1 class-transformer: specifier: ^0.5.1