chore: 初始化仓库,排除二进制文件和覆盖率文件
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
Test / test (push) Has been cancelled
Test / lint (push) Has been cancelled
Test / build (push) Has been cancelled

This commit is contained in:
lan
2025-11-28 23:30:49 +08:00
commit 4b4980820f
107 changed files with 20755 additions and 0 deletions

View File

@@ -0,0 +1,249 @@
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": "密码重置成功",
}))
}