Files
backend/internal/handler/user_handler.go

256 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"carrotskin/internal/container"
"carrotskin/internal/service"
"carrotskin/internal/types"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// 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 := h.container.UserService.GetByID(c.Request.Context(), userID)
if err != nil || user == nil {
h.logger.Error("获取用户信息失败",
zap.Int64("user_id", userID),
zap.Error(err),
)
RespondNotFound(c, "用户不存在")
return
}
RespondSuccess(c, UserToUserInfo(user))
}
// UpdateProfile 更新用户信息
func (h *UserHandler) UpdateProfile(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req types.UpdateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "请求参数错误", err)
return
}
user, err := h.container.UserService.GetByID(c.Request.Context(), userID)
if err != nil || user == nil {
RespondNotFound(c, "用户不存在")
return
}
// 处理密码修改
if req.NewPassword != "" {
if req.OldPassword == "" {
RespondBadRequest(c, "修改密码需要提供原密码", nil)
return
}
if err := h.container.UserService.ChangePassword(c.Request.Context(), userID, req.OldPassword, req.NewPassword); err != nil {
h.logger.Error("修改密码失败", zap.Int64("user_id", userID), zap.Error(err))
RespondBadRequest(c, err.Error(), nil)
return
}
h.logger.Info("用户修改密码成功", zap.Int64("user_id", userID))
}
// 更新头像
if req.Avatar != "" {
if err := h.container.UserService.ValidateAvatarURL(c.Request.Context(), req.Avatar); err != nil {
RespondBadRequest(c, err.Error(), nil)
return
}
user.Avatar = req.Avatar
if err := h.container.UserService.UpdateInfo(c.Request.Context(), user); err != nil {
h.logger.Error("更新用户信息失败", zap.Int64("user_id", user.ID), zap.Error(err))
RespondServerError(c, "更新失败", err)
return
}
}
// 重新获取更新后的用户信息
updatedUser, err := h.container.UserService.GetByID(c.Request.Context(), userID)
if err != nil || updatedUser == nil {
RespondNotFound(c, "用户不存在")
return
}
RespondSuccess(c, UserToUserInfo(updatedUser))
}
// UploadAvatar 直接上传头像文件
func (h *UserHandler) UploadAvatar(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
// 解析multipart表单
if err := c.Request.ParseMultipartForm(10 << 20); err != nil { // 10MB
RespondBadRequest(c, "解析表单失败", err)
return
}
// 获取文件
file, err := c.FormFile("file")
if err != nil {
RespondBadRequest(c, "获取文件失败", err)
return
}
// 读取文件内容
src, err := file.Open()
if err != nil {
RespondBadRequest(c, "打开文件失败", err)
return
}
defer src.Close()
fileData := make([]byte, file.Size)
if _, err := src.Read(fileData); err != nil {
RespondBadRequest(c, "读取文件失败", err)
return
}
// 调用服务上传头像
avatarURL, err := h.container.UserService.UploadAvatar(c.Request.Context(), userID, fileData, file.Filename)
if err != nil {
h.logger.Error("上传头像失败",
zap.Int64("user_id", userID),
zap.String("file_name", file.Filename),
zap.Error(err),
)
RespondBadRequest(c, err.Error(), nil)
return
}
// 获取更新后的用户信息
user, err := h.container.UserService.GetByID(c.Request.Context(), userID)
if err != nil || user == nil {
RespondNotFound(c, "用户不存在")
return
}
RespondSuccess(c, gin.H{
"avatar_url": avatarURL,
"user": UserToUserInfo(user),
})
}
// UpdateAvatar 更新头像URL保留用于外部URL
func (h *UserHandler) UpdateAvatar(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
avatarURL := c.Query("avatar_url")
if avatarURL == "" {
RespondBadRequest(c, "头像URL不能为空", nil)
return
}
if err := h.container.UserService.ValidateAvatarURL(c.Request.Context(), avatarURL); err != nil {
RespondBadRequest(c, err.Error(), nil)
return
}
if err := h.container.UserService.UpdateAvatar(c.Request.Context(), userID, avatarURL); err != nil {
h.logger.Error("更新头像失败",
zap.Int64("user_id", userID),
zap.String("avatar_url", avatarURL),
zap.Error(err),
)
RespondServerError(c, "更新头像失败", err)
return
}
user, err := h.container.UserService.GetByID(c.Request.Context(), userID)
if err != nil || user == nil {
RespondNotFound(c, "用户不存在")
return
}
RespondSuccess(c, UserToUserInfo(user))
}
// ChangeEmail 更换邮箱
func (h *UserHandler) ChangeEmail(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req types.ChangeEmailRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "请求参数错误", err)
return
}
if err := h.container.VerificationService.VerifyCode(c.Request.Context(), 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 := h.container.UserService.ChangeEmail(c.Request.Context(), userID, req.NewEmail); err != nil {
h.logger.Error("更换邮箱失败",
zap.Int64("user_id", userID),
zap.String("new_email", req.NewEmail),
zap.Error(err),
)
RespondBadRequest(c, err.Error(), nil)
return
}
user, err := h.container.UserService.GetByID(c.Request.Context(), userID)
if err != nil || user == nil {
RespondNotFound(c, "用户不存在")
return
}
RespondSuccess(c, UserToUserInfo(user))
}
// ResetYggdrasilPassword 重置Yggdrasil密码
func (h *UserHandler) ResetYggdrasilPassword(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
newPassword, err := h.container.YggdrasilService.ResetYggdrasilPassword(c.Request.Context(), userID)
if err != nil {
h.logger.Error("重置Yggdrasil密码失败", zap.Error(err), zap.Int64("userId", userID))
RespondServerError(c, "重置Yggdrasil密码失败", nil)
return
}
h.logger.Info("Yggdrasil密码重置成功", zap.Int64("userId", userID))
RespondSuccess(c, gin.H{"password": newPassword})
}