package handler import ( "carrotskin/internal/model" "carrotskin/internal/service" "carrotskin/internal/types" "carrotskin/pkg/auth" "carrotskin/pkg/email" "carrotskin/pkg/logger" "carrotskin/pkg/redis" "net/http" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // Register 用户注册 // @Summary 用户注册 // @Description 注册新用户账号 // @Tags auth // @Accept json // @Produce json // @Param request body types.RegisterRequest true "注册信息" // @Success 200 {object} model.Response "注册成功" // @Failure 400 {object} model.ErrorResponse "请求参数错误" // @Router /api/v1/auth/register [post] func Register(c *gin.Context) { loggerInstance := logger.MustGetLogger() jwtService := auth.MustGetJWTService() redisClient := redis.MustGetClient() var req types.RegisterRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.NewErrorResponse( model.CodeBadRequest, "请求参数错误", err, )) return } // 验证邮箱验证码 if err := service.VerifyCode(c.Request.Context(), redisClient, req.Email, req.VerificationCode, service.VerificationTypeRegister); err != nil { loggerInstance.Warn("验证码验证失败", zap.String("email", req.Email), zap.Error(err), ) c.JSON(http.StatusBadRequest, model.NewErrorResponse( model.CodeBadRequest, err.Error(), nil, )) return } // 调用service层注册用户(传递可选的头像URL) user, token, err := service.RegisterUser(jwtService, req.Username, req.Password, req.Email, req.Avatar) if err != nil { loggerInstance.Error("用户注册失败", zap.Error(err)) c.JSON(http.StatusBadRequest, model.NewErrorResponse( model.CodeBadRequest, err.Error(), nil, )) return } // 返回响应 c.JSON(http.StatusOK, model.NewSuccessResponse(&types.LoginResponse{ Token: token, UserInfo: &types.UserInfo{ ID: user.ID, Username: user.Username, Email: user.Email, Avatar: user.Avatar, Points: user.Points, Role: user.Role, Status: user.Status, LastLoginAt: user.LastLoginAt, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, }, })) } // Login 用户登录 // @Summary 用户登录 // @Description 用户登录获取JWT Token,支持用户名或邮箱登录 // @Tags auth // @Accept json // @Produce json // @Param request body types.LoginRequest true "登录信息(username字段支持用户名或邮箱)" // @Success 200 {object} model.Response{data=types.LoginResponse} "登录成功" // @Failure 400 {object} model.ErrorResponse "请求参数错误" // @Failure 401 {object} model.ErrorResponse "登录失败" // @Router /api/v1/auth/login [post] func Login(c *gin.Context) { loggerInstance := logger.MustGetLogger() jwtService := auth.MustGetJWTService() var req types.LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.NewErrorResponse( model.CodeBadRequest, "请求参数错误", err, )) return } // 获取IP和UserAgent ipAddress := c.ClientIP() userAgent := c.GetHeader("User-Agent") // 调用service层登录 user, token, err := service.LoginUser(jwtService, req.Username, req.Password, ipAddress, userAgent) if err != nil { loggerInstance.Warn("用户登录失败", zap.String("username_or_email", req.Username), zap.String("ip", ipAddress), zap.Error(err), ) c.JSON(http.StatusUnauthorized, model.NewErrorResponse( model.CodeUnauthorized, err.Error(), nil, )) return } // 返回响应 c.JSON(http.StatusOK, model.NewSuccessResponse(&types.LoginResponse{ Token: token, UserInfo: &types.UserInfo{ ID: user.ID, Username: user.Username, Email: user.Email, Avatar: user.Avatar, Points: user.Points, Role: user.Role, Status: user.Status, LastLoginAt: user.LastLoginAt, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, }, })) } // SendVerificationCode 发送验证码 // @Summary 发送验证码 // @Description 发送邮箱验证码(注册/重置密码/更换邮箱) // @Tags auth // @Accept json // @Produce json // @Param request body types.SendVerificationCodeRequest true "发送验证码请求" // @Success 200 {object} model.Response "发送成功" // @Failure 400 {object} model.ErrorResponse "请求参数错误" // @Router /api/v1/auth/send-code [post] func SendVerificationCode(c *gin.Context) { loggerInstance := logger.MustGetLogger() redisClient := redis.MustGetClient() emailService := email.MustGetService() var req types.SendVerificationCodeRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.NewErrorResponse( model.CodeBadRequest, "请求参数错误", err, )) return } // 发送验证码 if err := service.SendVerificationCode(c.Request.Context(), redisClient, emailService, req.Email, req.Type); err != nil { loggerInstance.Error("发送验证码失败", zap.String("email", req.Email), zap.String("type", req.Type), zap.Error(err), ) c.JSON(http.StatusBadRequest, model.NewErrorResponse( model.CodeBadRequest, err.Error(), nil, )) return } c.JSON(http.StatusOK, model.NewSuccessResponse(gin.H{ "message": "验证码已发送,请查收邮件", })) } // ResetPassword 重置密码 // @Summary 重置密码 // @Description 通过邮箱验证码重置密码 // @Tags auth // @Accept json // @Produce json // @Param request body types.ResetPasswordRequest true "重置密码请求" // @Success 200 {object} model.Response "重置成功" // @Failure 400 {object} model.ErrorResponse "请求参数错误" // @Router /api/v1/auth/reset-password [post] func ResetPassword(c *gin.Context) { loggerInstance := logger.MustGetLogger() redisClient := redis.MustGetClient() var req types.ResetPasswordRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.NewErrorResponse( model.CodeBadRequest, "请求参数错误", err, )) return } // 验证验证码 if err := service.VerifyCode(c.Request.Context(), redisClient, req.Email, req.VerificationCode, service.VerificationTypeResetPassword); err != nil { loggerInstance.Warn("验证码验证失败", zap.String("email", req.Email), zap.Error(err), ) c.JSON(http.StatusBadRequest, model.NewErrorResponse( model.CodeBadRequest, err.Error(), nil, )) return } // 重置密码 if err := service.ResetUserPassword(req.Email, req.NewPassword); err != nil { loggerInstance.Error("重置密码失败", zap.String("email", req.Email), zap.Error(err), ) c.JSON(http.StatusInternalServerError, model.NewErrorResponse( model.CodeServerError, err.Error(), nil, )) return } c.JSON(http.StatusOK, model.NewSuccessResponse(gin.H{ "message": "密码重置成功", })) }