feat(api): album update with independent upload/public switches
PATCH /v1/albums/{albumId}(契约 updateAlbum):部分更新,各开关互相独立;
translations 全量替换(deleteMany+createMany),defaultLocale 可同请求切换但
替换后的翻译集必须覆盖最终 defaultLocale。权限顺序 404(不可见)→403(可见
不可管)与 getAlbum 一致防枚举;合并校验(endAt vs 存量 startAt、单边提交)
在事务内对最终状态裁决。audit album.update 记录 metadata.fields(契约属性序)。
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// services/api/src/albums/albums.controller.ts —— /albums 端点(Task 15)。
|
||||
// 方法名与契约 operationId 一一对应(createAlbum/listAlbums/getAlbum;
|
||||
// updateAlbum 属 Task 16)。控制器级 SessionGuard:三端点全需认证
|
||||
// services/api/src/albums/albums.controller.ts —— /albums 端点(Task 15;Task 16
|
||||
// 增补 updateAlbum)。方法名与契约 operationId 一一对应(createAlbum/
|
||||
// listAlbums/getAlbum/updateAlbum)。控制器级 SessionGuard:四端点全需认证
|
||||
// (契约均有 bearerAuth、无 security: [] 例外)。职责仅剩:
|
||||
// · 透传认证用户(req.user,守卫挂载);
|
||||
// · 查询参数规整(limit 1..100 整数、cursor 长度),非法 → 400
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
Get,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
Query,
|
||||
Req,
|
||||
@@ -28,11 +29,14 @@ import {
|
||||
type AlbumResponse,
|
||||
AlbumsService,
|
||||
} from './albums.service';
|
||||
import { AlbumCreateRequestDto } from './dto';
|
||||
import { AlbumCreateRequestDto, AlbumUpdateRequestDto } from './dto';
|
||||
import { MAX_CURSOR_LENGTH } from '../shared/cursor';
|
||||
|
||||
/** 守卫放行后提取 req.user;防御性兜底(守卫未挂载属装配错误,按未认证拒绝)。 */
|
||||
function userOf(req: AuthenticatedRequest): AuthUser {
|
||||
/**
|
||||
* 守卫放行后提取 req.user;防御性兜底(守卫未挂载属装配错误,按未认证拒绝)。
|
||||
* members/categories 控制器(Task 17)复用同一判定,导出。
|
||||
*/
|
||||
export function userOf(req: AuthenticatedRequest): AuthUser {
|
||||
if (req.user === undefined) {
|
||||
throw new ApiException(
|
||||
ErrorCodes.AUTH_TOKEN_EXPIRED,
|
||||
@@ -43,8 +47,9 @@ function userOf(req: AuthenticatedRequest): AuthUser {
|
||||
return req.user;
|
||||
}
|
||||
|
||||
/** limit 查询参数:缺省 20,须为 1..100 的十进制整数(契约 bounds)。 */
|
||||
function parseLimit(raw: string | undefined): number {
|
||||
/** limit 查询参数:缺省 20,须为 1..100 的十进制整数(契约 bounds)。导出供
|
||||
* members 列表(Task 17,同契约 bounds)复用。 */
|
||||
export function parseLimit(raw: string | undefined): number {
|
||||
if (raw === undefined || raw === '') {
|
||||
return DEFAULT_ALBUM_PAGE_SIZE;
|
||||
}
|
||||
@@ -66,7 +71,9 @@ function parseLimit(raw: string | undefined): number {
|
||||
return limit;
|
||||
}
|
||||
|
||||
function parseCursor(raw: string | undefined): string | undefined {
|
||||
/** cursor 查询参数:仅做长度规整(语义校验在服务层解码时);导出供 members
|
||||
* 列表(Task 17)复用。 */
|
||||
export function parseCursor(raw: string | undefined): string | undefined {
|
||||
if (raw === undefined || raw === '') {
|
||||
return undefined;
|
||||
}
|
||||
@@ -113,4 +120,13 @@ export class AlbumsController {
|
||||
): Promise<AlbumResponse> {
|
||||
return this.albumsService.get(userOf(req), albumId);
|
||||
}
|
||||
|
||||
@Patch(':albumId')
|
||||
updateAlbum(
|
||||
@Param('albumId') albumId: string,
|
||||
@Body() dto: AlbumUpdateRequestDto,
|
||||
@Req() req: AuthenticatedRequest,
|
||||
): Promise<AlbumResponse> {
|
||||
return this.albumsService.update(userOf(req), albumId, dto);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user