feat: enhance profile editing and image upload functionality
- Introduced a utility function to ensure absolute media URLs for user profile images. - Updated the user cache synchronization method to handle profile data more effectively, including avatar, nickname, phone, and MBTI. - Refactored the avatar upload process to utilize the new URL handling function, improving reliability. - Modified the super article editor to focus on image uploads instead of file uploads, enhancing user experience with clearer labeling and prompts. This update aims to streamline user profile management and improve the image upload experience in the application.
This commit is contained in:
@@ -73,8 +73,7 @@ func isAllowedAttachment(file *multipart.FileHeader, ct string) bool {
|
||||
|
||||
// UploadPost POST /api/upload 通用上传(multipart:file + folder)
|
||||
// 同源挂载:POST /api/miniprogram/upload、POST /api/admin/upload(管理端须 Admin JWT)
|
||||
// 默认仅写入阿里云 OSS 并返回 OSS 公网完整 URL(见 system_config.oss_config)。
|
||||
// 若需本机无 OSS 调试,可在环境变量设置 UPLOAD_ALLOW_LOCAL_FALLBACK=true,此时未配置或失败才落盘并用 API_BASE_URL 拼接。
|
||||
// 优先写入 OSS(system_config.oss_config);未配置或上传失败时自动落本地 uploads/ 并由 BaseURL 拼接可访问 URL(不再向前端返回 OSS 配置类错误)。
|
||||
func UploadPost(c *gin.Context) {
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
@@ -131,16 +130,7 @@ func UploadPost(c *gin.Context) {
|
||||
name := fmt.Sprintf("%d_%s%s", time.Now().UnixNano(), randomStrUpload(6), ext)
|
||||
objectKey := filepath.ToSlash(filepath.Join("uploads", folder, name))
|
||||
|
||||
allowLocal := config.Get() != nil && config.Get().UploadAllowLocalFallback
|
||||
|
||||
if !oss.IsEnabled() {
|
||||
if !allowLocal {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{
|
||||
"success": false,
|
||||
"error": "未配置阿里云 OSS:请在管理端「系统设置 → OSS」保存完整 oss_config(AccessKey Secret 不得为占位符)。默认仅支持上传到 OSS 并返回 OSS 公网地址。",
|
||||
})
|
||||
return
|
||||
}
|
||||
uploadPostSaveLocal(c, file, folder, name, ct)
|
||||
return
|
||||
}
|
||||
@@ -169,17 +159,6 @@ func UploadPost(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !allowLocal {
|
||||
msg := "上传至阿里云 OSS 失败,请检查 oss_config、Bucket 权限与网络"
|
||||
if uploadErr != nil {
|
||||
msg = "上传至 OSS 失败: " + uploadErr.Error()
|
||||
} else if url == "" {
|
||||
msg = "上传至 OSS 未返回公网 URL,请检查 endpoint、bucket 与可选 publicBaseUrl"
|
||||
}
|
||||
c.JSON(http.StatusBadGateway, gin.H{"success": false, "error": msg})
|
||||
return
|
||||
}
|
||||
|
||||
if uploadErr != nil {
|
||||
log.Printf("upload: OSS failed objectKey=%s (local fallback): %v", objectKey, uploadErr)
|
||||
} else {
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"soul-api/internal/config"
|
||||
"soul-api/internal/database"
|
||||
"soul-api/internal/model"
|
||||
"soul-api/internal/oss"
|
||||
@@ -42,7 +41,7 @@ var (
|
||||
)
|
||||
|
||||
// UploadImagePost POST /api/miniprogram/upload/image 小程序-图片上传(支持压缩)
|
||||
// 默认仅写入 OSS 并返回公网完整 URL;环境变量 UPLOAD_ALLOW_LOCAL_FALLBACK=true 时未配置或失败才落盘。
|
||||
// 优先 OSS;未配置或失败时自动落本地 uploads/。
|
||||
// 表单:file(必填), folder(可选,默认 images), quality(可选 1-100,默认 85)
|
||||
func UploadImagePost(c *gin.Context) {
|
||||
file, err := c.FormFile("file")
|
||||
@@ -116,7 +115,6 @@ func UploadImagePost(c *gin.Context) {
|
||||
finalData = data
|
||||
}
|
||||
|
||||
allowLocal := config.Get() != nil && config.Get().UploadAllowLocalFallback
|
||||
var ossURL string
|
||||
var ossErr error
|
||||
if oss.IsEnabled() {
|
||||
@@ -135,18 +133,6 @@ func UploadImagePost(c *gin.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
if !allowLocal {
|
||||
msg := "未配置阿里云 OSS 或上传失败"
|
||||
if oss.IsEnabled() && ossErr != nil {
|
||||
msg = "上传至 OSS 失败: " + ossErr.Error()
|
||||
} else if !oss.IsEnabled() {
|
||||
msg = "未配置阿里云 OSS:请在管理端「系统设置 → OSS」保存完整 oss_config"
|
||||
} else {
|
||||
msg = "上传至 OSS 未返回公网地址"
|
||||
}
|
||||
c.JSON(http.StatusBadGateway, gin.H{"success": false, "error": msg})
|
||||
return
|
||||
}
|
||||
if ossErr != nil {
|
||||
log.Printf("upload/image: OSS failed folder=%s name=%s (local fallback): %v", folder, name, ossErr)
|
||||
} else {
|
||||
@@ -169,7 +155,7 @@ func UploadImagePost(c *gin.Context) {
|
||||
}
|
||||
|
||||
// UploadVideoPost POST /api/miniprogram/upload/video 小程序-视频上传
|
||||
// 默认仅 OSS;UPLOAD_ALLOW_LOCAL_FALLBACK=true 时未配置或失败才落盘。
|
||||
// 优先 OSS;未配置或失败时自动落本地。
|
||||
// 表单:file(必填), folder(可选,默认 videos)
|
||||
func UploadVideoPost(c *gin.Context) {
|
||||
file, err := c.FormFile("file")
|
||||
@@ -196,30 +182,18 @@ func UploadVideoPost(c *gin.Context) {
|
||||
}
|
||||
name := fmt.Sprintf("%d_%s%s", time.Now().UnixNano(), randomStrContent(8), ext)
|
||||
|
||||
allowLocal := config.Get() != nil && config.Get().UploadAllowLocalFallback
|
||||
var ossURL string
|
||||
var ossErr error
|
||||
|
||||
if oss.IsEnabled() {
|
||||
src, openErr := file.Open()
|
||||
if openErr != nil {
|
||||
if !allowLocal {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "打开文件失败"})
|
||||
return
|
||||
}
|
||||
ossErr = openErr
|
||||
} else {
|
||||
ossURL, ossErr = ossUploadFile(src, folder, name)
|
||||
_ = src.Close()
|
||||
}
|
||||
} else {
|
||||
if !allowLocal {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{
|
||||
"success": false,
|
||||
"error": "未配置阿里云 OSS:请在管理端「系统设置 → OSS」保存完整 oss_config",
|
||||
})
|
||||
return
|
||||
}
|
||||
ossErr = fmt.Errorf("OSS 未配置")
|
||||
}
|
||||
|
||||
@@ -235,17 +209,6 @@ func UploadVideoPost(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !allowLocal {
|
||||
msg := "上传至 OSS 失败"
|
||||
if ossErr != nil {
|
||||
msg = msg + ": " + ossErr.Error()
|
||||
} else {
|
||||
msg = "上传至 OSS 未返回公网地址"
|
||||
}
|
||||
c.JSON(http.StatusBadGateway, gin.H{"success": false, "error": msg})
|
||||
return
|
||||
}
|
||||
|
||||
if ossErr != nil {
|
||||
log.Printf("upload/video: OSS skipped or failed (local fallback) folder=%s name=%s: %v", folder, name, ossErr)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user