Skip to content

Commit b3c492a

Browse files
committed
POST /api/reports
1 parent 495525a commit b3c492a

File tree

3 files changed

+107
-9
lines changed

3 files changed

+107
-9
lines changed

backend/src/reports/models/report.model.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,40 @@ export class Report {
99
@ApiProperty({ description: 'Unique identifier for the report' })
1010
id: string;
1111

12+
@ApiProperty({ description: 'User ID of the report owner' })
13+
userId: string;
14+
1215
@ApiProperty({ description: 'Title of the report' })
1316
title: string;
1417

15-
@ApiProperty({ description: 'Content of the report' })
16-
content: string;
18+
@ApiProperty({ description: 'Whether the report is bookmarked' })
19+
bookmark: boolean;
1720

18-
@ApiProperty({ description: 'User ID of the report owner' })
19-
userId: string;
21+
@ApiProperty({ description: 'Category of the report' })
22+
category: string;
2023

21-
@ApiProperty({ description: 'Creation timestamp' })
22-
createdAt: string;
24+
@ApiProperty({ description: 'Date of the report' })
25+
date: string;
2326

24-
@ApiProperty({ description: 'Last update timestamp' })
25-
updatedAt: string;
27+
@ApiProperty({ description: 'Doctor associated with the report' })
28+
doctor: string;
29+
30+
@ApiProperty({ description: 'Facility where the report was created' })
31+
facility: string;
2632

2733
@ApiProperty({
2834
description: 'Status of the report',
2935
enum: ReportStatus,
3036
default: ReportStatus.UNREAD,
3137
})
3238
status: ReportStatus;
39+
40+
@ApiProperty({ description: 'File URL of the report' })
41+
fileUrl: string;
42+
43+
@ApiProperty({ description: 'Creation timestamp' })
44+
createdAt: string;
45+
46+
@ApiProperty({ description: 'Last update timestamp' })
47+
updatedAt: string;
3348
}

backend/src/reports/reports.controller.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
ValidationPipe,
99
Req,
1010
UnauthorizedException,
11+
Post,
1112
} from '@nestjs/common';
1213
import {
1314
ApiTags,
@@ -16,6 +17,7 @@ import {
1617
ApiBearerAuth,
1718
ApiParam,
1819
ApiQuery,
20+
ApiBody,
1921
} from '@nestjs/swagger';
2022
import { ReportsService } from './reports.service';
2123
import { Report } from './models/report.model';
@@ -105,6 +107,34 @@ export class ReportsController {
105107
return this.reportsService.updateStatus(id, updateDto, userId);
106108
}
107109

110+
@ApiOperation({ summary: 'Create a new report from S3 file' })
111+
@ApiResponse({
112+
status: 201,
113+
description: 'Report created successfully',
114+
type: Report,
115+
})
116+
@ApiBody({
117+
schema: {
118+
type: 'object',
119+
properties: {
120+
fileUrl: {
121+
type: 'string',
122+
description: 'S3 file URL for the report',
123+
},
124+
},
125+
required: ['fileUrl'],
126+
},
127+
description: 'S3 file URL for the report',
128+
})
129+
@Post()
130+
async createReport(
131+
@Body('fileUrl') fileUrl: string,
132+
@Req() request: RequestWithUser,
133+
): Promise<Report> {
134+
const userId = this.extractUserId(request);
135+
return this.reportsService.saveReport(fileUrl, userId);
136+
}
137+
108138
private extractUserId(request: RequestWithUser): string {
109139
// The user object is attached to the request by our middleware
110140
const user = request.user;

backend/src/reports/reports.service.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import {
1212
GetItemCommand,
1313
UpdateItemCommand,
1414
DynamoDBServiceException,
15+
PutItemCommand,
1516
} from '@aws-sdk/client-dynamodb';
1617
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';
17-
import { Report } from './models/report.model';
18+
import { Report, ReportStatus } from './models/report.model';
1819
import { GetReportsQueryDto } from './dto/get-reports.dto';
1920
import { UpdateReportStatusDto } from './dto/update-report-status.dto';
21+
import { v4 as uuidv4 } from 'uuid';
2022

2123
@Injectable()
2224
export class ReportsService {
@@ -250,4 +252,55 @@ export class ReportsService {
250252
throw new InternalServerErrorException(`Failed to update report status for ID ${id}`);
251253
}
252254
}
255+
256+
async saveReport(fileUrl: string, userId: string): Promise<Report> {
257+
if (!fileUrl) {
258+
throw new NotFoundException('File URL is required');
259+
}
260+
261+
if (!userId) {
262+
throw new ForbiddenException('User ID is required');
263+
}
264+
265+
try {
266+
const newReport: Report = {
267+
id: uuidv4(),
268+
userId,
269+
fileUrl,
270+
title: 'New Report',
271+
bookmark: false,
272+
category: '',
273+
date: '',
274+
doctor: '',
275+
facility: '',
276+
status: ReportStatus.UNREAD,
277+
createdAt: new Date().toISOString(),
278+
updatedAt: new Date().toISOString(),
279+
};
280+
281+
// Save to DynamoDB
282+
const command = new PutItemCommand({
283+
TableName: this.tableName,
284+
Item: marshall(newReport),
285+
});
286+
287+
await this.dynamoClient.send(command);
288+
this.logger.log(`Successfully saved report with ID ${newReport.id} for user ${userId}`);
289+
290+
return newReport;
291+
} catch (error: unknown) {
292+
this.logger.error(`Error saving report for user ${userId}:`);
293+
this.logger.error(error);
294+
295+
if (error instanceof DynamoDBServiceException) {
296+
if (error.name === 'ResourceNotFoundException') {
297+
throw new InternalServerErrorException(
298+
`Table "${this.tableName}" not found. Please check your database configuration.`,
299+
);
300+
}
301+
}
302+
303+
throw new InternalServerErrorException('Failed to save report to database');
304+
}
305+
}
253306
}

0 commit comments

Comments
 (0)