Files
photo-live/services/api/src/albums/members.controller.ts
T
浅念 47fb81ad31 chore(api): p1a final-review hygiene items
- contracts: add NOT_FOUND error code (framework-level 404 for unknown
  routes); Error enum + regen committed
- api: 404 default mapping in AllExceptionsFilter now NOT_FOUND (was
  ALBUM_NOT_FOUND); business 404s unchanged via explicit ApiException codes
- api: extract configureApp (prefix/CORS/x-powered-by) shared by main-cn
  bootstrap and e2e; disable x-powered-by, asserted in e2e
- api: move parseCursor/parseLimit (+page-size bounds) from
  albums.controller to shared/pagination; members/uploads/public re-pointed
- infra: bind compose published ports to 127.0.0.1 (mysql/redis/minio);
  .env.example endpoints follow suit
- e2e: unknown-route 404 NOT_FOUND + x-powered-by absent cases added
  (api e2e 120 -> 122)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-18 08:18:30 +08:00

70 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// services/api/src/albums/members.controller.ts —— /albums/{albumId}/members
// 端点(Task 17)。方法名与契约 operationId 一一对应(addAlbumMember/
// listAlbumMembers/removeAlbumMember)。控制器级 SessionGuard:三端点全需
// 认证。控制器只做认证用户透传 + 查询参数规整(shared/pagination 的
// parseLimit/parseCursor,同一契约 bounds/游标语义);权限与 HTTP 映射由
// MembersService 抛 ApiException(404 ALBUM_NOT_FOUND / 403 AUTH_FORBIDDEN /
// 409 MEMBER_CONFLICT)。
import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,
Param,
Post,
Query,
Req,
UseGuards,
} from '@nestjs/common';
import { AuthenticatedRequest, SessionGuard } from '../auth/session.guard';
import { userOf } from './albums.controller';
import { parseCursor, parseLimit } from '../shared/pagination';
import { MemberAddRequestDto } from './dto';
import {
type MemberListResponse,
type MemberResponse,
MembersService,
} from './members.service';
@Controller('albums/:albumId/members')
@UseGuards(SessionGuard)
export class MembersController {
constructor(private readonly membersService: MembersService) {}
@Post()
addAlbumMember(
@Param('albumId') albumId: string,
@Body() dto: MemberAddRequestDto,
@Req() req: AuthenticatedRequest,
): Promise<MemberResponse> {
return this.membersService.add(userOf(req), albumId, dto);
}
@Get()
listAlbumMembers(
@Param('albumId') albumId: string,
@Query('cursor') cursor: string | undefined,
@Query('limit') limit: string | undefined,
@Req() req: AuthenticatedRequest,
): Promise<MemberListResponse> {
return this.membersService.list(
userOf(req),
albumId,
parseCursor(cursor),
parseLimit(limit),
);
}
@Delete(':userId')
@HttpCode(HttpStatus.NO_CONTENT)
removeAlbumMember(
@Param('albumId') albumId: string,
@Param('userId') userId: string,
@Req() req: AuthenticatedRequest,
): Promise<void> {
return this.membersService.remove(userOf(req), albumId, userId);
}
}