ea8ffb6c74
- 修复订阅模式登录时错误检查余额的问题 - 区分无限余额和永久订阅两种永久会员类型 - 修复动态代码HTTP请求返回值在JS中无法正确访问的问题 - 添加侧边栏滚动位置保持功能 - 移除developer角色相关代码,统一使用admin - 添加缺失的i18n翻译key
725 lines
19 KiB
Go
725 lines
19 KiB
Go
package app
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"verification-platform-backend/internal/database"
|
|
"verification-platform-backend/internal/model"
|
|
"verification-platform-backend/internal/service"
|
|
"verification-platform-backend/internal/utils/httputil"
|
|
"verification-platform-backend/internal/utils/smtputil"
|
|
"verification-platform-backend/pkg/jwt"
|
|
"verification-platform-backend/pkg/response"
|
|
|
|
"github.com/dop251/goja"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func SetupDynamicRoutes(r *gin.RouterGroup) {
|
|
dynamicCode := r.Group("/dynamic-code")
|
|
{
|
|
dynamicCode.POST("/:key/execute", handleExecuteDynamicCode)
|
|
}
|
|
}
|
|
|
|
func handleExecuteDynamicCode(c *gin.Context) {
|
|
var token string
|
|
authHeader := c.GetHeader("Authorization")
|
|
if authHeader != "" {
|
|
parts := strings.SplitN(authHeader, " ", 2)
|
|
if len(parts) == 2 && parts[0] == "Bearer" {
|
|
token = parts[1]
|
|
}
|
|
}
|
|
|
|
if token == "" {
|
|
token = c.Query("token")
|
|
}
|
|
|
|
if token == "" {
|
|
response.Error(c, http.StatusUnauthorized, "Authorization header is required")
|
|
return
|
|
}
|
|
|
|
claims, err := jwt.ParseToken(token)
|
|
if err != nil {
|
|
response.Error(c, http.StatusUnauthorized, "Invalid token")
|
|
return
|
|
}
|
|
|
|
if time.Now().Unix() > claims.ExpiresAt.Unix() {
|
|
response.Error(c, http.StatusUnauthorized, "Token expired")
|
|
return
|
|
}
|
|
|
|
c.Set("user_id", claims.UserID)
|
|
c.Set("username", claims.Username)
|
|
c.Set("role", claims.Role)
|
|
|
|
appKey := c.Param("appKey")
|
|
key := c.Param("key")
|
|
|
|
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 = ?", claims.UserID, app.ID).First(&appUser).Error; err != nil {
|
|
response.Error(c, http.StatusForbidden, "无权访问该应用的动态代码")
|
|
return
|
|
}
|
|
|
|
var dynamicCode model.DynamicCode
|
|
if err := database.DB.Where("application_id = ? AND key = ?", app.ID, key).First(&dynamicCode).Error; err != nil {
|
|
response.Error(c, 404, "动态代码不存在")
|
|
return
|
|
}
|
|
|
|
if dynamicCode.Status != "active" {
|
|
response.Error(c, 400, "动态代码未启用")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Params map[string]interface{} `json:"params"`
|
|
UserID *uint `json:"user_id,omitempty"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
startTime := time.Now()
|
|
|
|
vm := goja.New()
|
|
|
|
appData := map[string]interface{}{
|
|
"id": app.ID,
|
|
"name": app.Name,
|
|
"description": app.Description,
|
|
"app_key": app.AppKey,
|
|
"status": app.Status,
|
|
"billing_type": app.BillingType,
|
|
"deduction_mode": app.DeductionMode,
|
|
"deduction_type": app.DeductionType,
|
|
"deduction_interval": app.DeductionInterval,
|
|
"deduction_unit": app.DeductionUnit,
|
|
"deduction_amount": app.DeductionAmount,
|
|
"enable_trial": app.EnableTrial,
|
|
"trial_balance": app.TrialBalance,
|
|
"trial_days": app.TrialDays,
|
|
"enable_free_period": app.EnableFreePeriod,
|
|
"free_period_type": app.FreePeriodType,
|
|
"free_period_start": app.FreePeriodStart,
|
|
"free_period_end": app.FreePeriodEnd,
|
|
"free_period_weekdays": app.FreePeriodWeekdays,
|
|
"free_period_start_time": app.FreePeriodStartTime,
|
|
"free_period_end_time": app.FreePeriodEndTime,
|
|
"max_devices": app.MaxDevices,
|
|
"bind_type": app.BindType,
|
|
"multi_open": app.MultiOpen,
|
|
"multi_open_mode": app.MultiOpenMode,
|
|
"max_instances": app.MaxInstances,
|
|
"login_policy": app.LoginPolicy,
|
|
"max_attempts": app.MaxAttempts,
|
|
"lock_duration": app.LockDuration,
|
|
"heartbeat_interval": app.HeartbeatInterval,
|
|
"heartbeat_timeout": app.HeartbeatTimeout,
|
|
"change_limit": app.ChangeLimit,
|
|
"change_interval": app.ChangeInterval,
|
|
"change_exceed_action": app.ChangeExceedAction,
|
|
"change_deduct_amount": app.ChangeDeductAmount,
|
|
}
|
|
if err := vm.Set("app", appData); err != nil {
|
|
response.Error(c, 500, "应用数据设置失败")
|
|
return
|
|
}
|
|
|
|
var constants []model.CloudConstant
|
|
database.DB.Where("app_id = ? AND status = ?", app.ID, "active").Find(&constants)
|
|
constantsData := make(map[string]interface{})
|
|
for _, c := range constants {
|
|
constantsData[c.Key] = c.Value
|
|
}
|
|
if err := vm.Set("constants", constantsData); err != nil {
|
|
response.Error(c, 500, "云端常量设置失败")
|
|
return
|
|
}
|
|
|
|
var cloudVariables []model.CloudVariable
|
|
database.DB.Where("app_id = ? AND status = ?", app.ID, "active").Find(&cloudVariables)
|
|
appVariables := make(map[string]interface{})
|
|
for _, v := range cloudVariables {
|
|
appVariables[v.Key] = v.DefaultValue
|
|
}
|
|
if err := vm.Set("appVariables", appVariables); err != nil {
|
|
response.Error(c, 500, "云端变量设置失败")
|
|
return
|
|
}
|
|
|
|
userData := map[string]interface{}{}
|
|
subscription := map[string]interface{}{}
|
|
userVariables := map[string]interface{}{}
|
|
devices := []map[string]interface{}{}
|
|
|
|
if req.UserID != nil {
|
|
var user model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", *req.UserID, app.ID).First(&user).Error; err == nil {
|
|
userData = map[string]interface{}{
|
|
"id": user.ID,
|
|
"username": user.Username,
|
|
"email": user.Email,
|
|
"status": user.Status,
|
|
"device_id": user.DeviceID,
|
|
"avatar": user.Avatar,
|
|
"created_at": user.CreatedAt,
|
|
"last_login_at": user.LastLoginAt,
|
|
}
|
|
|
|
subscription = map[string]interface{}{
|
|
"balance": user.Balance,
|
|
"is_trial_user": user.IsTrialUser,
|
|
"trial_start_at": user.TrialStartAt,
|
|
"trial_end_at": user.TrialEndAt,
|
|
"expiry_at": user.ExpiryAt,
|
|
"is_expired": user.ExpiryAt != nil && user.ExpiryAt.Before(time.Now()),
|
|
"is_lifetime": user.Balance == -1,
|
|
"days_remaining": calculateDaysRemaining(user.ExpiryAt, user.Balance),
|
|
}
|
|
|
|
var userDevices []model.UserDevice
|
|
database.DB.Where("user_id = ? AND application_id = ?", user.ID, app.ID).Find(&userDevices)
|
|
for _, d := range userDevices {
|
|
devices = append(devices, map[string]interface{}{
|
|
"id": d.ID,
|
|
"device_id": d.DeviceID,
|
|
"device_name": d.DeviceName,
|
|
"device_type": d.DeviceType,
|
|
"status": d.Status,
|
|
"created_at": d.CreatedAt,
|
|
})
|
|
}
|
|
|
|
var userVars []model.UserVariable
|
|
database.DB.Where("user_id = ? AND app_id = ?", user.ID, app.ID).Find(&userVars)
|
|
for _, v := range userVars {
|
|
userVariables[v.VarName] = v.VarValue
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := vm.Set("user", userData); err != nil {
|
|
response.Error(c, 500, "用户数据设置失败")
|
|
return
|
|
}
|
|
if err := vm.Set("subscription", subscription); err != nil {
|
|
response.Error(c, 500, "订阅数据设置失败")
|
|
return
|
|
}
|
|
if err := vm.Set("userVariables", userVariables); err != nil {
|
|
response.Error(c, 500, "用户变量设置失败")
|
|
return
|
|
}
|
|
if err := vm.Set("devices", devices); err != nil {
|
|
response.Error(c, 500, "设备数据设置失败")
|
|
return
|
|
}
|
|
|
|
for k, v := range req.Params {
|
|
if err := vm.Set(k, v); err != nil {
|
|
response.Error(c, 500, "参数设置失败")
|
|
return
|
|
}
|
|
}
|
|
|
|
if err := vm.Set("params", req.Params); err != nil {
|
|
response.Error(c, 500, "参数设置失败")
|
|
return
|
|
}
|
|
|
|
httpClient := httputil.NewHTTPClient(10 * time.Second)
|
|
httpObj := map[string]interface{}{
|
|
"get": func(url string, headers map[string]interface{}) map[string]interface{} {
|
|
convertedHeaders := make(map[string]string)
|
|
for k, v := range headers {
|
|
convertedHeaders[k] = fmt.Sprintf("%v", v)
|
|
}
|
|
resp := httpClient.Get(url, convertedHeaders)
|
|
return map[string]interface{}{
|
|
"statusCode": resp.StatusCode,
|
|
"status": resp.Status,
|
|
"headers": resp.Headers,
|
|
"body": resp.Body,
|
|
"json": resp.JSON,
|
|
"error": resp.Error,
|
|
}
|
|
},
|
|
"post": func(url string, headers map[string]interface{}, body interface{}) map[string]interface{} {
|
|
convertedHeaders := make(map[string]string)
|
|
for k, v := range headers {
|
|
convertedHeaders[k] = fmt.Sprintf("%v", v)
|
|
}
|
|
resp := httpClient.Post(url, convertedHeaders, body)
|
|
return map[string]interface{}{
|
|
"statusCode": resp.StatusCode,
|
|
"status": resp.Status,
|
|
"headers": resp.Headers,
|
|
"body": resp.Body,
|
|
"json": resp.JSON,
|
|
"error": resp.Error,
|
|
}
|
|
},
|
|
}
|
|
if err := vm.Set("http", httpObj); err != nil {
|
|
response.Error(c, 500, "HTTP对象设置失败")
|
|
return
|
|
}
|
|
|
|
dbObj := map[string]interface{}{
|
|
"getRecords": func(variableKey string, page, pageSize int) map[string]interface{} {
|
|
return getRecords(app.ID, req.UserID, variableKey, page, pageSize)
|
|
},
|
|
"deleteRecord": func(variableKey string, recordID uint) map[string]interface{} {
|
|
return deleteRecord(app.ID, req.UserID, variableKey, recordID)
|
|
},
|
|
"deleteRecords": func(variableKey string, recordIDs []uint) map[string]interface{} {
|
|
return deleteRecords(app.ID, req.UserID, variableKey, recordIDs)
|
|
},
|
|
}
|
|
if err := vm.Set("db", dbObj); err != nil {
|
|
response.Error(c, 500, "数据库对象设置失败")
|
|
return
|
|
}
|
|
|
|
smtpObj := map[string]interface{}{
|
|
"send": func(config map[string]interface{}, to []string, subject, body string, html bool) *smtputil.SMTPResult {
|
|
smtpConfig := smtputil.SMTPConfig{
|
|
Host: getString(config, "host"),
|
|
Port: getInt(config, "port", 587),
|
|
Username: getString(config, "username"),
|
|
Password: getString(config, "password"),
|
|
From: getString(config, "from"),
|
|
UseTLS: getBool(config, "use_tls", true),
|
|
}
|
|
client := smtputil.NewSMTPClient(smtpConfig, 30*time.Second)
|
|
return client.Send(smtputil.EmailMessage{
|
|
To: to,
|
|
Subject: subject,
|
|
Body: body,
|
|
HTML: html,
|
|
})
|
|
},
|
|
}
|
|
if err := vm.Set("smtp", smtpObj); err != nil {
|
|
response.Error(c, 500, "SMTP对象设置失败")
|
|
return
|
|
}
|
|
|
|
value, err := vm.RunString("(function() { " + dynamicCode.Code + " })()")
|
|
if err != nil {
|
|
response.Error(c, 400, "代码执行错误: "+err.Error())
|
|
return
|
|
}
|
|
|
|
executionTime := time.Since(startTime).Milliseconds()
|
|
|
|
result := value.Export()
|
|
|
|
if actionMap, ok := result.(map[string]interface{}); ok {
|
|
if action, hasAction := actionMap["action"]; hasAction {
|
|
switch action {
|
|
case "extend_time":
|
|
if err := handleExtendTime(app.ID, actionMap); err != nil {
|
|
response.Error(c, 500, "执行加时操作失败: "+err.Error())
|
|
return
|
|
}
|
|
case "deduct_points":
|
|
if err := handleDeductPoints(app.ID, actionMap); err != nil {
|
|
response.Error(c, 500, "执行扣点操作失败: "+err.Error())
|
|
return
|
|
}
|
|
case "update_user_variable":
|
|
appID := app.ID
|
|
if err := handleUpdateUserVariable(&appID, req.UserID, actionMap); err != nil {
|
|
response.Error(c, 500, "更新用户变量失败: "+err.Error())
|
|
return
|
|
}
|
|
case "update_app_variable":
|
|
if err := handleUpdateAppVariable(app.ID, actionMap); err != nil {
|
|
response.Error(c, 500, "更新应用变量失败: "+err.Error())
|
|
return
|
|
}
|
|
case "add_record":
|
|
if err := handleAddRecord(app.ID, req.UserID, actionMap); err != nil {
|
|
response.Error(c, 500, "添加记录失败: "+err.Error())
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"result": result,
|
|
"execution_time": executionTime,
|
|
})
|
|
}
|
|
|
|
func calculateDaysRemaining(expiryAt *time.Time, balance float64) int {
|
|
if balance == -1 {
|
|
return -1
|
|
}
|
|
if expiryAt == nil {
|
|
return 0
|
|
}
|
|
remaining := int(time.Until(*expiryAt).Hours() / 24)
|
|
if remaining < 0 {
|
|
return 0
|
|
}
|
|
return remaining
|
|
}
|
|
|
|
func handleExtendTime(appID uint, actionMap map[string]interface{}) error {
|
|
userID, ok := actionMap["user_id"].(float64)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
days, ok := actionMap["days"].(float64)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
var user model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", uint(userID), appID).First(&user).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
if user.Balance == -1 {
|
|
return nil
|
|
}
|
|
|
|
user.Balance += float64(days)
|
|
|
|
return database.DB.Save(&user).Error
|
|
}
|
|
|
|
func handleDeductPoints(appID uint, actionMap map[string]interface{}) error {
|
|
userID, ok := actionMap["user_id"].(float64)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
points, ok := actionMap["points"].(float64)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
var user model.AppUser
|
|
if err := database.DB.Where("id = ? AND application_id = ?", uint(userID), appID).First(&user).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
if user.Balance == -1 {
|
|
return nil
|
|
}
|
|
|
|
user.Balance -= points
|
|
if user.Balance < 0 {
|
|
user.Balance = 0
|
|
}
|
|
|
|
return database.DB.Save(&user).Error
|
|
}
|
|
|
|
func handleUpdateUserVariable(appID *uint, userID *uint, actionMap map[string]interface{}) error {
|
|
if userID == nil {
|
|
return nil
|
|
}
|
|
|
|
varName, ok := actionMap["name"].(string)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
varValue, ok := actionMap["value"].(string)
|
|
if !ok {
|
|
if v, ok := actionMap["value"]; ok {
|
|
varValue = toString(v)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var userVar model.UserVariable
|
|
if err := database.DB.Where("user_id = ? AND app_id = ? AND var_name = ?", *userID, appID, varName).First(&userVar).Error; err != nil {
|
|
userVar = model.UserVariable{
|
|
UserID: *userID,
|
|
AppID: *appID,
|
|
VarName: varName,
|
|
VarValue: varValue,
|
|
}
|
|
return database.DB.Create(&userVar).Error
|
|
}
|
|
|
|
userVar.VarValue = varValue
|
|
return database.DB.Save(&userVar).Error
|
|
}
|
|
|
|
func handleUpdateAppVariable(appID uint, actionMap map[string]interface{}) error {
|
|
varName, ok := actionMap["name"].(string)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
varValue, ok := actionMap["value"].(string)
|
|
if !ok {
|
|
if v, ok := actionMap["value"]; ok {
|
|
varValue = toString(v)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var appVar model.CloudVariable
|
|
if err := database.DB.Where("app_id = ? AND key = ?", appID, varName).First(&appVar).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
appVar.DefaultValue = varValue
|
|
return database.DB.Save(&appVar).Error
|
|
}
|
|
|
|
func toString(v interface{}) string {
|
|
switch val := v.(type) {
|
|
case string:
|
|
return val
|
|
case float64:
|
|
return string(rune(int(val)))
|
|
case int:
|
|
return string(rune(val))
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func handleAddRecord(appID uint, userID *uint, actionMap map[string]interface{}) error {
|
|
variableKey, ok := actionMap["variable_key"].(string)
|
|
if !ok {
|
|
return fmt.Errorf("缺少variable_key参数")
|
|
}
|
|
|
|
recordData, ok := actionMap["record_data"]
|
|
if !ok {
|
|
return fmt.Errorf("缺少record_data参数")
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("app_id = ? AND key = ?", appID, variableKey).First(&variable).Error; err != nil {
|
|
return fmt.Errorf("云端变量不存在: %s", variableKey)
|
|
}
|
|
|
|
if variable.VarType != "stream" {
|
|
return fmt.Errorf("该变量不是记录类型")
|
|
}
|
|
|
|
dataBytes, err := json.Marshal(recordData)
|
|
if err != nil {
|
|
return fmt.Errorf("序列化记录数据失败: %v", err)
|
|
}
|
|
|
|
record := model.CloudVariableRecord{
|
|
CloudVariableID: variable.ID,
|
|
Data: string(dataBytes),
|
|
}
|
|
|
|
if variable.Scope == "user" && userID != nil {
|
|
appUserID := *userID
|
|
record.AppUserID = &appUserID
|
|
}
|
|
|
|
if err := database.DB.Create(&record).Error; err != nil {
|
|
return fmt.Errorf("创建记录失败: %v", err)
|
|
}
|
|
|
|
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 _, oldRecord := range oldRecords {
|
|
database.DB.Delete(&oldRecord)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getRecords(appID uint, userID *uint, variableKey string, page, pageSize int) map[string]interface{} {
|
|
result := map[string]interface{}{
|
|
"success": false,
|
|
"records": []interface{}{},
|
|
"total": 0,
|
|
"page": page,
|
|
"pageSize": pageSize,
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("app_id = ? AND key = ?", appID, variableKey).First(&variable).Error; err != nil {
|
|
result["error"] = "云端变量不存在"
|
|
return result
|
|
}
|
|
|
|
if variable.VarType != "stream" {
|
|
result["error"] = "该变量不是记录类型"
|
|
return result
|
|
}
|
|
|
|
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" && userID != nil {
|
|
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").Offset(offset).Limit(pageSize).Find(&records).Error; err != nil {
|
|
result["error"] = "查询记录失败"
|
|
return result
|
|
}
|
|
|
|
var recordList []interface{}
|
|
for _, record := range records {
|
|
var data interface{}
|
|
if err := json.Unmarshal([]byte(record.Data), &data); err == nil {
|
|
recordList = append(recordList, map[string]interface{}{
|
|
"id": record.ID,
|
|
"data": data,
|
|
"created_at": record.CreatedAt,
|
|
})
|
|
}
|
|
}
|
|
|
|
result["success"] = true
|
|
result["records"] = recordList
|
|
result["total"] = total
|
|
return result
|
|
}
|
|
|
|
func deleteRecord(appID uint, userID *uint, variableKey string, recordID uint) map[string]interface{} {
|
|
result := map[string]interface{}{
|
|
"success": false,
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("app_id = ? AND key = ?", appID, variableKey).First(&variable).Error; err != nil {
|
|
result["error"] = "云端变量不存在"
|
|
return result
|
|
}
|
|
|
|
if variable.VarType != "stream" {
|
|
result["error"] = "该变量不是记录类型"
|
|
return result
|
|
}
|
|
|
|
query := database.DB.Where("id = ? AND cloud_variable_id = ?", recordID, variable.ID)
|
|
if variable.Scope == "user" && userID != nil {
|
|
query = query.Where("app_user_id = ?", *userID)
|
|
}
|
|
|
|
if err := query.Delete(&model.CloudVariableRecord{}).Error; err != nil {
|
|
result["error"] = "删除记录失败"
|
|
return result
|
|
}
|
|
|
|
result["success"] = true
|
|
return result
|
|
}
|
|
|
|
func deleteRecords(appID uint, userID *uint, variableKey string, recordIDs []uint) map[string]interface{} {
|
|
result := map[string]interface{}{
|
|
"success": false,
|
|
"deleted": 0,
|
|
}
|
|
|
|
var variable model.CloudVariable
|
|
if err := database.DB.Where("app_id = ? AND key = ?", appID, variableKey).First(&variable).Error; err != nil {
|
|
result["error"] = "云端变量不存在"
|
|
return result
|
|
}
|
|
|
|
if variable.VarType != "stream" {
|
|
result["error"] = "该变量不是记录类型"
|
|
return result
|
|
}
|
|
|
|
query := database.DB.Where("id IN ? AND cloud_variable_id = ?", recordIDs, variable.ID)
|
|
if variable.Scope == "user" && userID != nil {
|
|
query = query.Where("app_user_id = ?", *userID)
|
|
}
|
|
|
|
deleteResult := query.Delete(&model.CloudVariableRecord{})
|
|
if deleteResult.Error != nil {
|
|
result["error"] = "删除记录失败"
|
|
return result
|
|
}
|
|
|
|
result["success"] = true
|
|
result["deleted"] = deleteResult.RowsAffected
|
|
return result
|
|
}
|
|
|
|
func getString(m map[string]interface{}, key string) string {
|
|
if v, ok := m[key]; ok {
|
|
if s, ok := v.(string); ok {
|
|
return s
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func getInt(m map[string]interface{}, key string, defaultValue int) int {
|
|
if v, ok := m[key]; ok {
|
|
switch val := v.(type) {
|
|
case int:
|
|
return val
|
|
case float64:
|
|
return int(val)
|
|
}
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func getBool(m map[string]interface{}, key string, defaultValue bool) bool {
|
|
if v, ok := m[key]; ok {
|
|
if b, ok := v.(bool); ok {
|
|
return b
|
|
}
|
|
}
|
|
return defaultValue
|
|
}
|