feat(api): photo visibility lifecycle with audit and outbox events
Serializes turbo tasks (concurrency=1): api and worker e2e suites share one MySQL/MinIO and resetDb TRUNCATEs raced when run in parallel. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// services/api/src/photos/photos.controller.ts —— /photos 端点(Task 24)。
|
||||
// 方法名与契约 operationId 一一对应(updatePhoto/deletePhoto)。控制器级
|
||||
// SessionGuard:两端点全需认证(契约 bearerAuth)。职责仅透传认证用户与
|
||||
// 参数;404/403/400 映射与状态机裁决在服务层。注意 DTO 值导入(非
|
||||
// import type):@Body 参数类型经 emitDecoratorMetadata 进入设计期元数据。
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Patch,
|
||||
Req,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { userOf } from '../albums/albums.controller';
|
||||
import { AuthenticatedRequest, SessionGuard } from '../auth/session.guard';
|
||||
import { PhotosService, type PhotoRecord } from './photos.service';
|
||||
import { PhotoVisibilityUpdateDto } from './dto';
|
||||
|
||||
@Controller('photos')
|
||||
@UseGuards(SessionGuard)
|
||||
export class PhotosController {
|
||||
constructor(private readonly photosService: PhotosService) {}
|
||||
|
||||
/** 调整可见性(hidden↔published):按相册角色与上传人共同判定权限。 */
|
||||
@Patch(':photoId')
|
||||
updatePhoto(
|
||||
@Param('photoId') photoId: string,
|
||||
@Body() dto: PhotoVisibilityUpdateDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
): Promise<PhotoRecord> {
|
||||
return this.photosService.updateVisibility(
|
||||
userOf(req),
|
||||
photoId,
|
||||
dto.visibility,
|
||||
);
|
||||
}
|
||||
|
||||
/** 软删除:行/对象保留,公开端点即刻不可见;幂等重复删除 204。 */
|
||||
@Delete(':photoId')
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
async deletePhoto(
|
||||
@Param('photoId') photoId: string,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
): Promise<void> {
|
||||
await this.photosService.remove(userOf(req), photoId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user