import { Body, Controller, Get, Param, Patch, Post, Put, Query, Req, Res, UploadedFiles, UseGuards, UseInterceptors, } from '@nestjs/common'; import { FilesInterceptor } from '@nestjs/platform-express'; import { memoryStorage } from 'multer'; import type { Response } from 'express'; import { ApiBearerAuth, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger'; import { LabOrgGuard } from '../../common/guards/lab-org.guard'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { CasesService } from './cases.service'; import { ListLabCasesDto, UpdateLabCaseImportantDto, UpdateLabCaseExternalCodeDto, AssignLabCaseTaskDto, CreateLabInternalCaseDto, UpdateLabInternalCaseDto, } from './dto/cases.dto'; @ApiTags('cases') @ApiBearerAuth('JWT-auth') @UseGuards(JwtAuthGuard, LabOrgGuard) @Controller('cases') export class CasesController { constructor(private readonly casesService: CasesService) {} @Get() @ApiOperation({ summary: 'List lab cases received by this organization' }) list(@Query() query: ListLabCasesDto, @Req() req) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.list(organizationId, req.user.id, query); } @Post() @ApiOperation({ summary: 'Create a lab-origin draft case (TAB_CASES_EDIT)' }) create(@Body() dto: CreateLabInternalCaseDto, @Req() req) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.createInternal(dto, organizationId, req.user.id, req.user.language); } @Get('assignable-staff') @ApiOperation({ summary: 'Staff who can be assigned lab tasks' }) listAssignableStaff(@Req() req) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.listAssignableStaff(organizationId, req.user.id); } @Get('filter-options') @ApiOperation({ summary: 'Clinics and treatment types for inbox filters' }) listFilterOptions(@Req() req) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.listFilterOptions(organizationId, req.user.id); } @Get('linked-clinics') @ApiOperation({ summary: 'Active linked clinic organizations for lab-origin cases' }) listLinkedClinics(@Req() req) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.listLinkedClinics(organizationId, req.user.id); } @Get(':id') @ApiOperation({ summary: 'Get one lab case with tasks grouped by tooth' }) getOne(@Param('id') id: string, @Req() req) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.getOne(id, organizationId, req.user.id, req.user.language); } @Put(':id') @ApiOperation({ summary: 'Update a lab-origin draft case and its lines' }) update(@Param('id') id: string, @Body() dto: UpdateLabInternalCaseDto, @Req() req) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.updateInternal(id, dto, organizationId, req.user.id, req.user.language); } @Post(':id/start') @ApiOperation({ summary: 'Start a lab-origin draft (generate tasks, no clinic notify)' }) start(@Param('id') id: string, @Req() req) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.startInternal(id, organizationId, req.user.id, req.user.language); } @Post(':id/lines/:lineClientKey/attachments') @ApiOperation({ summary: 'Upload attachments for a lab-origin draft line' }) @ApiConsumes('multipart/form-data') @UseInterceptors( FilesInterceptor('files', 20, { storage: memoryStorage(), }), ) uploadAttachments( @Param('id') id: string, @Param('lineClientKey') lineClientKey: string, @UploadedFiles() files: Express.Multer.File[], @Req() req, ) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.uploadInternalAttachments( id, lineClientKey, files, organizationId, req.user.id, ); } @Get(':id/attachments/:attachmentId/file') @ApiOperation({ summary: 'Download an attachment shared with this lab case' }) async downloadAttachment( @Param('id') id: string, @Param('attachmentId') attachmentId: string, @Req() req, @Res() res: Response, ) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); const file = await this.casesService.streamCaseAttachment( id, attachmentId, organizationId, req.user.id, ); res.setHeader('Content-Type', file.mimeType); res.setHeader('Content-Disposition', `inline; filename="${file.fileName}"`); file.stream.pipe(res); } @Patch(':id/important') @ApiOperation({ summary: 'Toggle the important flag for a whole case' }) setCaseImportant( @Param('id') id: string, @Body() dto: UpdateLabCaseImportantDto, @Req() req, ) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.setCaseImportant(id, dto, organizationId, req.user.id, req.user.language); } @Patch(':id/external-code') @ApiOperation({ summary: 'Set or clear the optional external order code for a case' }) setCaseExternalCode( @Param('id') id: string, @Body() dto: UpdateLabCaseExternalCodeDto, @Req() req, ) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.setCaseExternalCode(id, dto, organizationId, req.user.id, req.user.language); } @Patch(':caseId/tasks/:taskId/assign') @ApiOperation({ summary: 'Assign or unassign a task to lab staff' }) assignTask( @Param('caseId') caseId: string, @Param('taskId') taskId: string, @Body() dto: AssignLabCaseTaskDto, @Req() req, ) { const organizationId = this.casesService.getOrganizationIdFromUser(req.user); return this.casesService.assignTask( caseId, taskId, dto, organizationId, req.user.id, req.user.language, ); } }