/** * 注册网关控制器 * * 架构层级:Gateway Layer(网关层) * * 功能描述: * - 处理用户注册相关的HTTP请求和响应 * - 提供RESTful API接口 * - 数据验证和格式化 * - 邮箱验证功能 * * 职责分离: * - 专注于HTTP协议处理和请求响应 * - 调用业务层服务完成具体功能 * - 处理API文档和参数验证 * - 不包含业务逻辑,只做数据转换和路由 * * 依赖关系: * - 依赖 Business Layer 的 RegisterService * - 使用 DTO 进行数据验证 * * API端点: * - POST /auth/register - 用户注册 * - POST /auth/send-email-verification - 发送邮箱验证码 * - POST /auth/verify-email - 验证邮箱验证码 * - POST /auth/resend-email-verification - 重新发送邮箱验证码 * * @author moyin * @version 2.0.0 * @since 2026-01-14 * @lastModified 2026-01-14 */ import { Controller, Post, Body, HttpStatus, ValidationPipe, UsePipes, Logger, Res } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse as SwaggerApiResponse, ApiBody } from '@nestjs/swagger'; import { Response } from 'express'; import { RegisterService } from '../../business/auth/register.service'; import { RegisterDto, EmailVerificationDto, SendEmailVerificationDto } from './dto/login.dto'; import { RegisterResponseDto, CommonResponseDto, TestModeEmailVerificationResponseDto, SuccessEmailVerificationResponseDto } from './dto/login_response.dto'; import { Throttle, ThrottlePresets } from '../../core/security_core/throttle.decorator'; import { Timeout, TimeoutPresets } from '../../core/security_core/timeout.decorator'; // 错误代码到HTTP状态码的映射 const ERROR_STATUS_MAP = { REGISTER_FAILED: HttpStatus.BAD_REQUEST, TEST_MODE_ONLY: HttpStatus.PARTIAL_CONTENT, SEND_EMAIL_VERIFICATION_FAILED: HttpStatus.BAD_REQUEST, EMAIL_VERIFICATION_FAILED: HttpStatus.BAD_REQUEST, RESEND_EMAIL_VERIFICATION_FAILED: HttpStatus.BAD_REQUEST, INVALID_VERIFICATION_CODE: HttpStatus.BAD_REQUEST, } as const; @ApiTags('auth') @Controller('auth') export class RegisterController { private readonly logger = new Logger(RegisterController.name); constructor(private readonly registerService: RegisterService) {} /** * 通用响应处理方法 * * 职责: * - 根据业务结果设置HTTP状态码 * - 处理不同类型的错误响应 * - 统一响应格式和错误处理 * * @param result 业务服务返回的结果 * @param res Express响应对象 * @param successStatus 成功时的HTTP状态码,默认为200 * @private */ private handleResponse(result: any, res: Response, successStatus: HttpStatus = HttpStatus.OK): void { if (result.success) { res.status(successStatus).json(result); return; } const statusCode = this.getErrorStatusCode(result); res.status(statusCode).json(result); } /** * 根据错误代码和消息获取HTTP状态码 * * @param result 业务服务返回的结果 * @returns HTTP状态码 * @private */ private getErrorStatusCode(result: any): HttpStatus { if (result.error_code && ERROR_STATUS_MAP[result.error_code as keyof typeof ERROR_STATUS_MAP]) { return ERROR_STATUS_MAP[result.error_code as keyof typeof ERROR_STATUS_MAP]; } if (result.message?.includes('已存在') || result.message?.includes('已被注册')) { return HttpStatus.CONFLICT; } if (result.message?.includes('用户不存在')) { return HttpStatus.NOT_FOUND; } return HttpStatus.BAD_REQUEST; } /** * 用户注册 * * @param registerDto 注册数据 * @param res Express响应对象 */ @ApiOperation({ summary: '用户注册', description: '创建新用户账户' }) @ApiBody({ type: RegisterDto }) @SwaggerApiResponse({ status: 201, description: '注册成功', type: RegisterResponseDto }) @SwaggerApiResponse({ status: 400, description: '请求参数错误' }) @SwaggerApiResponse({ status: 409, description: '用户名或邮箱已存在' }) @SwaggerApiResponse({ status: 429, description: '注册请求过于频繁' }) @Throttle(ThrottlePresets.REGISTER) @Timeout(TimeoutPresets.NORMAL) @Post('register') @UsePipes(new ValidationPipe({ transform: true })) async register(@Body() registerDto: RegisterDto, @Res() res: Response): Promise { const result = await this.registerService.register({ username: registerDto.username, password: registerDto.password, nickname: registerDto.nickname, email: registerDto.email, phone: registerDto.phone, email_verification_code: registerDto.email_verification_code }); this.handleResponse(result, res, HttpStatus.CREATED); } /** * 发送邮箱验证码 * * @param sendEmailVerificationDto 发送验证码数据 * @param res Express响应对象 */ @ApiOperation({ summary: '发送邮箱验证码', description: '向指定邮箱发送验证码' }) @ApiBody({ type: SendEmailVerificationDto }) @SwaggerApiResponse({ status: 200, description: '验证码发送成功(真实发送模式)', type: SuccessEmailVerificationResponseDto }) @SwaggerApiResponse({ status: 206, description: '测试模式:验证码已生成但未真实发送', type: TestModeEmailVerificationResponseDto }) @SwaggerApiResponse({ status: 400, description: '请求参数错误' }) @SwaggerApiResponse({ status: 429, description: '发送频率过高' }) @Throttle(ThrottlePresets.SEND_CODE_PER_EMAIL) @Timeout(TimeoutPresets.EMAIL_SEND) @Post('send-email-verification') @UsePipes(new ValidationPipe({ transform: true })) async sendEmailVerification( @Body() sendEmailVerificationDto: SendEmailVerificationDto, @Res() res: Response ): Promise { const result = await this.registerService.sendEmailVerification(sendEmailVerificationDto.email); this.handleResponse(result, res); } /** * 验证邮箱验证码 * * @param emailVerificationDto 邮箱验证数据 * @param res Express响应对象 */ @ApiOperation({ summary: '验证邮箱验证码', description: '使用验证码验证邮箱' }) @ApiBody({ type: EmailVerificationDto }) @SwaggerApiResponse({ status: 200, description: '邮箱验证成功', type: CommonResponseDto }) @SwaggerApiResponse({ status: 400, description: '验证码错误或已过期' }) @Post('verify-email') @UsePipes(new ValidationPipe({ transform: true })) async verifyEmail(@Body() emailVerificationDto: EmailVerificationDto, @Res() res: Response): Promise { const result = await this.registerService.verifyEmailCode( emailVerificationDto.email, emailVerificationDto.verification_code ); this.handleResponse(result, res); } /** * 重新发送邮箱验证码 * * @param sendEmailVerificationDto 发送验证码数据 * @param res Express响应对象 */ @ApiOperation({ summary: '重新发送邮箱验证码', description: '重新向指定邮箱发送验证码' }) @ApiBody({ type: SendEmailVerificationDto }) @SwaggerApiResponse({ status: 200, description: '验证码重新发送成功', type: SuccessEmailVerificationResponseDto }) @SwaggerApiResponse({ status: 206, description: '测试模式:验证码已生成但未真实发送', type: TestModeEmailVerificationResponseDto }) @SwaggerApiResponse({ status: 400, description: '邮箱已验证或用户不存在' }) @SwaggerApiResponse({ status: 429, description: '发送频率过高' }) @Throttle(ThrottlePresets.SEND_CODE) @Post('resend-email-verification') @UsePipes(new ValidationPipe({ transform: true })) async resendEmailVerification( @Body() sendEmailVerificationDto: SendEmailVerificationDto, @Res() res: Response ): Promise { const result = await this.registerService.resendEmailVerification(sendEmailVerificationDto.email); this.handleResponse(result, res); } }