250 lines
6.8 KiB
Go
250 lines
6.8 KiB
Go
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": "密码重置成功",
|
||
}))
|
||
}
|