102 lines
2.6 KiB
TypeScript
102 lines
2.6 KiB
TypeScript
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);
|
|
}
|
|
}
|