2026-09-17 23:00:19 +08:00
|
|
|
|
// services/api/src/uploads/uploads.controller.ts —— /uploads 端点(Task 18 起;
|
2026-09-28 18:56:07 +08:00
|
|
|
|
// Task 19 增补 listUploads/renewUploadCredential/completeUpload;查重预检
|
|
|
|
|
|
// checkUploadDuplicates 为「上传查重前置到入队前」Task 1 增补)。方法名与契约
|
2026-09-17 23:00:19 +08:00
|
|
|
|
// operationId 一一对应。控制器级 SessionGuard:端点全需认证。职责:透传认证
|
2026-09-18 08:18:30 +08:00
|
|
|
|
// 用户 + 查询参数规整(parseLimit/parseCursor 用 shared/pagination,同契约 bounds)。
|
2026-09-17 23:00:19 +08:00
|
|
|
|
// 注意 DTO 必须值导入(非 import type):@Body 参数类型经 emitDecoratorMetadata
|
|
|
|
|
|
// 进入设计期元数据,import type 会令参数在管线中被置为 undefined(Task 18 实测)。
|
2026-09-17 22:42:13 +08:00
|
|
|
|
import {
|
|
|
|
|
|
Body,
|
|
|
|
|
|
Controller,
|
2026-09-17 23:00:19 +08:00
|
|
|
|
Get,
|
|
|
|
|
|
HttpCode,
|
|
|
|
|
|
HttpStatus,
|
|
|
|
|
|
Param,
|
2026-09-17 22:42:13 +08:00
|
|
|
|
Post,
|
2026-09-17 23:00:19 +08:00
|
|
|
|
Query,
|
2026-09-17 22:42:13 +08:00
|
|
|
|
Req,
|
|
|
|
|
|
UseGuards,
|
|
|
|
|
|
} from '@nestjs/common';
|
2026-09-18 08:18:30 +08:00
|
|
|
|
import { userOf } from '../albums/albums.controller';
|
|
|
|
|
|
import { parseCursor, parseLimit } from '../shared/pagination';
|
2026-09-17 22:42:13 +08:00
|
|
|
|
import { AuthenticatedRequest, SessionGuard } from '../auth/session.guard';
|
|
|
|
|
|
import { UploadsService } from './uploads.service';
|
2026-09-17 23:00:19 +08:00
|
|
|
|
import type {
|
|
|
|
|
|
UploadCompleteResponse,
|
2026-09-28 18:56:07 +08:00
|
|
|
|
UploadDuplicateCheckResponse,
|
2026-09-17 23:00:19 +08:00
|
|
|
|
UploadInitResponse,
|
|
|
|
|
|
UploadSessionListResponse,
|
|
|
|
|
|
} from './uploads.service';
|
2026-09-28 18:56:07 +08:00
|
|
|
|
import { UploadInitRequestDto, DuplicateCheckRequestDto } from './dto';
|
2026-09-17 22:42:13 +08:00
|
|
|
|
|
|
|
|
|
|
@Controller('uploads')
|
|
|
|
|
|
@UseGuards(SessionGuard)
|
|
|
|
|
|
export class UploadsController {
|
|
|
|
|
|
constructor(private readonly uploadsService: UploadsService) {}
|
|
|
|
|
|
|
|
|
|
|
|
/** 契约 201(幂等重复调用返回原会话,同 201)。 */
|
|
|
|
|
|
@Post()
|
|
|
|
|
|
initUpload(
|
|
|
|
|
|
@Body() dto: UploadInitRequestDto,
|
|
|
|
|
|
@Req() req: AuthenticatedRequest,
|
|
|
|
|
|
): Promise<UploadInitResponse> {
|
|
|
|
|
|
return this.uploadsService.init(userOf(req), dto);
|
|
|
|
|
|
}
|
2026-09-17 23:00:19 +08:00
|
|
|
|
|
|
|
|
|
|
/** 上传历史:当前用户自己的会话,新在前,(createdAt,id) 键集游标。 */
|
|
|
|
|
|
@Get()
|
|
|
|
|
|
listUploads(
|
|
|
|
|
|
@Query('cursor') cursor: string | undefined,
|
|
|
|
|
|
@Query('limit') limit: string | undefined,
|
|
|
|
|
|
@Req() req: AuthenticatedRequest,
|
|
|
|
|
|
): Promise<UploadSessionListResponse> {
|
|
|
|
|
|
return this.uploadsService.list(
|
|
|
|
|
|
userOf(req),
|
|
|
|
|
|
parseCursor(cursor),
|
|
|
|
|
|
parseLimit(limit),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-28 18:56:07 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 查重预检(只读批量):判定谓词与 init ③.5 服务端查重逐字一致(见 service
|
|
|
|
|
|
* checkDuplicates)。声明于 :uploadId 参数路由之前(静态段路由,无实际冲突,
|
|
|
|
|
|
* 仅保持「具体路径先于参数路径」的可读惯例)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Post('duplicates/check')
|
|
|
|
|
|
@HttpCode(HttpStatus.OK)
|
|
|
|
|
|
checkUploadDuplicates(
|
|
|
|
|
|
@Body() dto: DuplicateCheckRequestDto,
|
|
|
|
|
|
@Req() req: AuthenticatedRequest,
|
|
|
|
|
|
): Promise<UploadDuplicateCheckResponse> {
|
|
|
|
|
|
return this.uploadsService.checkDuplicates(userOf(req), dto);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-17 23:00:19 +08:00
|
|
|
|
/** 续签:仅 pending 会话;返回结构同 initUpload(credential 为新值)。 */
|
|
|
|
|
|
@Post(':uploadId/renew')
|
|
|
|
|
|
@HttpCode(HttpStatus.OK)
|
|
|
|
|
|
renewUploadCredential(
|
|
|
|
|
|
@Param('uploadId') uploadId: string,
|
|
|
|
|
|
@Req() req: AuthenticatedRequest,
|
|
|
|
|
|
): Promise<UploadInitResponse> {
|
|
|
|
|
|
return this.uploadsService.renew(userOf(req), uploadId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 完成核验:幂等(重复调用返回相同结果,不重复建 job)。 */
|
|
|
|
|
|
@Post(':uploadId/complete')
|
|
|
|
|
|
@HttpCode(HttpStatus.OK)
|
|
|
|
|
|
completeUpload(
|
|
|
|
|
|
@Param('uploadId') uploadId: string,
|
|
|
|
|
|
@Req() req: AuthenticatedRequest,
|
|
|
|
|
|
): Promise<UploadCompleteResponse> {
|
|
|
|
|
|
return this.uploadsService.complete(userOf(req), uploadId);
|
|
|
|
|
|
}
|
2026-09-17 22:42:13 +08:00
|
|
|
|
}
|