import { BadRequestException, Body, Controller, Delete, Get, Param, ParseIntPipe, Post, UploadedFile, UseGuards, UseInterceptors, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { diskStorage } from 'multer'; import { extname } from 'path'; import { randomBytes } from 'crypto'; import { PhotosService } from './photos.service'; import { uploadDir } from './uploads'; import { CurrentUser, JwtAuthGuard, Roles, RolesGuard, type JwtPayload, } from '../auth/roles'; const ALLOWED = /\.(jpe?g|png|webp|gif)$/i; const storage = diskStorage({ destination: (_req, _file, cb) => cb(null, uploadDir()), filename: (_req, file, cb) => cb(null, `${Date.now()}-${randomBytes(6).toString('hex')}${extname(file.originalname).toLowerCase()}`), }); @Controller('api') export class PhotosController { constructor(private readonly photos: PhotosService) {} /** 公共图库:某车型的全部照片(所有人可看)。*/ @Get('models/:id/photos') list(@Param('id', ParseIntPipe) id: number) { return this.photos.listForModel(id); } /** 管理员候选审图:全站待确认照片。*/ @Get('photos/candidates') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') candidates() { return this.photos.listCandidates(); } /** 管理员上传到共享图库。*/ @Post('models/:id/photos') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') @UseInterceptors( FileInterceptor('file', { storage, limits: { fileSize: 8 * 1024 * 1024 }, fileFilter: (_req, file, cb) => ALLOWED.test(file.originalname) ? cb(null, true) : cb(new BadRequestException('仅支持 jpg/png/webp/gif'), false), }), ) upload( @Param('id', ParseIntPipe) id: number, @UploadedFile() file: Express.Multer.File, @Body('caption') caption: string, @CurrentUser() user: JwtPayload, ) { if (!file) throw new BadRequestException('未收到文件'); return this.photos.add(id, user.sub, file.filename, { caption: caption ?? '', status: 'confirmed', }); } @Post('photos/:pid/confirm') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') confirm(@Param('pid', ParseIntPipe) pid: number) { return this.photos.confirm(pid); } @Post('photos/:pid/feature') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') feature(@Param('pid', ParseIntPipe) pid: number) { return this.photos.setFeatured(pid); } @Delete('photos/:pid') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') remove(@Param('pid', ParseIntPipe) pid: number) { return this.photos.remove(pid); } }