From 10b45bd92f132da8d24a7b3b10e72fb43de68879 Mon Sep 17 00:00:00 2001 From: isra el Date: Sat, 20 Apr 2024 01:05:54 +0300 Subject: [PATCH] feat(api): implement an endpoint to retrieve received messages --- api/src/gateway/gateway.controller.ts | 32 +++++++++-- api/src/gateway/gateway.dto.ts | 80 +++++++++++++++++++++++++++ api/src/gateway/gateway.service.ts | 31 ++++++++++- api/src/gateway/schemas/sms.schema.ts | 13 +++-- 4 files changed, 145 insertions(+), 11 deletions(-) diff --git a/api/src/gateway/gateway.controller.ts b/api/src/gateway/gateway.controller.ts index 1275f52..b1e464d 100644 --- a/api/src/gateway/gateway.controller.ts +++ b/api/src/gateway/gateway.controller.ts @@ -11,11 +11,18 @@ import { HttpCode, HttpStatus, } from '@nestjs/common' -import { ApiBearerAuth, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger' +import { + ApiBearerAuth, + ApiOperation, + ApiQuery, + ApiResponse, + ApiTags, +} from '@nestjs/swagger' import { AuthGuard } from '../auth/guards/auth.guard' import { ReceivedSMSDTO, RegisterDeviceInputDTO, + RetrieveSMSResponseDTO, SendSMSInputDTO, } from './gateway.dto' import { GatewayService } from './gateway.service' @@ -112,13 +119,26 @@ export class GatewayController { description: 'Required if jwt bearer token not provided', }) @HttpCode(HttpStatus.OK) - @Post('/devices/:id/receivedSMS') + @Post('/devices/:id/receiveSMS') @UseGuards(AuthGuard, CanModifyDevice) - async receivedSMS( + async receiveSMS(@Param('id') deviceId: string, @Body() dto: ReceivedSMSDTO) { + const data = await this.gatewayService.receiveSMS(deviceId, dto) + return { data } + } + + @ApiOperation({ summary: 'Get received SMS from a device' }) + @ApiQuery({ + name: 'apiKey', + required: false, + description: 'Required if jwt bearer token not provided', + }) + @ApiResponse({ status: 200, type: RetrieveSMSResponseDTO }) + @UseGuards(AuthGuard, CanModifyDevice) + @Get('/devices/:id/getReceivedSMS') + async getReceivedSMS( @Param('id') deviceId: string, - @Body() dto: ReceivedSMSDTO, - ) { - const data = await this.gatewayService.receivedSMS(deviceId, dto) + ): Promise { + const data = await this.gatewayService.getReceivedSMS(deviceId) return { data } } } diff --git a/api/src/gateway/gateway.dto.ts b/api/src/gateway/gateway.dto.ts index cb405b0..ae26d78 100644 --- a/api/src/gateway/gateway.dto.ts +++ b/api/src/gateway/gateway.dto.ts @@ -100,3 +100,83 @@ export class ReceivedSMSDTO { }) receivedAt: Date } + +export class DeviceDTO { + @ApiProperty({ type: String }) + _id: string + + @ApiProperty({ type: Boolean }) + enabled: boolean + + @ApiProperty({ type: String }) + brand: string + + @ApiProperty({ type: String }) + manufacturer: string + + @ApiProperty({ type: String }) + model: string + + @ApiProperty({ type: String }) + buildId: string +} + +export class RetrieveSMSDTO { + @ApiProperty({ + type: String, + required: true, + description: 'The id of the received SMS', + }) + _id: string + + @ApiProperty({ + type: String, + required: true, + description: 'The message received', + }) + message: string + + @ApiProperty({ + type: DeviceDTO, + required: true, + description: 'The device that received the message', + }) + device: DeviceDTO + + @ApiProperty({ + type: String, + required: true, + description: 'The phone number of the sender', + }) + sender: string + + @ApiProperty({ + type: Date, + required: true, + description: 'The time the message was received', + }) + receivedAt: Date + + @ApiProperty({ + type: Date, + required: true, + description: 'The time the message was created', + }) + createdAt: Date + + @ApiProperty({ + type: Date, + required: true, + description: 'The time the message was last updated', + }) + updatedAt: Date +} + +export class RetrieveSMSResponseDTO { + @ApiProperty({ + type: [RetrieveSMSDTO], + required: true, + description: 'The received SMS data', + }) + data: RetrieveSMSDTO[] +} diff --git a/api/src/gateway/gateway.service.ts b/api/src/gateway/gateway.service.ts index 6935383..4574569 100644 --- a/api/src/gateway/gateway.service.ts +++ b/api/src/gateway/gateway.service.ts @@ -6,6 +6,7 @@ import * as firebaseAdmin from 'firebase-admin' import { ReceivedSMSDTO, RegisterDeviceInputDTO, + RetrieveSMSDTO, SendSMSInputDTO, } from './gateway.dto' import { User } from '../users/schemas/user.schema' @@ -137,7 +138,7 @@ export class GatewayService { } } - async receivedSMS(deviceId: string, dto: ReceivedSMSDTO): Promise { + async receiveSMS(deviceId: string, dto: ReceivedSMSDTO): Promise { const device = await this.deviceModel.findById(deviceId) if (!device) { @@ -173,6 +174,34 @@ export class GatewayService { return sms } + async getReceivedSMS(deviceId: string): Promise { + const device = await this.deviceModel.findById(deviceId) + + if (!device) { + throw new HttpException( + { + success: false, + error: 'Device does not exist', + }, + HttpStatus.BAD_REQUEST, + ) + } + + return await this.smsModel + .find( + { + device: device._id, + type: SMSType.RECEIVED, + }, + null, + { sort: { receivedAt: -1 }, limit: 200 }, + ) + .populate({ + path: 'device', + select: '_id brand model buildId enabled', + }) + } + async getStatsForUser(user: User) { const devices = await this.deviceModel.find({ user: user._id }) const apiKeys = await this.authService.getUserApiKeys(user) diff --git a/api/src/gateway/schemas/sms.schema.ts b/api/src/gateway/schemas/sms.schema.ts index 348c8f3..2cdf304 100644 --- a/api/src/gateway/schemas/sms.schema.ts +++ b/api/src/gateway/schemas/sms.schema.ts @@ -1,7 +1,6 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose' import { Document, Types } from 'mongoose' import { Device } from './device.schema' -import { SMSType } from '../sms-type.enum' export type SMSDocument = SMS & Document @@ -12,9 +11,15 @@ export class SMS { @Prop({ type: Types.ObjectId, ref: Device.name, required: true }) device: Device - @Prop({ type: String, required: true }) + @Prop({ type: String }) message: string + @Prop({ type: Boolean, default: false }) + encrypted: boolean + + @Prop({ type: String }) + encryptedMessage: string + @Prop({ type: String, required: true }) type: string @@ -22,14 +27,14 @@ export class SMS { @Prop({ type: String }) sender: string - @Prop({ type: Date, default: Date.now }) + @Prop({ type: Date }) receivedAt: Date // fields for outgoing messages @Prop({ type: String }) recipient: string - @Prop({ type: Date, default: Date.now }) + @Prop({ type: Date }) requestedAt: Date @Prop({ type: Date })