统一文件上传方式为直接上传,更新环境变量示例

This commit is contained in:
2025-12-08 15:40:28 +08:00
parent aa75691c49
commit 63ca7eff0d
18 changed files with 197 additions and 1032 deletions

View File

@@ -95,8 +95,8 @@ func registerUserRoutes(v1 *gin.RouterGroup, h *UserHandler, jwtService *auth.JW
userGroup.PUT("/profile", h.UpdateProfile)
// 头像相关
userGroup.POST("/avatar/upload-url", h.GenerateAvatarUploadURL)
userGroup.PUT("/avatar", h.UpdateAvatar)
userGroup.POST("/avatar/upload", h.UploadAvatar) // 直接上传头像文件
userGroup.PUT("/avatar", h.UpdateAvatar) // 更新头像URL外部URL
// 更换邮箱
userGroup.POST("/change-email", h.ChangeEmail)
@@ -122,9 +122,7 @@ func registerTextureRoutes(v1 *gin.RouterGroup, h *TextureHandler, jwtService *a
textureAuth := textureGroup.Group("")
textureAuth.Use(middleware.AuthMiddleware(jwtService))
{
textureAuth.POST("/upload", h.Upload) // 直接上传文件
textureAuth.POST("/upload-url", h.GenerateUploadURL) // 生成预签名URL保留兼容性
textureAuth.POST("", h.Create) // 创建材质记录配合预签名URL使用
textureAuth.POST("/upload", h.Upload) // 直接上传文件
textureAuth.PUT("/:id", h.Update)
textureAuth.DELETE("/:id", h.Delete)
textureAuth.POST("/:id/favorite", h.ToggleFavorite)

View File

@@ -25,93 +25,6 @@ func NewTextureHandler(c *container.Container) *TextureHandler {
}
}
// GenerateUploadURL 生成材质上传URL
func (h *TextureHandler) GenerateUploadURL(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req types.GenerateTextureUploadURLRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "请求参数错误", err)
return
}
if h.container.Storage == nil {
RespondServerError(c, "存储服务不可用", nil)
return
}
result, err := h.container.UploadService.GenerateTextureUploadURL(
c.Request.Context(),
userID,
req.FileName,
string(req.TextureType),
)
if err != nil {
h.logger.Error("生成材质上传URL失败",
zap.Int64("user_id", userID),
zap.String("file_name", req.FileName),
zap.String("texture_type", string(req.TextureType)),
zap.Error(err),
)
RespondBadRequest(c, err.Error(), nil)
return
}
RespondSuccess(c, &types.GenerateTextureUploadURLResponse{
PostURL: result.PostURL,
FormData: result.FormData,
TextureURL: result.FileURL,
ExpiresIn: 900,
})
}
// Create 创建材质记录
func (h *TextureHandler) Create(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req types.CreateTextureRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "请求参数错误", err)
return
}
maxTextures := h.container.UserService.GetMaxTexturesPerUser()
if err := h.container.TextureService.CheckUploadLimit(c.Request.Context(), userID, maxTextures); err != nil {
RespondBadRequest(c, err.Error(), nil)
return
}
texture, err := h.container.TextureService.Create(
c.Request.Context(),
userID,
req.Name,
req.Description,
string(req.Type),
req.URL,
req.Hash,
req.Size,
req.IsPublic,
req.IsSlim,
)
if err != nil {
h.logger.Error("创建材质失败",
zap.Int64("user_id", userID),
zap.String("name", req.Name),
zap.Error(err),
)
RespondBadRequest(c, err.Error(), nil)
return
}
RespondSuccess(c, TextureToTextureInfo(texture))
}
// Get 获取材质详情
func (h *TextureHandler) Get(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)

View File

@@ -102,44 +102,66 @@ func (h *UserHandler) UpdateProfile(c *gin.Context) {
RespondSuccess(c, UserToUserInfo(updatedUser))
}
// GenerateAvatarUploadURL 生成头像上传URL
func (h *UserHandler) GenerateAvatarUploadURL(c *gin.Context) {
// UploadAvatar 直接上传头像文件
func (h *UserHandler) UploadAvatar(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req types.GenerateAvatarUploadURLRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "请求参数错误", err)
// 解析multipart表单
if err := c.Request.ParseMultipartForm(10 << 20); err != nil { // 10MB
RespondBadRequest(c, "解析表单失败", err)
return
}
if h.container.Storage == nil {
RespondServerError(c, "存储服务不可用", nil)
return
}
result, err := h.container.UploadService.GenerateAvatarUploadURL(c.Request.Context(), userID, req.FileName)
// 获取文件
file, err := c.FormFile("file")
if err != nil {
h.logger.Error("生成头像上传URL失败",
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", req.FileName),
zap.String("file_name", file.Filename),
zap.Error(err),
)
RespondBadRequest(c, err.Error(), nil)
return
}
RespondSuccess(c, &types.GenerateAvatarUploadURLResponse{
PostURL: result.PostURL,
FormData: result.FormData,
AvatarURL: result.FileURL,
ExpiresIn: 900,
// 获取更新后的用户信息
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
// UpdateAvatar 更新头像URL保留用于外部URL
func (h *UserHandler) UpdateAvatar(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {