refactor: Implement dependency injection for handlers and services

- Refactored AuthHandler, UserHandler, TextureHandler, ProfileHandler, CaptchaHandler, and YggdrasilHandler to use dependency injection.
- Removed direct instantiation of services and repositories within handlers, replacing them with constructor injection.
- Updated the container to initialize service instances and provide them to handlers.
- Enhanced code structure for better testability and adherence to Go best practices.
This commit is contained in:
lafay
2025-12-02 19:43:39 +08:00
parent 188a05caa7
commit 801f1b1397
33 changed files with 3628 additions and 4129 deletions

View File

@@ -1,36 +1,38 @@
package handler
import (
"carrotskin/internal/container"
"carrotskin/internal/service"
"carrotskin/internal/types"
"carrotskin/pkg/database"
"carrotskin/pkg/logger"
"carrotskin/pkg/redis"
"carrotskin/pkg/storage"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// GetUserProfile 获取用户信息
// @Summary 获取用户信息
// @Description 获取当前登录用户的详细信息
// @Tags user
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} model.Response "获取成功"
// @Failure 401 {object} model.ErrorResponse "未授权"
// @Router /api/v1/user/profile [get]
func GetUserProfile(c *gin.Context) {
// UserHandler 用户处理器(依赖注入版本)
type UserHandler struct {
container *container.Container
logger *zap.Logger
}
// NewUserHandler 创建UserHandler实例
func NewUserHandler(c *container.Container) *UserHandler {
return &UserHandler{
container: c,
logger: c.Logger,
}
}
// GetProfile 获取用户信息
func (h *UserHandler) GetProfile(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
user, err := service.GetUserByID(userID)
user, err := h.container.UserService.GetByID(userID)
if err != nil || user == nil {
logger.MustGetLogger().Error("获取用户信息失败",
h.logger.Error("获取用户信息失败",
zap.Int64("user_id", userID),
zap.Error(err),
)
@@ -41,22 +43,8 @@ func GetUserProfile(c *gin.Context) {
RespondSuccess(c, UserToUserInfo(user))
}
// UpdateUserProfile 更新用户信息
// @Summary 更新用户信息
// @Description 更新当前登录用户的头像和密码(修改邮箱请使用 /change-email 接口)
// @Tags user
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body types.UpdateUserRequest true "更新信息修改密码时需同时提供old_password和new_password"
// @Success 200 {object} model.Response{data=types.UserInfo} "更新成功"
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
// @Failure 401 {object} model.ErrorResponse "未授权"
// @Failure 404 {object} model.ErrorResponse "用户不存在"
// @Failure 500 {object} model.ErrorResponse "服务器错误"
// @Router /api/v1/user/profile [put]
func UpdateUserProfile(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
// UpdateProfile 更新用户信息
func (h *UserHandler) UpdateProfile(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -68,7 +56,7 @@ func UpdateUserProfile(c *gin.Context) {
return
}
user, err := service.GetUserByID(userID)
user, err := h.container.UserService.GetByID(userID)
if err != nil || user == nil {
RespondNotFound(c, "用户不存在")
return
@@ -81,32 +69,31 @@ func UpdateUserProfile(c *gin.Context) {
return
}
if err := service.ChangeUserPassword(userID, req.OldPassword, req.NewPassword); err != nil {
loggerInstance.Error("修改密码失败", zap.Int64("user_id", userID), zap.Error(err))
if err := h.container.UserService.ChangePassword(userID, req.OldPassword, req.NewPassword); err != nil {
h.logger.Error("修改密码失败", zap.Int64("user_id", userID), zap.Error(err))
RespondBadRequest(c, err.Error(), nil)
return
}
loggerInstance.Info("用户修改密码成功", zap.Int64("user_id", userID))
h.logger.Info("用户修改密码成功", zap.Int64("user_id", userID))
}
// 更新头像
if req.Avatar != "" {
// 验证头像 URL 是否来自允许的域名
if err := service.ValidateAvatarURL(req.Avatar); err != nil {
if err := h.container.UserService.ValidateAvatarURL(req.Avatar); err != nil {
RespondBadRequest(c, err.Error(), nil)
return
}
user.Avatar = req.Avatar
if err := service.UpdateUserInfo(user); err != nil {
loggerInstance.Error("更新用户信息失败", zap.Int64("user_id", user.ID), zap.Error(err))
if err := h.container.UserService.UpdateInfo(user); err != nil {
h.logger.Error("更新用户信息失败", zap.Int64("user_id", user.ID), zap.Error(err))
RespondServerError(c, "更新失败", err)
return
}
}
// 重新获取更新后的用户信息
updatedUser, err := service.GetUserByID(userID)
updatedUser, err := h.container.UserService.GetByID(userID)
if err != nil || updatedUser == nil {
RespondNotFound(c, "用户不存在")
return
@@ -116,17 +103,7 @@ func UpdateUserProfile(c *gin.Context) {
}
// GenerateAvatarUploadURL 生成头像上传URL
// @Summary 生成头像上传URL
// @Description 生成预签名URL用于上传用户头像
// @Tags user
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body types.GenerateAvatarUploadURLRequest true "文件名"
// @Success 200 {object} model.Response "生成成功"
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
// @Router /api/v1/user/avatar/upload-url [post]
func GenerateAvatarUploadURL(c *gin.Context) {
func (h *UserHandler) GenerateAvatarUploadURL(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -138,10 +115,14 @@ func GenerateAvatarUploadURL(c *gin.Context) {
return
}
storageClient := storage.MustGetClient()
result, err := service.GenerateAvatarUploadURL(c.Request.Context(), storageClient, userID, req.FileName)
if h.container.Storage == nil {
RespondServerError(c, "存储服务不可用", nil)
return
}
result, err := service.GenerateAvatarUploadURL(c.Request.Context(), h.container.Storage, userID, req.FileName)
if err != nil {
logger.MustGetLogger().Error("生成头像上传URL失败",
h.logger.Error("生成头像上传URL失败",
zap.Int64("user_id", userID),
zap.String("file_name", req.FileName),
zap.Error(err),
@@ -159,17 +140,7 @@ func GenerateAvatarUploadURL(c *gin.Context) {
}
// UpdateAvatar 更新头像URL
// @Summary 更新头像URL
// @Description 上传完成后更新用户的头像URL到数据库
// @Tags user
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param avatar_url query string true "头像URL"
// @Success 200 {object} model.Response "更新成功"
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
// @Router /api/v1/user/avatar [put]
func UpdateAvatar(c *gin.Context) {
func (h *UserHandler) UpdateAvatar(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -181,13 +152,13 @@ func UpdateAvatar(c *gin.Context) {
return
}
if err := service.ValidateAvatarURL(avatarURL); err != nil {
if err := h.container.UserService.ValidateAvatarURL(avatarURL); err != nil {
RespondBadRequest(c, err.Error(), nil)
return
}
if err := service.UpdateUserAvatar(userID, avatarURL); err != nil {
logger.MustGetLogger().Error("更新头像失败",
if err := h.container.UserService.UpdateAvatar(userID, avatarURL); err != nil {
h.logger.Error("更新头像失败",
zap.Int64("user_id", userID),
zap.String("avatar_url", avatarURL),
zap.Error(err),
@@ -196,7 +167,7 @@ func UpdateAvatar(c *gin.Context) {
return
}
user, err := service.GetUserByID(userID)
user, err := h.container.UserService.GetByID(userID)
if err != nil || user == nil {
RespondNotFound(c, "用户不存在")
return
@@ -206,19 +177,7 @@ func UpdateAvatar(c *gin.Context) {
}
// ChangeEmail 更换邮箱
// @Summary 更换邮箱
// @Description 通过验证码更换用户邮箱
// @Tags user
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body types.ChangeEmailRequest true "更换邮箱请求"
// @Success 200 {object} model.Response{data=types.UserInfo} "更换成功"
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
// @Failure 401 {object} model.ErrorResponse "未授权"
// @Router /api/v1/user/change-email [post]
func ChangeEmail(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
func (h *UserHandler) ChangeEmail(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -230,15 +189,14 @@ func ChangeEmail(c *gin.Context) {
return
}
redisClient := redis.MustGetClient()
if err := service.VerifyCode(c.Request.Context(), redisClient, req.NewEmail, req.VerificationCode, service.VerificationTypeChangeEmail); err != nil {
loggerInstance.Warn("验证码验证失败", zap.String("new_email", req.NewEmail), zap.Error(err))
if err := service.VerifyCode(c.Request.Context(), h.container.Redis, req.NewEmail, req.VerificationCode, service.VerificationTypeChangeEmail); err != nil {
h.logger.Warn("验证码验证失败", zap.String("new_email", req.NewEmail), zap.Error(err))
RespondBadRequest(c, err.Error(), nil)
return
}
if err := service.ChangeUserEmail(userID, req.NewEmail); err != nil {
loggerInstance.Error("更换邮箱失败",
if err := h.container.UserService.ChangeEmail(userID, req.NewEmail); err != nil {
h.logger.Error("更换邮箱失败",
zap.Int64("user_id", userID),
zap.String("new_email", req.NewEmail),
zap.Error(err),
@@ -247,7 +205,7 @@ func ChangeEmail(c *gin.Context) {
return
}
user, err := service.GetUserByID(userID)
user, err := h.container.UserService.GetByID(userID)
if err != nil || user == nil {
RespondNotFound(c, "用户不存在")
return
@@ -257,31 +215,19 @@ func ChangeEmail(c *gin.Context) {
}
// ResetYggdrasilPassword 重置Yggdrasil密码
// @Summary 重置Yggdrasil密码
// @Description 重置当前用户的Yggdrasil密码并返回新密码
// @Tags user
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} model.Response "重置成功"
// @Failure 401 {object} model.ErrorResponse "未授权"
// @Failure 500 {object} model.ErrorResponse "服务器错误"
// @Router /api/v1/user/yggdrasil-password/reset [post]
func ResetYggdrasilPassword(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
func (h *UserHandler) ResetYggdrasilPassword(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
db := database.MustGetDB()
newPassword, err := service.ResetYggdrasilPassword(db, userID)
newPassword, err := service.ResetYggdrasilPassword(h.container.DB, userID)
if err != nil {
loggerInstance.Error("重置Yggdrasil密码失败", zap.Error(err), zap.Int64("userId", userID))
h.logger.Error("重置Yggdrasil密码失败", zap.Error(err), zap.Int64("userId", userID))
RespondServerError(c, "重置Yggdrasil密码失败", nil)
return
}
loggerInstance.Info("Yggdrasil密码重置成功", zap.Int64("userId", userID))
h.logger.Info("Yggdrasil密码重置成功", zap.Int64("userId", userID))
RespondSuccess(c, gin.H{"password": newPassword})
}