98986b0eb7
数据库配置: - SQLite 开启 WAL 模式,读写可并发 - 设置 busy_timeout=5000ms 避免锁超时 - 设置 synchronous=NORMAL 平衡性能和安全 - SQLite MaxOpenConns 设为 1 避免并发写入冲突 事务修复: - auth.go: 注册流程(用户+设备+会话)加入事务 - auth.go: 密码重置(修改密码+标记验证码)加入事务 - cards.go: 卡密使用加入事务,补充 UsedAt 字段 - cards.go: 代理商批量生成(扣款+生成卡密)加入事务 - extension.go: 充值(修改余额+记录)加入事务 - extension.go: 扣费(修改余额+记录)加入事务 - storage_config.go: 设置默认存储加入事务
437 lines
10 KiB
Go
437 lines
10 KiB
Go
package admin
|
|
|
|
import (
|
|
"net/http"
|
|
"verification-platform-backend/internal/database"
|
|
"verification-platform-backend/internal/model"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func SetupStorageConfigRoutes(r *gin.RouterGroup) {
|
|
storageConfigs := r.Group("/storage-configs")
|
|
{
|
|
storageConfigs.GET("", handleGetStorageConfigs)
|
|
storageConfigs.POST("", handleCreateStorageConfig)
|
|
storageConfigs.POST("/test", handleTestStorageConfigNew)
|
|
storageConfigs.GET("/:id", handleGetStorageConfig)
|
|
storageConfigs.PUT("/:id", handleUpdateStorageConfig)
|
|
storageConfigs.DELETE("/:id", handleDeleteStorageConfig)
|
|
storageConfigs.PUT("/:id/status", handleUpdateStorageConfigStatus)
|
|
storageConfigs.PUT("/:id/default", handleSetDefaultStorageConfig)
|
|
storageConfigs.POST("/:id/test", handleTestStorageConfig)
|
|
storageConfigs.PUT("/batch/status", handleBatchUpdateStorageConfigStatus)
|
|
storageConfigs.DELETE("/batch", handleBatchDeleteStorageConfigs)
|
|
}
|
|
}
|
|
|
|
func handleGetStorageConfigs(c *gin.Context) {
|
|
var configs []model.StorageConfig
|
|
database.DB.Order("id desc").Find(&configs)
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"data": gin.H{
|
|
"storage_configs": configs,
|
|
},
|
|
})
|
|
}
|
|
|
|
type CreateStorageConfigRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Type string `json:"type" binding:"required"`
|
|
Endpoint string `json:"endpoint"`
|
|
Bucket string `json:"bucket"`
|
|
AccessKey string `json:"access_key"`
|
|
SecretKey string `json:"secret_key"`
|
|
Region string `json:"region"`
|
|
PathPrefix string `json:"path_prefix"`
|
|
IsDefault bool `json:"is_default"`
|
|
Remark string `json:"remark"`
|
|
}
|
|
|
|
func handleCreateStorageConfig(c *gin.Context) {
|
|
var req CreateStorageConfigRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "无效的请求数据",
|
|
})
|
|
return
|
|
}
|
|
|
|
var config model.StorageConfig
|
|
|
|
if req.IsDefault {
|
|
tx := database.DB.Begin()
|
|
tx.Model(&model.StorageConfig{}).Where("is_default = ?", true).Update("is_default", false)
|
|
config = model.StorageConfig{
|
|
Name: req.Name,
|
|
Type: req.Type,
|
|
Endpoint: req.Endpoint,
|
|
Bucket: req.Bucket,
|
|
AccessKey: req.AccessKey,
|
|
SecretKey: req.SecretKey,
|
|
Region: req.Region,
|
|
PathPrefix: req.PathPrefix,
|
|
IsDefault: req.IsDefault,
|
|
Status: "active",
|
|
Remark: req.Remark,
|
|
}
|
|
if err := tx.Create(&config).Error; err != nil {
|
|
tx.Rollback()
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"code": 500,
|
|
"message": "创建失败",
|
|
})
|
|
return
|
|
}
|
|
tx.Commit()
|
|
} else {
|
|
config = model.StorageConfig{
|
|
Name: req.Name,
|
|
Type: req.Type,
|
|
Endpoint: req.Endpoint,
|
|
Bucket: req.Bucket,
|
|
AccessKey: req.AccessKey,
|
|
SecretKey: req.SecretKey,
|
|
Region: req.Region,
|
|
PathPrefix: req.PathPrefix,
|
|
IsDefault: req.IsDefault,
|
|
Status: "active",
|
|
Remark: req.Remark,
|
|
}
|
|
if err := database.DB.Create(&config).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"code": 500,
|
|
"message": "创建失败",
|
|
})
|
|
return
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "创建成功",
|
|
"data": config,
|
|
})
|
|
}
|
|
|
|
func handleGetStorageConfig(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var config model.StorageConfig
|
|
if err := database.DB.First(&config, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"code": 404,
|
|
"message": "存储配置不存在",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"data": config,
|
|
})
|
|
}
|
|
|
|
type UpdateStorageConfigRequest struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Endpoint string `json:"endpoint"`
|
|
Bucket string `json:"bucket"`
|
|
AccessKey string `json:"access_key"`
|
|
SecretKey string `json:"secret_key"`
|
|
Region string `json:"region"`
|
|
PathPrefix string `json:"path_prefix"`
|
|
IsDefault bool `json:"is_default"`
|
|
Status string `json:"status"`
|
|
Remark string `json:"remark"`
|
|
}
|
|
|
|
func handleUpdateStorageConfig(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var config model.StorageConfig
|
|
if err := database.DB.First(&config, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"code": 404,
|
|
"message": "存储配置不存在",
|
|
})
|
|
return
|
|
}
|
|
|
|
var req UpdateStorageConfigRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "无效的请求数据",
|
|
})
|
|
return
|
|
}
|
|
|
|
if req.IsDefault && !config.IsDefault {
|
|
database.DB.Model(&model.StorageConfig{}).Where("is_default = ?", true).Update("is_default", false)
|
|
}
|
|
|
|
if req.Name != "" {
|
|
config.Name = req.Name
|
|
}
|
|
if req.Type != "" {
|
|
config.Type = req.Type
|
|
}
|
|
config.Endpoint = req.Endpoint
|
|
config.Bucket = req.Bucket
|
|
config.AccessKey = req.AccessKey
|
|
config.SecretKey = req.SecretKey
|
|
config.Region = req.Region
|
|
config.PathPrefix = req.PathPrefix
|
|
config.IsDefault = req.IsDefault
|
|
if req.Status != "" {
|
|
config.Status = req.Status
|
|
}
|
|
config.Remark = req.Remark
|
|
|
|
if err := database.DB.Save(&config).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"code": 500,
|
|
"message": "更新失败",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "更新成功",
|
|
"data": config,
|
|
})
|
|
}
|
|
|
|
func handleDeleteStorageConfig(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var config model.StorageConfig
|
|
if err := database.DB.First(&config, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"code": 404,
|
|
"message": "存储配置不存在",
|
|
})
|
|
return
|
|
}
|
|
|
|
if config.Type == "local" {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "本地存储不能删除",
|
|
})
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Delete(&config).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"code": 500,
|
|
"message": "删除失败",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "删除成功",
|
|
})
|
|
}
|
|
|
|
type UpdateStorageConfigStatusRequest struct {
|
|
Status string `json:"status" binding:"required"`
|
|
}
|
|
|
|
func handleUpdateStorageConfigStatus(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var config model.StorageConfig
|
|
if err := database.DB.First(&config, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"code": 404,
|
|
"message": "存储配置不存在",
|
|
})
|
|
return
|
|
}
|
|
|
|
var req UpdateStorageConfigStatusRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "无效的请求数据",
|
|
})
|
|
return
|
|
}
|
|
|
|
config.Status = req.Status
|
|
if err := database.DB.Save(&config).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"code": 500,
|
|
"message": "更新失败",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "更新成功",
|
|
})
|
|
}
|
|
|
|
func handleSetDefaultStorageConfig(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var config model.StorageConfig
|
|
if err := database.DB.First(&config, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"code": 404,
|
|
"message": "存储配置不存在",
|
|
})
|
|
return
|
|
}
|
|
|
|
database.DB.Model(&model.StorageConfig{}).Where("is_default = ?", true).Update("is_default", false)
|
|
|
|
config.IsDefault = true
|
|
if err := database.DB.Save(&config).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"code": 500,
|
|
"message": "设置失败",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "设置成功",
|
|
})
|
|
}
|
|
|
|
func handleTestStorageConfigNew(c *gin.Context) {
|
|
var req CreateStorageConfigRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "无效的请求数据",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "连接成功",
|
|
})
|
|
}
|
|
|
|
func handleTestStorageConfig(c *gin.Context) {
|
|
id := c.Param("id")
|
|
|
|
var config model.StorageConfig
|
|
if err := database.DB.First(&config, id).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"code": 404,
|
|
"message": "存储配置不存在",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "连接成功",
|
|
})
|
|
}
|
|
|
|
type BatchUpdateStorageConfigStatusRequest struct {
|
|
IDs []uint `json:"ids"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
func handleBatchUpdateStorageConfigStatus(c *gin.Context) {
|
|
var req BatchUpdateStorageConfigStatusRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "参数错误",
|
|
})
|
|
return
|
|
}
|
|
|
|
if req.Status != "active" && req.Status != "inactive" {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "无效的状态",
|
|
})
|
|
return
|
|
}
|
|
|
|
if len(req.IDs) == 0 {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "请选择要更新的存储配置",
|
|
})
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Model(&model.StorageConfig{}).Where("id IN ?", req.IDs).Update("status", req.Status).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"code": 500,
|
|
"message": "批量更新失败",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "批量更新成功",
|
|
})
|
|
}
|
|
|
|
type BatchDeleteStorageConfigsRequest struct {
|
|
IDs []uint `json:"ids"`
|
|
}
|
|
|
|
func handleBatchDeleteStorageConfigs(c *gin.Context) {
|
|
var req BatchDeleteStorageConfigsRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "参数错误",
|
|
})
|
|
return
|
|
}
|
|
|
|
if len(req.IDs) == 0 {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "请选择要删除的存储配置",
|
|
})
|
|
return
|
|
}
|
|
|
|
var localConfigs []model.StorageConfig
|
|
database.DB.Where("id IN ? AND type = ?", req.IDs, "local").Find(&localConfigs)
|
|
if len(localConfigs) > 0 {
|
|
c.JSON(http.StatusBadRequest, gin.H{
|
|
"code": 400,
|
|
"message": "本地存储不能删除",
|
|
})
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Where("id IN ?", req.IDs).Delete(&model.StorageConfig{}).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"code": 500,
|
|
"message": "批量删除失败",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"message": "批量删除成功",
|
|
})
|
|
}
|