80 lines
2.9 KiB
TypeScript
80 lines
2.9 KiB
TypeScript
import {
|
|||
|
|
Controller,
|
||
|
|
HttpCode,
|
||
|
|
Post,
|
||
|
|
UploadedFile,
|
||
|
|
UseInterceptors,
|
||
|
|
} from '@nestjs/common';
|
||
|
|
import { Body } from '@nestjs/common';
|
||
|
|
import { FileInterceptor } from '@nestjs/platform-express';
|
||
|
|
import { CustomerProfileService } from './customer-profile.service';
|
||
|
|
import { AdminUploadsService } from '../admin-uploads/admin-uploads.service';
|
||
|
|
import { CompleteProfileDto } from './dto/complete-profile.dto';
|
||
|
|
import { CurrentCustomer, CustomerAuth } from '../customer-auth/customer.guards';
|
||
|
|
import type { AuthenticatedCustomer } from '../customer-auth/customer-jwt.strategy';
|
||
|
|
|
||
|
|
/** See AdminUploadsController — the same locally-declared multer subset. */
|
||
|
|
interface UploadedMulterFile {
|
||
|
|
originalname: string;
|
||
|
|
mimetype: string;
|
||
|
|
size: number;
|
||
|
|
buffer: Buffer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The customer's own profile writes.
|
||
|
|
*
|
||
|
|
* Legacy endpoints:
|
||
|
|
* POST file/create -> the PWA's SingleImageUploader posted here with the
|
||
|
|
* customer token (routes/api.php:95, inside the
|
||
|
|
* `auth:api-customer` group)
|
||
|
|
* POST major/complete -> Major\CustomerController::complete
|
||
|
|
* (routes/api.php:114)
|
||
|
|
*
|
||
|
|
* Both are mounted under /customer/me here so the customer surface stays in one
|
||
|
|
* place. The subject always comes from the token — no id is accepted from the
|
||
|
|
* client, per D21.
|
||
|
|
*/
|
||
|
|
@Controller('customer/me')
|
||
|
|
export class CustomerProfileController {
|
||
|
|
constructor(
|
||
|
|
private readonly profile: CustomerProfileService,
|
||
|
|
private readonly uploads: AdminUploadsService,
|
||
|
|
) {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* A customer uploading one of their own documents.
|
||
|
|
*
|
||
|
|
* The reference let the app upload through the very same `file/create` the
|
||
|
|
* admin panel used, behind the customer guard (routes/api.php:95). The
|
||
|
|
* target's copy of that route sits behind an ADMIN guard
|
||
|
|
* (AdminUploadsController), which no app token can pass — so without this
|
||
|
|
* route the page could not upload at all.
|
||
|
|
*
|
||
|
|
* It reuses AdminUploadsService unchanged, so the size limit, the MIME
|
||
|
|
* whitelist and the stored-name scheme are identical on both paths. The
|
||
|
|
* uploader is recorded as null rather than as an admin, because
|
||
|
|
* `UploadedFile.uploadedByAdminUserId` is an AdminUser FK and this caller is
|
||
|
|
* a customer; `purpose` carries the document kind instead.
|
||
|
|
*/
|
||
|
|
@CustomerAuth()
|
||
|
|
@Post('documents')
|
||
|
|
@HttpCode(200)
|
||
|
|
@UseInterceptors(FileInterceptor('file'))
|
||
|
|
upload(
|
||
|
|
@UploadedFile() file: UploadedMulterFile | undefined,
|
||
|
|
@Body('purpose') purpose: string | undefined,
|
||
|
|
@CurrentCustomer() _me: AuthenticatedCustomer,
|
||
|
|
) {
|
||
|
|
return this.uploads.store(file, purpose ?? 'customer-document', null);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Ports POST major/complete. The customer is the token's. */
|
||
|
|
@CustomerAuth()
|
||
|
|
@Post('complete-profile')
|
||
|
|
@HttpCode(200)
|
||
|
|
complete(@Body() dto: CompleteProfileDto, @CurrentCustomer() me: AuthenticatedCustomer) {
|
||
|
|
return this.profile.complete(me.id, dto);
|
||
|
|
}
|
||
|
|
}
|