From 343dbe086f889538c741ccdd573d9dd9ff5c12fd Mon Sep 17 00:00:00 2001 From: enlineawork Date: Mon, 7 Sep 2026 21:38:40 -0300 Subject: [PATCH] F4: expose secure remote company signature endpoints --- .../company-signature-invite.controller.ts | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 api-v3/src/inspection-closing/company-signature-invite.controller.ts diff --git a/api-v3/src/inspection-closing/company-signature-invite.controller.ts b/api-v3/src/inspection-closing/company-signature-invite.controller.ts new file mode 100644 index 0000000..d1a4b93 --- /dev/null +++ b/api-v3/src/inspection-closing/company-signature-invite.controller.ts @@ -0,0 +1,77 @@ +import { + Body, + Controller, + Get, + Param, + ParseUUIDPipe, + Post, + Req, + UploadedFile, + UseInterceptors, +} from '@nestjs/common'; +import { FileInterceptor } from '@nestjs/platform-express'; +import { CurrentAuth } from '../auth/decorators/current-auth.decorator'; +import { Public } from '../auth/decorators/public.decorator'; +import { SkipCsrf } from '../auth/decorators/skip-csrf.decorator'; +import { RequirePermissions } from '../authorization/decorators/require-permissions.decorator'; +import type { AuthPrincipal, RequestWithContext } from '../common/http/request-context'; +import { CompanySignatureInviteService } from './company-signature-invite.service'; +import { + CreateCompanySignatureInviteDto, + PublicCompanyRefusalDto, + PublicCompanySignatureDto, +} from './dto/company-signature-invite.dto'; +import { + MAX_INSPECTION_SIGNATURE_BYTES, + type UploadedInspectionSignatureFile, +} from './inspection-signature-file'; + +@Controller('inspection-acts/:actId/company-signature-invitations') +export class CompanySignatureInviteController { + constructor(private readonly invites: CompanySignatureInviteService) {} + + @Post() + @RequirePermissions('inspection_closure.sign') + create( + @Param('actId', new ParseUUIDPipe({ version: '4' })) actId: string, + @Body() dto: CreateCompanySignatureInviteDto, + @CurrentAuth() principal: AuthPrincipal, + @Req() request: RequestWithContext, + ) { + return this.invites.create(actId, dto, principal, request); + } +} + +@Public() +@SkipCsrf() +@Controller('public/company-signatures') +export class PublicCompanySignatureController { + constructor(private readonly invites: CompanySignatureInviteService) {} + + @Get(':token') + view(@Param('token') token: string) { + return this.invites.view(token); + } + + @Post(':token/sign') + @UseInterceptors(FileInterceptor('file', { + limits: { fileSize: MAX_INSPECTION_SIGNATURE_BYTES, files: 1 }, + })) + sign( + @Param('token') token: string, + @Body() dto: PublicCompanySignatureDto, + @UploadedFile() file: UploadedInspectionSignatureFile | undefined, + @Req() request: RequestWithContext, + ) { + return this.invites.sign(token, dto, file, request); + } + + @Post(':token/refuse') + refuse( + @Param('token') token: string, + @Body() dto: PublicCompanyRefusalDto, + @Req() request: RequestWithContext, + ) { + return this.invites.refuse(token, dto, request); + } +}