import { Body, Controller, Get, Param, ParseUUIDPipe, Patch, Post, Req, Res, UploadedFile, UploadedFiles, UseInterceptors, } from '@nestjs/common'; import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express'; import type { Response } from 'express'; import { CurrentAuth } from '../auth/decorators/current-auth.decorator'; import { RequirePermissions } from '../authorization/decorators/require-permissions.decorator'; import type { AuthPrincipal, RequestWithContext } from '../common/http/request-context'; import { CreateInspectionReportFollowUpDto } from './dto/create-inspection-report-follow-up.dto'; import { OfficializeInspectionReportGedoDto } from './dto/officialize-inspection-report-gedo.dto'; import { UpdateInspectionReportContentDto } from './dto/update-inspection-report-content.dto'; import { MAX_REPORT_DOSSIER_PDF_BYTES, type UploadedReportDossierFile, } from './inspection-report-dossier-file'; import { InspectionReportDossierService } from './inspection-report-dossier.service'; @Controller('inspection-reports/:reportId/dossier') export class InspectionReportDossierController { constructor(private readonly dossier: InspectionReportDossierService) {} @Get() @RequirePermissions('inspection_reports.read') get(@Param('reportId', new ParseUUIDPipe({ version: '4' })) reportId: string) { return this.dossier.get(reportId); } @Patch('content') @RequirePermissions('inspection_reports.edit') updateContent( @Param('reportId', new ParseUUIDPipe({ version: '4' })) reportId: string, @Body() dto: UpdateInspectionReportContentDto, @CurrentAuth() principal: AuthPrincipal, @Req() request: RequestWithContext, ) { return this.dossier.updateContent(reportId, dto, principal, request); } @Post('gedo') @RequirePermissions('inspection_reports.officialize') @UseInterceptors(FileInterceptor('file', { limits: { fileSize: MAX_REPORT_DOSSIER_PDF_BYTES, files: 1 }, })) officializeGedo( @Param('reportId', new ParseUUIDPipe({ version: '4' })) reportId: string, @Body() dto: OfficializeInspectionReportGedoDto, @UploadedFile() file: UploadedReportDossierFile | undefined, @CurrentAuth() principal: AuthPrincipal, @Req() request: RequestWithContext, ) { return this.dossier.officializeGedo(reportId, dto, file, principal, request); } @Get('gedo/pdf') @RequirePermissions('inspection_reports.read') async gedoPdf( @Param('reportId', new ParseUUIDPipe({ version: '4' })) reportId: string, @Res() response: Response, ): Promise { const content = await this.dossier.gedoPdfContent(reportId); response.setHeader('Content-Type', 'application/pdf'); response.setHeader('Content-Disposition', `attachment; filename="${content.originalName.replaceAll('"', '')}"`); response.setHeader('Cache-Control', 'private, no-store'); response.setHeader('X-Content-Type-Options', 'nosniff'); await new Promise((resolveSend, rejectSend) => { response.sendFile(content.filePath, (error) => { if (error) rejectSend(error); else resolveSend(); }); }); } @Get('follow-ups') @RequirePermissions('inspection_reports.read') followUps(@Param('reportId', new ParseUUIDPipe({ version: '4' })) reportId: string) { return this.dossier.listFollowUps(reportId); } @Post('follow-ups') @RequirePermissions('inspection_reports.follow_up') @UseInterceptors(FilesInterceptor('files', 10, { limits: { fileSize: MAX_REPORT_DOSSIER_PDF_BYTES, files: 10 }, })) createFollowUp( @Param('reportId', new ParseUUIDPipe({ version: '4' })) reportId: string, @Body() dto: CreateInspectionReportFollowUpDto, @UploadedFiles() files: UploadedReportDossierFile[] | undefined, @CurrentAuth() principal: AuthPrincipal, @Req() request: RequestWithContext, ) { return this.dossier.createFollowUp(reportId, dto, files ?? [], principal, request); } } @Controller('inspection-report-follow-up-files') export class InspectionReportFollowUpFileController { constructor(private readonly dossier: InspectionReportDossierService) {} @Get(':fileId/content') @RequirePermissions('inspection_reports.read') async content( @Param('fileId', new ParseUUIDPipe({ version: '4' })) fileId: string, @Res() response: Response, ): Promise { const content = await this.dossier.followUpFileContent(fileId); response.setHeader('Content-Type', 'application/pdf'); response.setHeader('Content-Disposition', `attachment; filename="${content.originalName.replaceAll('"', '')}"`); response.setHeader('Cache-Control', 'private, no-store'); response.setHeader('X-Content-Type-Options', 'nosniff'); await new Promise((resolveSend, rejectSend) => { response.sendFile(content.filePath, (error) => { if (error) rejectSend(error); else resolveSend(); }); }); } }