2026-01-19 16:14:08 +08:00
|
|
|
|
package handlers
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"log"
|
|
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
"github.com/niangaodev/art-code/models"
|
|
|
|
|
|
"github.com/niangaodev/art-code/repositories"
|
|
|
|
|
|
"github.com/niangaodev/art-code/utils"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// AdminUploadAttachment 上传附件
|
|
|
|
|
|
func AdminUploadAttachment(c *gin.Context) {
|
|
|
|
|
|
// 获取文件
|
|
|
|
|
|
file, err := c.FormFile("file")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "No file uploaded")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取分类ID(可选)
|
|
|
|
|
|
categoryIDStr := c.PostForm("categoryId")
|
|
|
|
|
|
var categoryID *uint
|
|
|
|
|
|
if categoryIDStr != "" {
|
|
|
|
|
|
if id, err := strconv.ParseUint(categoryIDStr, 10, 32); err == nil {
|
|
|
|
|
|
idUint := uint(id)
|
|
|
|
|
|
categoryID = &idUint
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取存储类型
|
|
|
|
|
|
storageType := c.DefaultPostForm("storageType", "local")
|
|
|
|
|
|
|
|
|
|
|
|
// 打开文件
|
|
|
|
|
|
src, err := file.Open()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to open file")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer src.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 获取OSS配置
|
|
|
|
|
|
var ossConfig *models.OSSConfig
|
|
|
|
|
|
if storageType != "local" {
|
|
|
|
|
|
ossConfig, err = repositories.GetActiveOSSConfig(storageType)
|
|
|
|
|
|
if err != nil || ossConfig == nil {
|
|
|
|
|
|
utils.Error(c, 400, "OSS config not found or not active")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建OSS配置对象
|
|
|
|
|
|
config := &utils.OSSConfig{
|
|
|
|
|
|
StorageType: storageType,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ossConfig != nil {
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 根据存储类型从专用字段或通用字段读取配置
|
|
|
|
|
|
var accessKey, secretKey, bucket, region, domain string
|
|
|
|
|
|
|
|
|
|
|
|
switch ossConfig.StorageType {
|
|
|
|
|
|
case "aliyun":
|
|
|
|
|
|
// 优先使用专用字段
|
|
|
|
|
|
if ossConfig.OSSAccessKeyID != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.OSSAccessKeyID)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ossConfig.OSSAccessKeySecret != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.OSSAccessKeySecret)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bucket = ossConfig.OSSBucket
|
|
|
|
|
|
domain = ossConfig.OSSDomain
|
|
|
|
|
|
// 如果专用字段为空,使用通用字段(向后兼容)
|
|
|
|
|
|
if accessKey == "" && ossConfig.AccessKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.AccessKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if secretKey == "" && ossConfig.SecretKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.SecretKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if bucket == "" {
|
|
|
|
|
|
bucket = ossConfig.Bucket
|
|
|
|
|
|
}
|
|
|
|
|
|
if domain == "" {
|
|
|
|
|
|
domain = ossConfig.Domain
|
|
|
|
|
|
}
|
|
|
|
|
|
case "qcloud":
|
|
|
|
|
|
// 优先使用专用字段
|
|
|
|
|
|
if ossConfig.QCloudSecretID != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.QCloudSecretID)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ossConfig.QCloudSecretKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.QCloudSecretKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bucket = ossConfig.QCloudBucket
|
|
|
|
|
|
region = ossConfig.QCloudRegion
|
|
|
|
|
|
domain = ossConfig.QCloudDomain
|
|
|
|
|
|
// 向后兼容
|
|
|
|
|
|
if accessKey == "" && ossConfig.AccessKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.AccessKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if secretKey == "" && ossConfig.SecretKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.SecretKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if bucket == "" {
|
|
|
|
|
|
bucket = ossConfig.Bucket
|
|
|
|
|
|
}
|
|
|
|
|
|
if region == "" {
|
|
|
|
|
|
region = ossConfig.Region
|
|
|
|
|
|
}
|
|
|
|
|
|
if domain == "" {
|
|
|
|
|
|
domain = ossConfig.Domain
|
|
|
|
|
|
}
|
|
|
|
|
|
case "qiniu":
|
|
|
|
|
|
// 优先使用专用字段
|
|
|
|
|
|
if ossConfig.QiniuAccessKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.QiniuAccessKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ossConfig.QiniuSecretKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.QiniuSecretKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bucket = ossConfig.QiniuBucket
|
|
|
|
|
|
region = ossConfig.QiniuRegion
|
|
|
|
|
|
domain = ossConfig.QiniuDomain
|
|
|
|
|
|
// 向后兼容
|
|
|
|
|
|
if accessKey == "" && ossConfig.AccessKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.AccessKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if secretKey == "" && ossConfig.SecretKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.SecretKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if bucket == "" {
|
|
|
|
|
|
bucket = ossConfig.Bucket
|
|
|
|
|
|
}
|
|
|
|
|
|
if region == "" {
|
|
|
|
|
|
region = ossConfig.Region
|
|
|
|
|
|
}
|
|
|
|
|
|
if domain == "" {
|
|
|
|
|
|
domain = ossConfig.Domain
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
// 使用通用字段
|
|
|
|
|
|
if ossConfig.AccessKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.AccessKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ossConfig.SecretKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(ossConfig.SecretKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bucket = ossConfig.Bucket
|
|
|
|
|
|
region = ossConfig.Region
|
|
|
|
|
|
domain = ossConfig.Domain
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
config.AccessKey = accessKey
|
|
|
|
|
|
config.SecretKey = secretKey
|
2026-01-19 20:21:09 +08:00
|
|
|
|
config.Bucket = bucket
|
|
|
|
|
|
config.Region = region
|
|
|
|
|
|
config.Domain = domain
|
|
|
|
|
|
|
|
|
|
|
|
// 填充专用字段
|
|
|
|
|
|
switch ossConfig.StorageType {
|
|
|
|
|
|
case "aliyun":
|
|
|
|
|
|
config.OSSAccessKeyID = accessKey
|
|
|
|
|
|
config.OSSAccessKeySecret = secretKey
|
|
|
|
|
|
config.OSSEndpoint = ossConfig.OSSEndpoint
|
|
|
|
|
|
config.OSSBucket = bucket
|
|
|
|
|
|
config.OSSDomain = domain
|
|
|
|
|
|
case "qcloud":
|
|
|
|
|
|
config.QCloudSecretID = accessKey
|
|
|
|
|
|
config.QCloudSecretKey = secretKey
|
|
|
|
|
|
config.QCloudRegion = region
|
|
|
|
|
|
config.QCloudBucket = bucket
|
|
|
|
|
|
config.QCloudDomain = domain
|
|
|
|
|
|
case "qiniu":
|
|
|
|
|
|
config.QiniuAccessKey = accessKey
|
|
|
|
|
|
config.QiniuSecretKey = secretKey
|
|
|
|
|
|
config.QiniuBucket = bucket
|
|
|
|
|
|
config.QiniuRegion = region
|
|
|
|
|
|
config.QiniuDomain = domain
|
|
|
|
|
|
}
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取上传器
|
|
|
|
|
|
uploader, err := utils.GetOSSUploader(config)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 上传文件
|
|
|
|
|
|
filePath, fileURL, err := uploader.Upload(src, file.Filename, file.Size)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to upload file: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取文件类型
|
|
|
|
|
|
fileType := utils.GetFileType(file.Header.Get("Content-Type"))
|
|
|
|
|
|
|
|
|
|
|
|
// 创建附件记录
|
|
|
|
|
|
attachment := &models.Attachment{
|
|
|
|
|
|
CategoryID: categoryID,
|
|
|
|
|
|
OriginalName: file.Filename,
|
|
|
|
|
|
StoredName: file.Filename,
|
|
|
|
|
|
FilePath: filePath,
|
|
|
|
|
|
FileURL: fileURL,
|
|
|
|
|
|
FileSize: file.Size,
|
|
|
|
|
|
FileType: fileType,
|
|
|
|
|
|
MimeType: file.Header.Get("Content-Type"),
|
|
|
|
|
|
StorageType: storageType,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ossConfig != nil {
|
|
|
|
|
|
ossConfigID := ossConfig.ID
|
|
|
|
|
|
attachment.OSSConfigID = &ossConfigID
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := repositories.CreateAttachment(attachment); err != nil {
|
|
|
|
|
|
// 如果数据库保存失败,尝试删除已上传的文件
|
|
|
|
|
|
uploader.Delete(filePath)
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "File uploaded successfully", attachment)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminGetAttachments 获取附件列表
|
|
|
|
|
|
func AdminGetAttachments(c *gin.Context) {
|
|
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
|
|
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))
|
|
|
|
|
|
categoryIDStr := c.Query("categoryId")
|
|
|
|
|
|
fileType := c.Query("fileType")
|
|
|
|
|
|
|
|
|
|
|
|
var categoryID *uint
|
|
|
|
|
|
if categoryIDStr != "" {
|
|
|
|
|
|
if id, err := strconv.ParseUint(categoryIDStr, 10, 32); err == nil {
|
|
|
|
|
|
idUint := uint(id)
|
|
|
|
|
|
categoryID = &idUint
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
attachments, total, err := repositories.GetAttachments(page, pageSize, categoryID, fileType)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res := gin.H{
|
|
|
|
|
|
"list": attachments,
|
|
|
|
|
|
"total": total,
|
|
|
|
|
|
"page": page,
|
|
|
|
|
|
"size": pageSize,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.Success(c, res)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminDeleteAttachment 删除附件
|
|
|
|
|
|
func AdminDeleteAttachment(c *gin.Context) {
|
|
|
|
|
|
idStr := c.Param("id")
|
|
|
|
|
|
var id uint
|
|
|
|
|
|
if _, err := strconv.ParseUint(idStr, 10, 32); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid attachment ID")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取附件信息
|
|
|
|
|
|
attachment, err := repositories.GetAttachmentByID(id)
|
|
|
|
|
|
if err != nil || attachment == nil {
|
|
|
|
|
|
utils.Error(c, 404, "Attachment not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取OSS配置并删除文件
|
|
|
|
|
|
if attachment.StorageType != "" {
|
|
|
|
|
|
var ossConfig *models.OSSConfig
|
|
|
|
|
|
if attachment.OSSConfigID != nil {
|
|
|
|
|
|
ossConfig, err = repositories.GetOSSConfigByID(*attachment.OSSConfigID)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ossConfig, err = repositories.GetActiveOSSConfig(attachment.StorageType)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err == nil && ossConfig != nil {
|
|
|
|
|
|
config := &utils.OSSConfig{
|
|
|
|
|
|
StorageType: attachment.StorageType,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 根据存储类型从专用字段或通用字段读取配置
|
|
|
|
|
|
var accessKey, secretKey, bucket, region, domain string
|
|
|
|
|
|
|
|
|
|
|
|
switch ossConfig.StorageType {
|
|
|
|
|
|
case "aliyun":
|
|
|
|
|
|
if ossConfig.OSSAccessKeyID != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.OSSAccessKeyID); err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ossConfig.OSSAccessKeySecret != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.OSSAccessKeySecret); err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bucket = ossConfig.OSSBucket
|
|
|
|
|
|
domain = ossConfig.OSSDomain
|
|
|
|
|
|
// 向后兼容
|
|
|
|
|
|
if accessKey == "" && ossConfig.AccessKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.AccessKey); err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if secretKey == "" && ossConfig.SecretKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.SecretKey); err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if bucket == "" {
|
|
|
|
|
|
bucket = ossConfig.Bucket
|
|
|
|
|
|
}
|
|
|
|
|
|
if domain == "" {
|
|
|
|
|
|
domain = ossConfig.Domain
|
|
|
|
|
|
}
|
|
|
|
|
|
case "qcloud":
|
|
|
|
|
|
if ossConfig.QCloudSecretID != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.QCloudSecretID); err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ossConfig.QCloudSecretKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.QCloudSecretKey); err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bucket = ossConfig.QCloudBucket
|
|
|
|
|
|
region = ossConfig.QCloudRegion
|
|
|
|
|
|
domain = ossConfig.QCloudDomain
|
|
|
|
|
|
// 向后兼容
|
|
|
|
|
|
if accessKey == "" && ossConfig.AccessKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.AccessKey); err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if secretKey == "" && ossConfig.SecretKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.SecretKey); err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if bucket == "" {
|
|
|
|
|
|
bucket = ossConfig.Bucket
|
|
|
|
|
|
}
|
|
|
|
|
|
if region == "" {
|
|
|
|
|
|
region = ossConfig.Region
|
|
|
|
|
|
}
|
|
|
|
|
|
if domain == "" {
|
|
|
|
|
|
domain = ossConfig.Domain
|
|
|
|
|
|
}
|
|
|
|
|
|
case "qiniu":
|
|
|
|
|
|
if ossConfig.QiniuAccessKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.QiniuAccessKey); err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ossConfig.QiniuSecretKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.QiniuSecretKey); err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bucket = ossConfig.QiniuBucket
|
|
|
|
|
|
region = ossConfig.QiniuRegion
|
|
|
|
|
|
domain = ossConfig.QiniuDomain
|
|
|
|
|
|
// 向后兼容
|
|
|
|
|
|
if accessKey == "" && ossConfig.AccessKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.AccessKey); err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if secretKey == "" && ossConfig.SecretKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.SecretKey); err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if bucket == "" {
|
|
|
|
|
|
bucket = ossConfig.Bucket
|
|
|
|
|
|
}
|
|
|
|
|
|
if region == "" {
|
|
|
|
|
|
region = ossConfig.Region
|
|
|
|
|
|
}
|
|
|
|
|
|
if domain == "" {
|
|
|
|
|
|
domain = ossConfig.Domain
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
if ossConfig.AccessKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.AccessKey); err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ossConfig.SecretKey != "" {
|
|
|
|
|
|
if decrypted, err := utils.DecryptAES(ossConfig.SecretKey); err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
bucket = ossConfig.Bucket
|
|
|
|
|
|
region = ossConfig.Region
|
|
|
|
|
|
domain = ossConfig.Domain
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
|
|
|
|
|
|
config.AccessKey = accessKey
|
|
|
|
|
|
config.SecretKey = secretKey
|
|
|
|
|
|
config.Bucket = bucket
|
|
|
|
|
|
config.Region = region
|
|
|
|
|
|
config.Domain = domain
|
2026-01-19 16:14:08 +08:00
|
|
|
|
|
|
|
|
|
|
uploader, err := utils.GetOSSUploader(config)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
uploader.Delete(attachment.FilePath)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除数据库记录
|
|
|
|
|
|
if err := repositories.DeleteAttachment(id); err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "Attachment deleted successfully", nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// AdminUpdateAttachment 更新附件
|
|
|
|
|
|
func AdminUpdateAttachment(c *gin.Context) {
|
|
|
|
|
|
idStr := c.Param("id")
|
|
|
|
|
|
var id uint
|
|
|
|
|
|
if _, err := strconv.ParseUint(idStr, 10, 32); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid attachment ID")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取现有附件
|
|
|
|
|
|
attachment, err := repositories.GetAttachmentByID(id)
|
|
|
|
|
|
if err != nil || attachment == nil {
|
|
|
|
|
|
utils.Error(c, 404, "Attachment not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析请求体
|
|
|
|
|
|
var req struct {
|
|
|
|
|
|
CategoryID *uint `json:"categoryId"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid request")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新分类ID
|
|
|
|
|
|
if req.CategoryID != nil {
|
|
|
|
|
|
if *req.CategoryID == 0 {
|
|
|
|
|
|
// 如果categoryId为0,设置为nil(无分类)
|
|
|
|
|
|
attachment.CategoryID = nil
|
|
|
|
|
|
} else {
|
|
|
|
|
|
attachment.CategoryID = req.CategoryID
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新附件
|
|
|
|
|
|
if err := repositories.UpdateAttachment(attachment); err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重新获取更新后的附件(包含关联的分类信息)
|
|
|
|
|
|
updatedAttachment, err := repositories.GetAttachmentByID(id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "Attachment updated successfully", updatedAttachment)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 16:14:08 +08:00
|
|
|
|
// AdminGetAttachmentCategories 获取附件分类列表
|
|
|
|
|
|
func AdminGetAttachmentCategories(c *gin.Context) {
|
|
|
|
|
|
categories, err := repositories.GetAttachmentCategories()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.Success(c, categories)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminCreateAttachmentCategory 创建附件分类
|
|
|
|
|
|
func AdminCreateAttachmentCategory(c *gin.Context) {
|
|
|
|
|
|
var category models.AttachmentCategory
|
|
|
|
|
|
if err := c.ShouldBindJSON(&category); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid request")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := repositories.CreateAttachmentCategory(&category); err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "Category created successfully", category)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminUpdateAttachmentCategory 更新附件分类
|
|
|
|
|
|
func AdminUpdateAttachmentCategory(c *gin.Context) {
|
|
|
|
|
|
idStr := c.Param("id")
|
|
|
|
|
|
var id uint
|
|
|
|
|
|
if _, err := strconv.ParseUint(idStr, 10, 32); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid category ID")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var category models.AttachmentCategory
|
|
|
|
|
|
if err := c.ShouldBindJSON(&category); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid request")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
category.ID = id
|
|
|
|
|
|
|
|
|
|
|
|
if err := repositories.UpdateAttachmentCategory(&category); err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "Category updated successfully", nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminDeleteAttachmentCategory 删除附件分类
|
|
|
|
|
|
func AdminDeleteAttachmentCategory(c *gin.Context) {
|
|
|
|
|
|
idStr := c.Param("id")
|
|
|
|
|
|
var id uint
|
|
|
|
|
|
if _, err := strconv.ParseUint(idStr, 10, 32); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid category ID")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := repositories.DeleteAttachmentCategory(id); err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "Category deleted successfully", nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminGetOSSConfigs 获取OSS配置列表
|
|
|
|
|
|
func AdminGetOSSConfigs(c *gin.Context) {
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 检查是否存在默认本地存储配置,如果不存在则创建
|
|
|
|
|
|
defaultConfig, err := repositories.GetDefaultLocalOSSConfig()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Printf("Error checking default local OSS config: %v", err)
|
|
|
|
|
|
} else if defaultConfig == nil {
|
|
|
|
|
|
// 创建默认本地存储配置
|
|
|
|
|
|
// 本地存储不需要AccessKey和SecretKey,直接使用空字符串(不加密)
|
|
|
|
|
|
defaultOSSConfig := &models.OSSConfig{
|
|
|
|
|
|
Name: "本地存储",
|
|
|
|
|
|
StorageType: "local",
|
|
|
|
|
|
AccessKey: "", // 空字符串,不加密
|
|
|
|
|
|
SecretKey: "", // 空字符串,不加密
|
|
|
|
|
|
Bucket: "",
|
|
|
|
|
|
Region: "",
|
|
|
|
|
|
Domain: "",
|
|
|
|
|
|
IsActive: 1,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := repositories.CreateOSSConfig(defaultOSSConfig); err != nil {
|
|
|
|
|
|
log.Printf("Error creating default local OSS config: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 16:14:08 +08:00
|
|
|
|
configs, err := repositories.GetOSSConfigs()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不返回加密的密钥
|
|
|
|
|
|
for i := range configs {
|
|
|
|
|
|
configs[i].AccessKey = "***"
|
|
|
|
|
|
configs[i].SecretKey = "***"
|
2026-01-19 20:21:09 +08:00
|
|
|
|
configs[i].OSSAccessKeyID = "***"
|
|
|
|
|
|
configs[i].OSSAccessKeySecret = "***"
|
|
|
|
|
|
configs[i].QCloudSecretID = "***"
|
|
|
|
|
|
configs[i].QCloudSecretKey = "***"
|
|
|
|
|
|
configs[i].QiniuAccessKey = "***"
|
|
|
|
|
|
configs[i].QiniuSecretKey = "***"
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.Success(c, configs)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminCreateOSSConfig 创建OSS配置
|
|
|
|
|
|
func AdminCreateOSSConfig(c *gin.Context) {
|
|
|
|
|
|
var req struct {
|
|
|
|
|
|
Name string `json:"name" binding:"required"`
|
|
|
|
|
|
StorageType string `json:"storageType" binding:"required"`
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 通用字段(向后兼容)
|
|
|
|
|
|
AccessKey string `json:"accessKey"`
|
|
|
|
|
|
SecretKey string `json:"secretKey"`
|
|
|
|
|
|
Bucket string `json:"bucket"`
|
|
|
|
|
|
Region string `json:"region"`
|
|
|
|
|
|
Domain string `json:"domain"`
|
|
|
|
|
|
// 阿里云OSS专用字段
|
|
|
|
|
|
OSSAccessKeyID string `json:"ossAccessKeyId"`
|
|
|
|
|
|
OSSAccessKeySecret string `json:"ossAccessKeySecret"`
|
|
|
|
|
|
OSSEndpoint string `json:"ossEndpoint"`
|
|
|
|
|
|
OSSBucket string `json:"ossBucket"`
|
|
|
|
|
|
OSSDomain string `json:"ossDomain"`
|
|
|
|
|
|
// 腾讯云COS专用字段
|
|
|
|
|
|
QCloudSecretID string `json:"qcloudSecretId"`
|
|
|
|
|
|
QCloudSecretKey string `json:"qcloudSecretKey"`
|
|
|
|
|
|
QCloudRegion string `json:"qcloudRegion"`
|
|
|
|
|
|
QCloudBucket string `json:"qcloudBucket"`
|
|
|
|
|
|
QCloudDomain string `json:"qcloudDomain"`
|
|
|
|
|
|
// 七牛云专用字段
|
|
|
|
|
|
QiniuAccessKey string `json:"qiniuAccessKey"`
|
|
|
|
|
|
QiniuSecretKey string `json:"qiniuSecretKey"`
|
|
|
|
|
|
QiniuBucket string `json:"qiniuBucket"`
|
|
|
|
|
|
QiniuRegion string `json:"qiniuRegion"`
|
|
|
|
|
|
QiniuDomain string `json:"qiniuDomain"`
|
|
|
|
|
|
IsActive int `json:"isActive"`
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid request")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 加密函数
|
|
|
|
|
|
encryptKey := func(key string) (string, error) {
|
|
|
|
|
|
if key == "" {
|
|
|
|
|
|
return "", nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return utils.EncryptAES(key)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加密通用密钥(向后兼容)
|
|
|
|
|
|
encryptedAccessKey, err := encryptKey(req.AccessKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt access key: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
encryptedSecretKey, err := encryptKey(req.SecretKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt secret key: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加密阿里云密钥
|
|
|
|
|
|
encryptedOSSAccessKeyID, err := encryptKey(req.OSSAccessKeyID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt OSS access key ID: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
encryptedOSSAccessKeySecret, err := encryptKey(req.OSSAccessKeySecret)
|
2026-01-19 16:14:08 +08:00
|
|
|
|
if err != nil {
|
2026-01-19 20:21:09 +08:00
|
|
|
|
utils.Error(c, 500, "Failed to encrypt OSS access key secret: "+err.Error())
|
2026-01-19 16:14:08 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 加密腾讯云密钥
|
|
|
|
|
|
encryptedQCloudSecretID, err := encryptKey(req.QCloudSecretID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt QCloud secret ID: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
encryptedQCloudSecretKey, err := encryptKey(req.QCloudSecretKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt QCloud secret key: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加密七牛云密钥
|
|
|
|
|
|
encryptedQiniuAccessKey, err := encryptKey(req.QiniuAccessKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt Qiniu access key: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
encryptedQiniuSecretKey, err := encryptKey(req.QiniuSecretKey)
|
2026-01-19 16:14:08 +08:00
|
|
|
|
if err != nil {
|
2026-01-19 20:21:09 +08:00
|
|
|
|
utils.Error(c, 500, "Failed to encrypt Qiniu secret key: "+err.Error())
|
2026-01-19 16:14:08 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ossConfig := &models.OSSConfig{
|
|
|
|
|
|
Name: req.Name,
|
|
|
|
|
|
StorageType: req.StorageType,
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 通用字段(向后兼容)
|
|
|
|
|
|
AccessKey: encryptedAccessKey,
|
|
|
|
|
|
SecretKey: encryptedSecretKey,
|
|
|
|
|
|
Bucket: req.Bucket,
|
|
|
|
|
|
Region: req.Region,
|
|
|
|
|
|
Domain: req.Domain,
|
|
|
|
|
|
// 阿里云OSS专用字段
|
|
|
|
|
|
OSSAccessKeyID: encryptedOSSAccessKeyID,
|
|
|
|
|
|
OSSAccessKeySecret: encryptedOSSAccessKeySecret,
|
|
|
|
|
|
OSSEndpoint: req.OSSEndpoint,
|
|
|
|
|
|
OSSBucket: req.OSSBucket,
|
|
|
|
|
|
OSSDomain: req.OSSDomain,
|
|
|
|
|
|
// 腾讯云COS专用字段
|
|
|
|
|
|
QCloudSecretID: encryptedQCloudSecretID,
|
|
|
|
|
|
QCloudSecretKey: encryptedQCloudSecretKey,
|
|
|
|
|
|
QCloudRegion: req.QCloudRegion,
|
|
|
|
|
|
QCloudBucket: req.QCloudBucket,
|
|
|
|
|
|
QCloudDomain: req.QCloudDomain,
|
|
|
|
|
|
// 七牛云专用字段
|
|
|
|
|
|
QiniuAccessKey: encryptedQiniuAccessKey,
|
|
|
|
|
|
QiniuSecretKey: encryptedQiniuSecretKey,
|
|
|
|
|
|
QiniuBucket: req.QiniuBucket,
|
|
|
|
|
|
QiniuRegion: req.QiniuRegion,
|
|
|
|
|
|
QiniuDomain: req.QiniuDomain,
|
|
|
|
|
|
IsActive: req.IsActive,
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := repositories.CreateOSSConfig(ossConfig); err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不返回加密的密钥
|
|
|
|
|
|
ossConfig.AccessKey = "***"
|
|
|
|
|
|
ossConfig.SecretKey = "***"
|
2026-01-19 20:21:09 +08:00
|
|
|
|
ossConfig.OSSAccessKeyID = "***"
|
|
|
|
|
|
ossConfig.OSSAccessKeySecret = "***"
|
|
|
|
|
|
ossConfig.QCloudSecretID = "***"
|
|
|
|
|
|
ossConfig.QCloudSecretKey = "***"
|
|
|
|
|
|
ossConfig.QiniuAccessKey = "***"
|
|
|
|
|
|
ossConfig.QiniuSecretKey = "***"
|
2026-01-19 16:14:08 +08:00
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "OSS config created successfully", ossConfig)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminUpdateOSSConfig 更新OSS配置
|
|
|
|
|
|
func AdminUpdateOSSConfig(c *gin.Context) {
|
|
|
|
|
|
idStr := c.Param("id")
|
|
|
|
|
|
var id uint
|
|
|
|
|
|
if _, err := strconv.ParseUint(idStr, 10, 32); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid OSS config ID")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var req struct {
|
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
|
StorageType string `json:"storageType"`
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 通用字段(向后兼容)
|
|
|
|
|
|
AccessKey string `json:"accessKey"`
|
|
|
|
|
|
SecretKey string `json:"secretKey"`
|
|
|
|
|
|
Bucket string `json:"bucket"`
|
|
|
|
|
|
Region string `json:"region"`
|
|
|
|
|
|
Domain string `json:"domain"`
|
|
|
|
|
|
// 阿里云OSS专用字段
|
|
|
|
|
|
OSSAccessKeyID string `json:"ossAccessKeyId"`
|
|
|
|
|
|
OSSAccessKeySecret string `json:"ossAccessKeySecret"`
|
|
|
|
|
|
OSSEndpoint string `json:"ossEndpoint"`
|
|
|
|
|
|
OSSBucket string `json:"ossBucket"`
|
|
|
|
|
|
OSSDomain string `json:"ossDomain"`
|
|
|
|
|
|
// 腾讯云COS专用字段
|
|
|
|
|
|
QCloudSecretID string `json:"qcloudSecretId"`
|
|
|
|
|
|
QCloudSecretKey string `json:"qcloudSecretKey"`
|
|
|
|
|
|
QCloudRegion string `json:"qcloudRegion"`
|
|
|
|
|
|
QCloudBucket string `json:"qcloudBucket"`
|
|
|
|
|
|
QCloudDomain string `json:"qcloudDomain"`
|
|
|
|
|
|
// 七牛云专用字段
|
|
|
|
|
|
QiniuAccessKey string `json:"qiniuAccessKey"`
|
|
|
|
|
|
QiniuSecretKey string `json:"qiniuSecretKey"`
|
|
|
|
|
|
QiniuBucket string `json:"qiniuBucket"`
|
|
|
|
|
|
QiniuRegion string `json:"qiniuRegion"`
|
|
|
|
|
|
QiniuDomain string `json:"qiniuDomain"`
|
|
|
|
|
|
IsActive int `json:"isActive"`
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid request")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取现有配置
|
|
|
|
|
|
existingConfig, err := repositories.GetOSSConfigByID(id)
|
|
|
|
|
|
if err != nil || existingConfig == nil {
|
|
|
|
|
|
utils.Error(c, 404, "OSS config not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 检查是否要启用配置,如果是非local类型,需要验证AccessKey和SecretKey
|
|
|
|
|
|
if req.IsActive == 1 && existingConfig.IsActive == 0 {
|
|
|
|
|
|
// 检查当前配置的AccessKey和SecretKey(需要解密)
|
|
|
|
|
|
var accessKey, secretKey string
|
|
|
|
|
|
if existingConfig.AccessKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(existingConfig.AccessKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
accessKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if existingConfig.SecretKey != "" {
|
|
|
|
|
|
decrypted, err := utils.DecryptAES(existingConfig.SecretKey)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
secretKey = decrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果提供了新的AccessKey或SecretKey,使用新的
|
|
|
|
|
|
if req.AccessKey != "" && req.AccessKey != "***" {
|
|
|
|
|
|
accessKey = req.AccessKey
|
|
|
|
|
|
}
|
|
|
|
|
|
if req.SecretKey != "" && req.SecretKey != "***" {
|
|
|
|
|
|
secretKey = req.SecretKey
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 对于非local类型,必须填写AccessKey和SecretKey
|
|
|
|
|
|
if existingConfig.StorageType != "local" && (accessKey == "" || secretKey == "") {
|
|
|
|
|
|
utils.Error(c, 400, "启用非本地存储配置前必须填写AccessKey和SecretKey")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加密函数
|
|
|
|
|
|
encryptKey := func(key string) (string, error) {
|
|
|
|
|
|
if key == "" {
|
|
|
|
|
|
return "", nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return utils.EncryptAES(key)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 16:14:08 +08:00
|
|
|
|
// 更新字段
|
|
|
|
|
|
if req.Name != "" {
|
|
|
|
|
|
existingConfig.Name = req.Name
|
|
|
|
|
|
}
|
|
|
|
|
|
if req.StorageType != "" {
|
|
|
|
|
|
existingConfig.StorageType = req.StorageType
|
|
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理通用字段(向后兼容)
|
|
|
|
|
|
if req.AccessKey != "***" {
|
|
|
|
|
|
encrypted, err := encryptKey(req.AccessKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt access key: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
existingConfig.AccessKey = encrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
if req.SecretKey != "***" {
|
|
|
|
|
|
encrypted, err := encryptKey(req.SecretKey)
|
2026-01-19 16:14:08 +08:00
|
|
|
|
if err != nil {
|
2026-01-19 20:21:09 +08:00
|
|
|
|
utils.Error(c, 500, "Failed to encrypt secret key: "+err.Error())
|
2026-01-19 16:14:08 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
existingConfig.SecretKey = encrypted
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 更新通用字段(允许空字符串)
|
|
|
|
|
|
existingConfig.Bucket = req.Bucket
|
|
|
|
|
|
existingConfig.Region = req.Region
|
|
|
|
|
|
existingConfig.Domain = req.Domain
|
|
|
|
|
|
|
|
|
|
|
|
// 处理阿里云OSS专用字段
|
|
|
|
|
|
if req.OSSAccessKeyID != "***" {
|
|
|
|
|
|
encrypted, err := encryptKey(req.OSSAccessKeyID)
|
2026-01-19 16:14:08 +08:00
|
|
|
|
if err != nil {
|
2026-01-19 20:21:09 +08:00
|
|
|
|
utils.Error(c, 500, "Failed to encrypt OSS access key ID: "+err.Error())
|
2026-01-19 16:14:08 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
existingConfig.OSSAccessKeyID = encrypted
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
if req.OSSAccessKeySecret != "***" {
|
|
|
|
|
|
encrypted, err := encryptKey(req.OSSAccessKeySecret)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt OSS access key secret: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
existingConfig.OSSAccessKeySecret = encrypted
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
existingConfig.OSSEndpoint = req.OSSEndpoint
|
|
|
|
|
|
existingConfig.OSSBucket = req.OSSBucket
|
|
|
|
|
|
existingConfig.OSSDomain = req.OSSDomain
|
|
|
|
|
|
|
|
|
|
|
|
// 处理腾讯云COS专用字段
|
|
|
|
|
|
if req.QCloudSecretID != "***" {
|
|
|
|
|
|
encrypted, err := encryptKey(req.QCloudSecretID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt QCloud secret ID: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
existingConfig.QCloudSecretID = encrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
if req.QCloudSecretKey != "***" {
|
|
|
|
|
|
encrypted, err := encryptKey(req.QCloudSecretKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt QCloud secret key: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
existingConfig.QCloudSecretKey = encrypted
|
|
|
|
|
|
}
|
|
|
|
|
|
existingConfig.QCloudRegion = req.QCloudRegion
|
|
|
|
|
|
existingConfig.QCloudBucket = req.QCloudBucket
|
|
|
|
|
|
existingConfig.QCloudDomain = req.QCloudDomain
|
|
|
|
|
|
|
|
|
|
|
|
// 处理七牛云专用字段
|
|
|
|
|
|
if req.QiniuAccessKey != "***" {
|
|
|
|
|
|
encrypted, err := encryptKey(req.QiniuAccessKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt Qiniu access key: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
existingConfig.QiniuAccessKey = encrypted
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
if req.QiniuSecretKey != "***" {
|
|
|
|
|
|
encrypted, err := encryptKey(req.QiniuSecretKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.Error(c, 500, "Failed to encrypt Qiniu secret key: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
existingConfig.QiniuSecretKey = encrypted
|
2026-01-19 16:14:08 +08:00
|
|
|
|
}
|
2026-01-19 20:21:09 +08:00
|
|
|
|
existingConfig.QiniuBucket = req.QiniuBucket
|
|
|
|
|
|
existingConfig.QiniuRegion = req.QiniuRegion
|
|
|
|
|
|
existingConfig.QiniuDomain = req.QiniuDomain
|
|
|
|
|
|
|
2026-01-19 16:14:08 +08:00
|
|
|
|
existingConfig.IsActive = req.IsActive
|
|
|
|
|
|
|
|
|
|
|
|
if err := repositories.UpdateOSSConfig(existingConfig); err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不返回加密的密钥
|
|
|
|
|
|
existingConfig.AccessKey = "***"
|
|
|
|
|
|
existingConfig.SecretKey = "***"
|
2026-01-19 20:21:09 +08:00
|
|
|
|
existingConfig.OSSAccessKeyID = "***"
|
|
|
|
|
|
existingConfig.OSSAccessKeySecret = "***"
|
|
|
|
|
|
existingConfig.QCloudSecretID = "***"
|
|
|
|
|
|
existingConfig.QCloudSecretKey = "***"
|
|
|
|
|
|
existingConfig.QiniuAccessKey = "***"
|
|
|
|
|
|
existingConfig.QiniuSecretKey = "***"
|
2026-01-19 16:14:08 +08:00
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "OSS config updated successfully", existingConfig)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AdminDeleteOSSConfig 删除OSS配置
|
|
|
|
|
|
func AdminDeleteOSSConfig(c *gin.Context) {
|
|
|
|
|
|
idStr := c.Param("id")
|
|
|
|
|
|
var id uint
|
|
|
|
|
|
if _, err := strconv.ParseUint(idStr, 10, 32); err != nil {
|
|
|
|
|
|
utils.Error(c, 400, "Invalid OSS config ID")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 20:21:09 +08:00
|
|
|
|
// 获取配置信息,检查是否为默认本地存储配置
|
|
|
|
|
|
ossConfig, err := repositories.GetOSSConfigByID(id)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ossConfig == nil {
|
|
|
|
|
|
utils.Error(c, 404, "OSS config not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否为默认本地存储配置,不允许删除
|
|
|
|
|
|
if ossConfig.Name == "本地存储" && ossConfig.StorageType == "local" {
|
|
|
|
|
|
utils.Error(c, 400, "默认本地存储配置不能删除")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 16:14:08 +08:00
|
|
|
|
if err := repositories.DeleteOSSConfig(id); err != nil {
|
|
|
|
|
|
utils.ServerError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
utils.SuccessWithMsg(c, "OSS config deleted successfully", nil)
|
|
|
|
|
|
}
|