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