diff --git a/src/config/app.config.ts b/src/config/app.config.ts index f6df1c1..21fda24 100644 --- a/src/config/app.config.ts +++ b/src/config/app.config.ts @@ -1,10 +1,10 @@ import { registerAs } from '@nestjs/config'; export default registerAs('appConfig', () => ({ - user: process.env.RABBITMQ_USER , - pass: process.env.RABBITMQ_PASS , - host: process.env.RABBITMQ_HOST , - port: process.env.RABBITMQ_PORT , + user: process.env.RABBITMQ_USER, + pass: process.env.RABBITMQ_PASS, + host: process.env.RABBITMQ_HOST, + port: process.env.RABBITMQ_PORT, apiUrl: process.env.RABBITMQ_API_URL || 'https://rabbitmq.dcb.pixpay.sn/api', queues: { smsmo: process.env.RABBITMQ_QUEUE_WEBHOOK || 'smsmo_queue', @@ -12,9 +12,9 @@ export default registerAs('appConfig', () => ({ he: process.env.RABBITMQ_QUEUE_NOTIFICATION || 'he_queue', }, keycloak: { - authServerUrl: process.env.KEYCLOAK_AUTH_SERVER_URL , - clientId: process.env.KEYCLOAK_CLIENT_ID , - clientSecret: process.env.KEYCLOAK_CLIENT_SECRET , - realm: process.env.KEYCLOAK_REALM , + authServerUrl: process.env.KEYCLOAK_AUTH_SERVER_URL, + clientId: process.env.KEYCLOAK_CLIENT_ID, + clientSecret: process.env.KEYCLOAK_CLIENT_SECRET, + realm: process.env.KEYCLOAK_REALM, }, })); diff --git a/src/controllers/webhook.controller.ts b/src/controllers/webhook.controller.ts index 825e98f..0b13a09 100644 --- a/src/controllers/webhook.controller.ts +++ b/src/controllers/webhook.controller.ts @@ -10,7 +10,14 @@ import { HttpStatus, } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { + ApiBearerAuth, + ApiBody, + ApiCreatedResponse, + ApiOkResponse, + ApiOperation, + ApiTags, +} from '@nestjs/swagger'; import { Resource, Roles } from 'nest-keycloak-connect'; import { InboundSMSMessageNotificationWrapperDto } from 'src/dtos/sms.mo.dto'; import { SubscriptionDto } from 'src/dtos/subscription.dto'; @@ -18,12 +25,25 @@ import { WebhookService } from 'src/services/webhook.service'; @Controller('webhook') @ApiTags('webhook') +@ApiBearerAuth() export class WebhookController { constructor(private readonly webhookService: WebhookService) {} @Post('sms-mo/:operator/:country') @HttpCode(HttpStatus.CREATED) @Roles({ roles: ['admin_webhook'] }) + @ApiOperation({ summary: 'Receive callback for SMS MO notification' }) + @ApiBody({ type: InboundSMSMessageNotificationWrapperDto }) + @ApiCreatedResponse({ + description: 'SMS MO callback successfully queued', + schema: { + example: { + status: 'queued', + operator: 'Orange', + country: 'SN', + }, + }, + }) async smsMoNotification( @Param('country') country: string, @Param('operator') operator: string, @@ -41,6 +61,18 @@ export class WebhookController { @Post('subscription/:operator/:country') @HttpCode(HttpStatus.CREATED) @Roles({ roles: ['admin_webhook'] }) + @ApiOperation({ summary: 'Receive callback for management of subscription' }) + @ApiBody({ type: SubscriptionDto }) + @ApiCreatedResponse({ + description: 'Subscription event successfully queued', + schema: { + example: { + status: 'queued', + operator: 'Orange', + country: 'EG', + }, + }, + }) async manageSubscription( @Param('country') country: string, @Param('operator') operator: string, @@ -57,6 +89,15 @@ export class WebhookController { @Get('he/:operator/:country') @HttpCode(HttpStatus.OK) @Roles({ roles: ['admin_webhook'] }) + @ApiOperation({ summary: 'Receive callback for HE notification' }) + @ApiOkResponse({ + description: 'HE notification successfully queued', + schema: { + example: { + status: 'queued', + }, + }, + }) async heNotification( @Param('country') country: string, @Param('operator') operator: string, @@ -73,6 +114,6 @@ export class WebhookController { callback, ); - return { status: 'queued', operator, country, callback }; + return { status: 'queued' }; } } diff --git a/src/dtos/sms.mo.dto.ts b/src/dtos/sms.mo.dto.ts index 679bbb6..2bd6924 100644 --- a/src/dtos/sms.mo.dto.ts +++ b/src/dtos/sms.mo.dto.ts @@ -1,38 +1,54 @@ -import { IsString, ValidateNested, IsNotEmpty, IsDateString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { + IsString, + ValidateNested, + IsNotEmpty, + IsDateString, +} from 'class-validator'; import { Type } from 'class-transformer'; export class InboundSMSMessageDto { + @ApiProperty({ example: '2025-10-30T14:00:00Z' }) @IsDateString() dateTime: string; + @ApiProperty({ example: '+33612345678' }) @IsString() @IsNotEmpty() destinationAddress: string; + @ApiProperty({ example: 'mes1234' }) @IsString() @IsNotEmpty() messageId: string; + @ApiProperty({ + example: 'recipient id %% The content of the message we should send.', + }) @IsString() @IsNotEmpty() message: string; + @ApiProperty({ example: 'acr:token' }) @IsString() @IsNotEmpty() senderAddress: string; } export class InboundSMSMessageNotificationDto { + @ApiProperty({ example: '12345' }) @IsString() @IsNotEmpty() callbackData: string; + @ApiProperty({ type: InboundSMSMessageDto }) @ValidateNested() @Type(() => InboundSMSMessageDto) inboundSMSMessage: InboundSMSMessageDto; } export class InboundSMSMessageNotificationWrapperDto { + @ApiProperty({ type: InboundSMSMessageNotificationDto }) @ValidateNested() @Type(() => InboundSMSMessageNotificationDto) inboundSMSMessageNotification: InboundSMSMessageNotificationDto; diff --git a/src/main.ts b/src/main.ts index 29c5dc3..2067a0f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -16,6 +16,8 @@ async function bootstrap() { .setDescription( 'This is a service dedicated to the reception of callback from external source and sending to rabbitMQ', ) + .addBearerAuth() + .addTag('auth') .setVersion('1.0') .build(); @@ -27,7 +29,7 @@ async function bootstrap() { }); const port = process.env.PORT || 3000; await app.listen(port); - + console.log(`Application is running on: http://localhost:${port}`); console.log(`Swagger docs: http://localhost:${port}/api/docs`); console.log(`Swagger docs: http://localhost:${port}/api/swagger-json`);