2618ad3163
- 契约 listAlbumAssetStatus(GET /albums/{albumId}/assets):每 (kind,locale)
最新 effective 行 + 现签 URL;权限同详情(可见即读);deleted → 404
- 服务端 AssetsService.status(createdAt,id DESC 组内取首;presignGet 现签)
- Admin 品牌资产页签改造:进入即加载现状——三种 kind 卡片(预览图/未设置
空态/设置时间),banner 分全局/zh/en 槽位;上传成功自动刷新(替换语义)
- API 56/56、admin 87/87 + build 全绿
Co-Authored-By: Claude Code <noreply@anthropic.com>
62 lines
2.0 KiB
TypeScript
62 lines
2.0 KiB
TypeScript
// services/api/src/albums/assets.controller.ts —— /albums/{albumId}/assets
|
||
// 端点(P1b Task 3)。方法名与契约 operationId 一一对应(initAlbumAssetUpload/
|
||
// completeAlbumAssetUpload)。控制器级 SessionGuard:两端点全需认证。控制器只做
|
||
// 认证用户与路径参数透传;权限与 HTTP 映射由 AssetsService 抛 ApiException
|
||
// (404 ALBUM_NOT_FOUND / 403 AUTH_FORBIDDEN / 400 VALIDATION_FAILED 或
|
||
// UPLOAD_VERIFY_FAILED)。
|
||
import {
|
||
Body,
|
||
Controller,
|
||
HttpCode,
|
||
HttpStatus,
|
||
Get,
|
||
Param,
|
||
Post,
|
||
Req,
|
||
UseGuards,
|
||
} from '@nestjs/common';
|
||
import type { components } from '@photo/contracts';
|
||
import { AuthenticatedRequest, SessionGuard } from '../auth/session.guard';
|
||
import { userOf } from './albums.controller';
|
||
import { AssetInitRequestDto } from './dto';
|
||
import {
|
||
AssetsService,
|
||
type AssetCompleteResponse,
|
||
type AssetInitResponse,
|
||
} from './assets.service';
|
||
|
||
@Controller('albums/:albumId/assets')
|
||
@UseGuards(SessionGuard)
|
||
export class AssetsController {
|
||
constructor(private readonly assetsService: AssetsService) {}
|
||
|
||
/** 契约 201:会话行已建(每次 init 新行新键,无幂等键)。 */
|
||
@Get()
|
||
listStatus(
|
||
@Param('albumId') albumId: string,
|
||
@Req() req: AuthenticatedRequest,
|
||
): Promise<components['schemas']['AssetStatusResponse']> {
|
||
return this.assetsService.status(userOf(req), albumId);
|
||
}
|
||
|
||
@Post()
|
||
initAlbumAssetUpload(
|
||
@Param('albumId') albumId: string,
|
||
@Body() dto: AssetInitRequestDto,
|
||
@Req() req: AuthenticatedRequest,
|
||
): Promise<AssetInitResponse> {
|
||
return this.assetsService.init(userOf(req), albumId, dto);
|
||
}
|
||
|
||
/** 完成核验:幂等(已生效行现签新 URL 返回,即签名刷新入口)。 */
|
||
@Post(':assetId/complete')
|
||
@HttpCode(HttpStatus.OK)
|
||
completeAlbumAssetUpload(
|
||
@Param('albumId') albumId: string,
|
||
@Param('assetId') assetId: string,
|
||
@Req() req: AuthenticatedRequest,
|
||
): Promise<AssetCompleteResponse> {
|
||
return this.assetsService.complete(userOf(req), albumId, assetId);
|
||
}
|
||
}
|