139 lines
5.0 KiB
TypeScript
139 lines
5.0 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Get,
|
|
Param,
|
|
ParseUUIDPipe,
|
|
Post,
|
|
Put,
|
|
Req,
|
|
Res,
|
|
UploadedFile,
|
|
UseInterceptors,
|
|
} from '@nestjs/common';
|
|
import { FileInterceptor } 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 { CloseInspectionActDto } from './dto/close-inspection-act.dto';
|
|
import { CreateCompanyOutcomeDto } from './dto/create-company-outcome.dto';
|
|
import { CreateInspectionSignatureDto } from './dto/create-inspection-signature.dto';
|
|
import { CreateCompanySignatureDto } from './dto/create-company-signature.dto';
|
|
import { UpsertInspectionResponsibleDto } from './dto/upsert-inspection-responsible.dto';
|
|
import { InspectionClosingService } from './inspection-closing.service';
|
|
import {
|
|
MAX_INSPECTION_SIGNATURE_BYTES,
|
|
type UploadedInspectionSignatureFile,
|
|
} from './inspection-signature-file';
|
|
|
|
@Controller('inspection-acts/:actId')
|
|
export class InspectionClosingController {
|
|
constructor(private readonly closing: InspectionClosingService) {}
|
|
|
|
@Get('closure')
|
|
@RequirePermissions('inspection_closure.read')
|
|
get(@Param('actId', new ParseUUIDPipe({ version: '4' })) actId: string) {
|
|
return this.closing.get(actId);
|
|
}
|
|
|
|
@Put('responsible')
|
|
@RequirePermissions('inspection_closure.prepare')
|
|
responsible(
|
|
@Param('actId', new ParseUUIDPipe({ version: '4' })) actId: string,
|
|
@Body() dto: UpsertInspectionResponsibleDto,
|
|
@CurrentAuth() principal: AuthPrincipal,
|
|
@Req() request: RequestWithContext,
|
|
) {
|
|
return this.closing.upsertResponsible(actId, dto, principal, request);
|
|
}
|
|
|
|
@Post('lock')
|
|
@RequirePermissions('inspection_closure.prepare')
|
|
lock(
|
|
@Param('actId', new ParseUUIDPipe({ version: '4' })) actId: string,
|
|
@CurrentAuth() principal: AuthPrincipal,
|
|
@Req() request: RequestWithContext,
|
|
) {
|
|
return this.closing.prepare(actId, principal, request);
|
|
}
|
|
|
|
@Post('signatures/inspector')
|
|
@RequirePermissions('inspection_closure.sign')
|
|
@UseInterceptors(FileInterceptor('file', {
|
|
limits: { fileSize: MAX_INSPECTION_SIGNATURE_BYTES, files: 1 },
|
|
}))
|
|
inspectorSignature(
|
|
@Param('actId', new ParseUUIDPipe({ version: '4' })) actId: string,
|
|
@Body() dto: CreateInspectionSignatureDto,
|
|
@UploadedFile() file: UploadedInspectionSignatureFile | undefined,
|
|
@CurrentAuth() principal: AuthPrincipal,
|
|
@Req() request: RequestWithContext,
|
|
) {
|
|
return this.closing.signInspector(actId, dto, file, principal, request);
|
|
}
|
|
|
|
@Post('signatures/company')
|
|
@RequirePermissions('inspection_closure.sign')
|
|
@UseInterceptors(FileInterceptor('file', {
|
|
limits: { fileSize: MAX_INSPECTION_SIGNATURE_BYTES, files: 1 },
|
|
}))
|
|
companySignature(
|
|
@Param('actId', new ParseUUIDPipe({ version: '4' })) actId: string,
|
|
@Body() dto: CreateCompanySignatureDto,
|
|
@UploadedFile() file: UploadedInspectionSignatureFile | undefined,
|
|
@CurrentAuth() principal: AuthPrincipal,
|
|
@Req() request: RequestWithContext,
|
|
) {
|
|
return this.closing.signCompany(actId, dto, file, principal, request);
|
|
}
|
|
|
|
@Post('company-outcome')
|
|
@RequirePermissions('inspection_closure.sign')
|
|
companyOutcome(
|
|
@Param('actId', new ParseUUIDPipe({ version: '4' })) actId: string,
|
|
@Body() dto: CreateCompanyOutcomeDto,
|
|
@CurrentAuth() principal: AuthPrincipal,
|
|
@Req() request: RequestWithContext,
|
|
) {
|
|
return this.closing.recordCompanyOutcome(actId, dto, principal, request);
|
|
}
|
|
|
|
@Post('seal')
|
|
@RequirePermissions('inspection_closure.close')
|
|
seal(
|
|
@Param('actId', new ParseUUIDPipe({ version: '4' })) actId: string,
|
|
@Body() dto: CloseInspectionActDto,
|
|
@CurrentAuth() principal: AuthPrincipal,
|
|
@Req() request: RequestWithContext,
|
|
) {
|
|
return this.closing.close(actId, dto, principal, request);
|
|
}
|
|
}
|
|
|
|
@Controller('inspection-act-signatures')
|
|
export class InspectionSignatureContentController {
|
|
constructor(private readonly closing: InspectionClosingService) {}
|
|
|
|
@Get(':signatureId/content')
|
|
@RequirePermissions('inspection_closure.read')
|
|
async content(
|
|
@Param('signatureId', new ParseUUIDPipe({ version: '4' })) signatureId: string,
|
|
@Res() response: Response,
|
|
): Promise<void> {
|
|
const { filePath, signature } = await this.closing.signatureContent(signatureId);
|
|
response.setHeader('Content-Type', 'image/png');
|
|
response.setHeader('Content-Length', String(signature.sizeBytes));
|
|
response.setHeader('Content-Disposition', 'inline; filename="firma.png"');
|
|
response.setHeader('Cache-Control', 'private, no-store');
|
|
response.setHeader('X-Content-Type-Options', 'nosniff');
|
|
response.setHeader('Content-Security-Policy', "sandbox; default-src 'none'");
|
|
await new Promise<void>((resolveSend, rejectSend) => {
|
|
response.sendFile(filePath, (error) => {
|
|
if (error) rejectSend(error);
|
|
else resolveSend();
|
|
});
|
|
});
|
|
}
|
|
}
|