ea8ffb6c74
- 修复订阅模式登录时错误检查余额的问题 - 区分无限余额和永久订阅两种永久会员类型 - 修复动态代码HTTP请求返回值在JS中无法正确访问的问题 - 添加侧边栏滚动位置保持功能 - 移除developer角色相关代码,统一使用admin - 添加缺失的i18n翻译key
919 lines
26 KiB
Go
919 lines
26 KiB
Go
package app
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"verification-platform-backend/internal/database"
|
|
"verification-platform-backend/internal/middleware"
|
|
"verification-platform-backend/internal/model"
|
|
"verification-platform-backend/internal/service"
|
|
"verification-platform-backend/pkg/response"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func SetupCloudRoutes(r *gin.RouterGroup) {
|
|
r.GET("/constants", handleAppGetConstants)
|
|
r.GET("/constants/:key", handleAppGetConstantByKey)
|
|
r.GET("/constants/:key/download", handleAppDownloadConstant)
|
|
r.GET("/variables", handleAppGetVariables)
|
|
r.GET("/variables/:key", handleAppGetVariableByKey)
|
|
r.GET("/variables/:key/download", handleAppDownloadVariable)
|
|
r.POST("/variables/:key/upload", handleAppUploadVariableBinary)
|
|
r.POST("/variables", handleAppUpdateVariables)
|
|
r.POST("/variables/:key/records", handleAppCreateVariableRecord)
|
|
r.GET("/variables/:key/records", handleAppGetVariableRecords)
|
|
r.DELETE("/variables/:key/records/:record_id", handleAppDeleteVariableRecord)
|
|
r.POST("/call-function", handleAppCallFunction)
|
|
}
|
|
|
|
func handleAppGetConstants(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端常量")
|
|
return
|
|
}
|
|
|
|
var constants []model.CloudConstant
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND status = ?", app.UserID, app.ID, "active").Find(&constants).Error; err != nil {
|
|
response.Error(c, 500, "获取云端常量失败")
|
|
return
|
|
}
|
|
|
|
result := make(map[string]interface{})
|
|
for _, constant := range constants {
|
|
if constant.VarType == "binary" {
|
|
result[constant.Key] = gin.H{
|
|
"type": "binary",
|
|
"value": "/api/v1/app/" + appKey + "/constants/" + constant.Key + "/download",
|
|
"file_name": constant.OriginalName,
|
|
"file_size": constant.FileSize,
|
|
"md5": constant.FileMD5,
|
|
"mime_type": constant.MimeType,
|
|
}
|
|
} else {
|
|
result[constant.Key] = gin.H{
|
|
"type": constant.VarType,
|
|
"value": constant.Value,
|
|
}
|
|
}
|
|
}
|
|
|
|
response.Success(c, result)
|
|
}
|
|
|
|
func handleAppGetConstantByKey(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端常量")
|
|
return
|
|
}
|
|
|
|
var constant model.CloudConstant
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND key = ? AND status = ?", app.UserID, app.ID, key, "active").First(&constant).Error; err != nil {
|
|
response.Error(c, 404, "云端常量不存在")
|
|
return
|
|
}
|
|
|
|
if constant.VarType == "binary" {
|
|
response.Success(c, gin.H{
|
|
"key": constant.Key,
|
|
"type": "binary",
|
|
"value": "/api/v1/app/" + appKey + "/constants/" + constant.Key + "/download",
|
|
"file_name": constant.OriginalName,
|
|
"file_size": constant.FileSize,
|
|
"md5": constant.FileMD5,
|
|
"mime_type": constant.MimeType,
|
|
})
|
|
} else {
|
|
response.Success(c, gin.H{
|
|
"key": constant.Key,
|
|
"type": constant.VarType,
|
|
"value": constant.Value,
|
|
})
|
|
}
|
|
}
|
|
|
|
func handleAppDownloadConstant(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端常量")
|
|
return
|
|
}
|
|
|
|
var constant model.CloudConstant
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND key = ? AND status = ?", app.UserID, app.ID, key, "active").First(&constant).Error; err != nil {
|
|
response.Error(c, 404, "云端常量不存在")
|
|
return
|
|
}
|
|
|
|
if constant.VarType != "binary" || constant.FilePath == "" {
|
|
response.Error(c, 400, "该常量不是文件类型")
|
|
return
|
|
}
|
|
|
|
filePath := constant.FilePath
|
|
if strings.HasPrefix(filePath, "/") {
|
|
filePath = filePath[1:]
|
|
}
|
|
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
response.Error(c, 404, "文件不存在")
|
|
return
|
|
}
|
|
|
|
encodedFilename := url.QueryEscape(constant.OriginalName)
|
|
c.Header("Content-Description", "File Transfer")
|
|
c.Header("Content-Type", "application/octet-stream")
|
|
c.Header("Content-Disposition", "attachment; filename*=UTF-8''"+encodedFilename)
|
|
c.Header("Content-Transfer-Encoding", "binary")
|
|
c.Header("Expires", "0")
|
|
c.Header("Cache-Control", "must-revalidate")
|
|
c.Header("Pragma", "public")
|
|
c.FileAttachment(filePath, constant.OriginalName)
|
|
}
|
|
|
|
func handleAppGetVariables(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端变量")
|
|
return
|
|
}
|
|
|
|
var variables []model.CloudVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND status = ?", app.UserID, app.ID, "active").Find(&variables).Error; err != nil {
|
|
response.Error(c, 500, "获取云端变量失败")
|
|
return
|
|
}
|
|
|
|
var userVariables []model.UserVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ?", userID, app.ID).Find(&userVariables).Error; err != nil {
|
|
response.Error(c, 500, "获取用户变量失败")
|
|
return
|
|
}
|
|
|
|
userVarMap := make(map[string]model.UserVariable)
|
|
for _, uv := range userVariables {
|
|
userVarMap[uv.VarName] = uv
|
|
}
|
|
|
|
result := make(map[string]interface{})
|
|
for _, v := range variables {
|
|
if v.VarType == "binary" {
|
|
if v.Scope == "user" {
|
|
if uv, ok := userVarMap[v.Key]; ok && uv.FilePath != "" {
|
|
result[v.Key] = gin.H{
|
|
"type": "binary",
|
|
"value": "/api/v1/app/" + appKey + "/variables/" + v.Key + "/download",
|
|
"file_name": uv.OriginalName,
|
|
"file_size": uv.FileSize,
|
|
"md5": uv.FileMD5,
|
|
"mime_type": uv.MimeType,
|
|
}
|
|
} else {
|
|
result[v.Key] = gin.H{
|
|
"type": "binary",
|
|
"value": "/api/v1/app/" + appKey + "/variables/" + v.Key + "/download",
|
|
"file_name": v.OriginalName,
|
|
"file_size": v.FileSize,
|
|
"md5": v.FileMD5,
|
|
"mime_type": v.MimeType,
|
|
}
|
|
}
|
|
} else {
|
|
result[v.Key] = gin.H{
|
|
"type": "binary",
|
|
"value": "/api/v1/app/" + appKey + "/variables/" + v.Key + "/download",
|
|
"file_name": v.OriginalName,
|
|
"file_size": v.FileSize,
|
|
"md5": v.FileMD5,
|
|
"mime_type": v.MimeType,
|
|
}
|
|
}
|
|
} else {
|
|
if v.Scope == "app" {
|
|
result[v.Key] = gin.H{
|
|
"type": v.VarType,
|
|
"value": v.DefaultValue,
|
|
}
|
|
} else {
|
|
value := v.DefaultValue
|
|
if uv, ok := userVarMap[v.Key]; ok {
|
|
value = uv.VarValue
|
|
}
|
|
result[v.Key] = gin.H{
|
|
"type": v.VarType,
|
|
"value": value,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
response.Success(c, result)
|
|
}
|
|
|
|
func handleAppGetVariableByKey(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端变量")
|
|
return
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND key = ? AND status = ?", app.UserID, app.ID, key, "active").First(&variable).Error; err != nil {
|
|
response.Error(c, 404, "云端变量不存在")
|
|
return
|
|
}
|
|
|
|
if variable.VarType == "binary" {
|
|
if variable.Scope == "user" {
|
|
var userVar model.UserVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", userID, app.ID, key).First(&userVar).Error; err == nil && userVar.FilePath != "" {
|
|
response.Success(c, gin.H{
|
|
"key": variable.Key,
|
|
"type": "binary",
|
|
"value": "/api/v1/app/" + appKey + "/variables/" + variable.Key + "/download",
|
|
"file_name": userVar.OriginalName,
|
|
"file_size": userVar.FileSize,
|
|
"md5": userVar.FileMD5,
|
|
"mime_type": userVar.MimeType,
|
|
})
|
|
return
|
|
}
|
|
}
|
|
response.Success(c, gin.H{
|
|
"key": variable.Key,
|
|
"type": "binary",
|
|
"value": "/api/v1/app/" + appKey + "/variables/" + variable.Key + "/download",
|
|
"file_name": variable.OriginalName,
|
|
"file_size": variable.FileSize,
|
|
"md5": variable.FileMD5,
|
|
"mime_type": variable.MimeType,
|
|
})
|
|
return
|
|
}
|
|
|
|
if variable.Scope == "app" {
|
|
response.Success(c, gin.H{
|
|
"key": variable.Key,
|
|
"type": variable.VarType,
|
|
"value": variable.DefaultValue,
|
|
})
|
|
return
|
|
}
|
|
|
|
var userVar model.UserVariable
|
|
value := variable.DefaultValue
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", userID, app.ID, key).First(&userVar).Error; err == nil {
|
|
value = userVar.VarValue
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"key": variable.Key,
|
|
"type": variable.VarType,
|
|
"value": value,
|
|
})
|
|
}
|
|
|
|
func handleAppDownloadVariable(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端变量")
|
|
return
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND key = ? AND status = ?", app.UserID, app.ID, key, "active").First(&variable).Error; err != nil {
|
|
response.Error(c, 404, "云端变量不存在")
|
|
return
|
|
}
|
|
|
|
if variable.VarType != "binary" {
|
|
response.Error(c, 400, "该变量不是二进制类型")
|
|
return
|
|
}
|
|
|
|
var filePath string
|
|
var originalName string
|
|
|
|
if variable.Scope == "user" {
|
|
var userVar model.UserVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", userID, app.ID, key).First(&userVar).Error; err == nil && userVar.FilePath != "" {
|
|
filePath = userVar.FilePath
|
|
originalName = userVar.OriginalName
|
|
} else {
|
|
filePath = variable.FilePath
|
|
originalName = variable.OriginalName
|
|
}
|
|
} else {
|
|
filePath = variable.FilePath
|
|
originalName = variable.OriginalName
|
|
}
|
|
|
|
if filePath == "" {
|
|
response.Error(c, 400, "该变量没有关联文件")
|
|
return
|
|
}
|
|
|
|
if strings.HasPrefix(filePath, "/") {
|
|
filePath = filePath[1:]
|
|
}
|
|
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
response.Error(c, 404, "文件不存在")
|
|
return
|
|
}
|
|
|
|
encodedFilename := url.QueryEscape(originalName)
|
|
c.Header("Content-Description", "File Transfer")
|
|
c.Header("Content-Type", "application/octet-stream")
|
|
c.Header("Content-Disposition", "attachment; filename*=UTF-8''"+encodedFilename)
|
|
c.Header("Content-Transfer-Encoding", "binary")
|
|
c.Header("Expires", "0")
|
|
c.Header("Cache-Control", "must-revalidate")
|
|
c.Header("Pragma", "public")
|
|
c.FileAttachment(filePath, originalName)
|
|
}
|
|
|
|
func handleAppUpdateVariables(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端变量")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Variables map[string]string `json:"variables"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var variables []model.CloudVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ?", app.UserID, app.ID).Find(&variables).Error; err != nil {
|
|
response.Error(c, 500, "获取云端变量失败")
|
|
return
|
|
}
|
|
|
|
varMap := make(map[string]model.CloudVariable)
|
|
for _, v := range variables {
|
|
varMap[v.Key] = v
|
|
}
|
|
|
|
for key, value := range req.Variables {
|
|
variable, exists := varMap[key]
|
|
if !exists {
|
|
continue
|
|
}
|
|
|
|
if variable.Scope == "app" {
|
|
variable.DefaultValue = value
|
|
database.DB.Save(&variable)
|
|
} else {
|
|
var userVar model.UserVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", userID, app.ID, key).First(&userVar).Error; err != nil {
|
|
userVar = model.UserVariable{
|
|
UserID: userID.(uint),
|
|
AppID: app.ID,
|
|
VarName: key,
|
|
VarValue: value,
|
|
VarType: variable.VarType,
|
|
}
|
|
database.DB.Create(&userVar)
|
|
} else {
|
|
userVar.VarValue = value
|
|
database.DB.Save(&userVar)
|
|
}
|
|
}
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "更新成功",
|
|
})
|
|
}
|
|
|
|
func handleAppUploadVariableBinary(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端变量")
|
|
return
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND key = ? AND status = ?", app.UserID, app.ID, key, "active").First(&variable).Error; err != nil {
|
|
response.Error(c, 404, "云端变量不存在")
|
|
return
|
|
}
|
|
|
|
if variable.VarType != "binary" {
|
|
response.Error(c, 400, "该变量不是二进制类型")
|
|
return
|
|
}
|
|
|
|
if variable.WritePermission != "user" {
|
|
response.Error(c, 403, "该变量不允许用户写入")
|
|
return
|
|
}
|
|
|
|
file, header, err := c.Request.FormFile("file")
|
|
if err != nil {
|
|
response.Error(c, 400, "请选择要上传的文件")
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
var adminUser model.User
|
|
if err := database.DB.First(&adminUser, app.UserID).Error; err != nil {
|
|
response.Error(c, 500, "获取管理员信息失败")
|
|
return
|
|
}
|
|
|
|
if adminUser.CurrentPackageID != nil {
|
|
var permission model.PackagePermission
|
|
if err := database.DB.Where("package_id = ?", adminUser.CurrentPackageID).First(&permission).Error; err == nil {
|
|
maxStorageBytes := int64(permission.MaxStorage) * 1024 * 1024
|
|
if adminUser.StorageUsed+header.Size > maxStorageBytes {
|
|
usedMB := float64(adminUser.StorageUsed) / 1024 / 1024
|
|
maxMB := float64(permission.MaxStorage)
|
|
response.Error(c, 403, fmt.Sprintf("存储空间不足,已使用 %.2f MB / %.2f MB", usedMB, maxMB))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
uploadDir := "uploads/cloud-files"
|
|
if err := os.MkdirAll(uploadDir, 0755); err != nil {
|
|
response.Error(c, 500, "创建上传目录失败")
|
|
return
|
|
}
|
|
|
|
ext := filepath.Ext(header.Filename)
|
|
filename := fmt.Sprintf("%d_%d_%d%s", app.UserID, userID, time.Now().UnixNano(), ext)
|
|
filePath := filepath.Join(uploadDir, filename)
|
|
|
|
dst, err := os.Create(filePath)
|
|
if err != nil {
|
|
response.Error(c, 500, "创建文件失败")
|
|
return
|
|
}
|
|
defer dst.Close()
|
|
|
|
hash := md5.New()
|
|
multiWriter := io.MultiWriter(dst, hash)
|
|
if _, err := io.Copy(multiWriter, file); err != nil {
|
|
response.Error(c, 500, "保存文件失败")
|
|
return
|
|
}
|
|
fileMD5 := hex.EncodeToString(hash.Sum(nil))
|
|
|
|
fileURL := "/uploads/cloud-files/" + filename
|
|
|
|
mimeType := header.Header.Get("Content-Type")
|
|
if mimeType == "" {
|
|
mimeType = "application/octet-stream"
|
|
}
|
|
|
|
if variable.Scope == "app" {
|
|
if variable.FilePath != "" && variable.FileSize > 0 {
|
|
oldFilePath := variable.FilePath
|
|
if strings.HasPrefix(oldFilePath, "/") {
|
|
oldFilePath = oldFilePath[1:]
|
|
}
|
|
os.Remove(oldFilePath)
|
|
if err := middleware.UpdateStorageUsed(app.UserID, variable.FileSize, "delete"); err != nil {
|
|
fmt.Printf("更新存储使用量失败: %v\n", err)
|
|
}
|
|
}
|
|
|
|
variable.DefaultValue = fileURL
|
|
variable.FilePath = fileURL
|
|
variable.FileSize = header.Size
|
|
variable.MimeType = mimeType
|
|
variable.OriginalName = header.Filename
|
|
variable.FileMD5 = fileMD5
|
|
database.DB.Save(&variable)
|
|
} else {
|
|
var userVar model.UserVariable
|
|
existingFile := false
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", userID, app.ID, key).First(&userVar).Error; err == nil {
|
|
if userVar.FilePath != "" && userVar.FileSize > 0 {
|
|
existingFile = true
|
|
}
|
|
}
|
|
|
|
userVar = model.UserVariable{
|
|
UserID: userID.(uint),
|
|
AppID: app.ID,
|
|
VarName: key,
|
|
VarValue: fileURL,
|
|
VarType: "binary",
|
|
FilePath: fileURL,
|
|
FileSize: header.Size,
|
|
MimeType: mimeType,
|
|
OriginalName: header.Filename,
|
|
FileMD5: fileMD5,
|
|
}
|
|
|
|
if existingFile {
|
|
var oldVar model.UserVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", userID, app.ID, key).First(&oldVar).Error; err == nil {
|
|
if oldVar.FilePath != "" && oldVar.FileSize > 0 {
|
|
oldFilePath := oldVar.FilePath
|
|
if strings.HasPrefix(oldFilePath, "/") {
|
|
oldFilePath = oldFilePath[1:]
|
|
}
|
|
os.Remove(oldFilePath)
|
|
if err := middleware.UpdateStorageUsed(app.UserID, oldVar.FileSize, "delete"); err != nil {
|
|
fmt.Printf("更新存储使用量失败: %v\n", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", userID, app.ID, key).Assign(userVar).FirstOrCreate(&userVar)
|
|
}
|
|
|
|
if err := middleware.UpdateStorageUsed(app.UserID, header.Size, "upload"); err != nil {
|
|
fmt.Printf("更新存储使用量失败: %v\n", err)
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "上传成功",
|
|
"file_url": fileURL,
|
|
"file_size": header.Size,
|
|
"mime_type": mimeType,
|
|
"original_name": header.Filename,
|
|
"download_url": "/api/v1/app/" + appKey + "/variables/" + key + "/download",
|
|
})
|
|
}
|
|
|
|
func handleAppCallFunction(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
UserID uint `json:"user_id"`
|
|
Name string `json:"name"`
|
|
Params map[string]interface{} `json:"params"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"result": nil,
|
|
})
|
|
}
|
|
|
|
func handleAppCreateVariableRecord(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端变量")
|
|
return
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND key = ? AND status = ?", app.UserID, app.ID, key, "active").First(&variable).Error; err != nil {
|
|
response.Error(c, 404, "云端变量不存在")
|
|
return
|
|
}
|
|
|
|
if variable.VarType != "stream" {
|
|
response.Error(c, 400, "该变量不是记录类型")
|
|
return
|
|
}
|
|
|
|
if variable.WritePermission != "user" && variable.WritePermission != "app_user" {
|
|
response.Error(c, 403, "该变量不允许应用用户写入")
|
|
return
|
|
}
|
|
|
|
var req map[string]interface{}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
dataBytes, err := json.Marshal(req)
|
|
if err != nil {
|
|
response.Error(c, 500, "序列化数据失败")
|
|
return
|
|
}
|
|
|
|
record := model.CloudVariableRecord{
|
|
CloudVariableID: variable.ID,
|
|
Data: string(dataBytes),
|
|
}
|
|
|
|
if variable.Scope == "user" {
|
|
appUserID := userID.(uint)
|
|
record.AppUserID = &appUserID
|
|
}
|
|
|
|
if err := database.DB.Create(&record).Error; err != nil {
|
|
response.Error(c, 500, "创建记录失败")
|
|
return
|
|
}
|
|
|
|
if variable.MaxRecords > 0 {
|
|
var total int64
|
|
database.DB.Model(&model.CloudVariableRecord{}).Where("cloud_variable_id = ?", variable.ID).Count(&total)
|
|
if int(total) > variable.MaxRecords {
|
|
deleteCount := int(total) - variable.MaxRecords
|
|
var oldRecords []model.CloudVariableRecord
|
|
database.DB.Where("cloud_variable_id = ?", variable.ID).
|
|
Order("created_at ASC").
|
|
Limit(deleteCount).
|
|
Find(&oldRecords)
|
|
for _, r := range oldRecords {
|
|
database.DB.Delete(&r)
|
|
}
|
|
}
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"id": record.ID,
|
|
"created_at": record.CreatedAt,
|
|
})
|
|
}
|
|
|
|
func handleAppGetVariableRecords(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端变量")
|
|
return
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND key = ? AND status = ?", app.UserID, app.ID, key, "active").First(&variable).Error; err != nil {
|
|
response.Error(c, 404, "云端变量不存在")
|
|
return
|
|
}
|
|
|
|
if variable.VarType != "stream" {
|
|
response.Error(c, 400, "该变量不是记录类型")
|
|
return
|
|
}
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if pageSize < 1 || pageSize > 100 {
|
|
pageSize = 20
|
|
}
|
|
|
|
var total int64
|
|
query := database.DB.Model(&model.CloudVariableRecord{}).Where("cloud_variable_id = ?", variable.ID)
|
|
if variable.Scope == "user" {
|
|
query = query.Where("app_user_id = ?", userID)
|
|
}
|
|
query.Count(&total)
|
|
|
|
var records []model.CloudVariableRecord
|
|
offset := (page - 1) * pageSize
|
|
if err := query.Order("created_at DESC").Limit(pageSize).Offset(offset).Find(&records).Error; err != nil {
|
|
response.Error(c, 500, "获取记录失败")
|
|
return
|
|
}
|
|
|
|
result := make([]gin.H, len(records))
|
|
for i, r := range records {
|
|
var data map[string]interface{}
|
|
json.Unmarshal([]byte(r.Data), &data)
|
|
result[i] = gin.H{
|
|
"id": r.ID,
|
|
"data": data,
|
|
"created_at": r.CreatedAt,
|
|
}
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"records": result,
|
|
"total": total,
|
|
"page": page,
|
|
"page_size": pageSize,
|
|
"total_pages": (total + int64(pageSize) - 1) / int64(pageSize),
|
|
})
|
|
}
|
|
|
|
func handleAppDeleteVariableRecord(c *gin.Context) {
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
recordID := c.Param("record_id")
|
|
userID, _ := c.Get("user_id")
|
|
|
|
var app model.Application
|
|
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
|
response.Error(c, 404, "应用不存在")
|
|
return
|
|
}
|
|
|
|
if service.GetApplicationDisabledStatus(app.ID) {
|
|
response.Error(c, 403, "该应用已被禁用")
|
|
return
|
|
}
|
|
|
|
var appUser model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", userID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, 403, "无权访问该应用的云端变量")
|
|
return
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND key = ? AND status = ?", app.UserID, app.ID, key, "active").First(&variable).Error; err != nil {
|
|
response.Error(c, 404, "云端变量不存在")
|
|
return
|
|
}
|
|
|
|
if variable.VarType != "stream" {
|
|
response.Error(c, 400, "该变量不是记录类型")
|
|
return
|
|
}
|
|
|
|
var record model.CloudVariableRecord
|
|
query := database.DB.Where("id = ? AND cloud_variable_id = ?", recordID, variable.ID)
|
|
if variable.Scope == "user" {
|
|
query = query.Where("app_user_id = ?", userID)
|
|
}
|
|
if err := query.First(&record).Error; err != nil {
|
|
response.Error(c, 404, "记录不存在")
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Delete(&record).Error; err != nil {
|
|
response.Error(c, 500, "删除记录失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, nil)
|
|
}
|