feat: implement data import/export and optimize terminal UX
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type DataController struct {
|
||||
dataService *services.DataService
|
||||
taskController *TaskController
|
||||
envController *EnvController
|
||||
}
|
||||
|
||||
func NewDataController(tc *TaskController, ec *EnvController) *DataController {
|
||||
return &DataController{
|
||||
dataService: services.NewDataService(),
|
||||
taskController: tc,
|
||||
envController: ec,
|
||||
}
|
||||
}
|
||||
|
||||
// ExportBusinessData 导出业务数据
|
||||
func (dc *DataController) ExportBusinessData(c *gin.Context) {
|
||||
var req struct {
|
||||
TaskIDs []string `json:"task_ids"`
|
||||
EnvIDs []string `json:"env_ids"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
exportData := dc.dataService.ExportBusinessData(req.TaskIDs, req.EnvIDs)
|
||||
utils.Success(c, exportData)
|
||||
}
|
||||
|
||||
// ImportBusinessData 导入业务数据
|
||||
func (dc *DataController) ImportBusinessData(c *gin.Context) {
|
||||
var req models.ExportData
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if req.Version == "" {
|
||||
utils.BadRequest(c, "无效的导入数据格式")
|
||||
return
|
||||
}
|
||||
|
||||
// 停止相关的定时任务
|
||||
if len(req.Tasks) > 0 {
|
||||
for _, task := range req.Tasks {
|
||||
dc.taskController.executorService.RemoveCronTask(task.ID)
|
||||
dc.taskController.executorService.GetScheduler().StopTask(task.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// 导入数据
|
||||
if err := dc.dataService.ImportBusinessData(&req); err != nil {
|
||||
utils.ServerError(c, "导入失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 重新启动任务和通知相关的代理
|
||||
if len(req.Tasks) > 0 {
|
||||
for i := range req.Tasks {
|
||||
task := &req.Tasks[i]
|
||||
if utils.DerefBool(task.Enabled, true) && (task.AgentID == nil || *task.AgentID == "") {
|
||||
dc.taskController.executorService.AddCronTask(task)
|
||||
}
|
||||
if task.AgentID != nil && *task.AgentID != "" {
|
||||
dc.taskController.agentWSManager.BroadcastTasks(*task.AgentID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
utils.SuccessMsg(c, "导入成功")
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func (ec *EnvController) CreateEnvVar(c *gin.Context) {
|
||||
}
|
||||
|
||||
if req.Type == "" {
|
||||
req.Type = "normal"
|
||||
req.Type = constant.EnvTypeNormal
|
||||
}
|
||||
|
||||
hidden := true
|
||||
@@ -187,7 +187,7 @@ func (ec *EnvController) UpdateEnvVar(c *gin.Context) {
|
||||
}
|
||||
|
||||
if req.Type == "" {
|
||||
req.Type = "normal"
|
||||
req.Type = constant.EnvTypeNormal
|
||||
}
|
||||
|
||||
// 对于更新,获取现有数据
|
||||
@@ -323,7 +323,7 @@ func (ec *EnvController) BulkSaveEnv(c *gin.Context) {
|
||||
userID := c.GetString("userID")
|
||||
|
||||
for _, req := range reqs {
|
||||
if req.Type == "secret" {
|
||||
if req.Type == constant.EnvTypeSecret {
|
||||
continue // 二次严苛拦截,机密变量不应下发/保存
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/models/vo"
|
||||
"github.com/engigu/baihu-panel/internal/services"
|
||||
"github.com/engigu/baihu-panel/internal/tunnel"
|
||||
"github.com/engigu/baihu-panel/internal/utils"
|
||||
@@ -271,15 +269,7 @@ func (ic *InterconnectController) SyncScript(c *gin.Context) {
|
||||
func (ic *InterconnectController) SyncEnv(c *gin.Context) {
|
||||
var req struct {
|
||||
NodeIDs []string `json:"node_ids" binding:"required"`
|
||||
Envs []struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Remark string `json:"remark"`
|
||||
Type string `json:"type"`
|
||||
Hidden *bool `json:"hidden"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
} `json:"envs" binding:"required"`
|
||||
Envs []struct{ ID string `json:"id"` } `json:"envs" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -287,27 +277,14 @@ func (ic *InterconnectController) SyncEnv(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Filter out secret variables securely using the database
|
||||
var safeEnvs []interface{}
|
||||
for _, envReq := range req.Envs {
|
||||
var env models.EnvironmentVariable
|
||||
query := database.DB
|
||||
if envReq.ID != "" {
|
||||
query = query.Where("id = ? OR name = ?", envReq.ID, envReq.Name)
|
||||
} else {
|
||||
query = query.Where("name = ?", envReq.Name)
|
||||
}
|
||||
if err := query.First(&env).Error; err == nil {
|
||||
if env.Type == "secret" {
|
||||
continue // 坚决阻断下发机密数据
|
||||
}
|
||||
}
|
||||
if envReq.Type == "secret" {
|
||||
continue // 坚决阻断下发机密数据
|
||||
}
|
||||
safeEnvs = append(safeEnvs, envReq)
|
||||
var envIDs []string
|
||||
for _, e := range req.Envs {
|
||||
envIDs = append(envIDs, e.ID)
|
||||
}
|
||||
|
||||
dataService := services.NewDataService()
|
||||
exportData := dataService.ExportBusinessData(nil, envIDs)
|
||||
|
||||
results := make([]map[string]interface{}, 0)
|
||||
|
||||
for _, nodeID := range req.NodeIDs {
|
||||
@@ -317,13 +294,13 @@ func (ic *InterconnectController) SyncEnv(c *gin.Context) {
|
||||
continue
|
||||
}
|
||||
|
||||
client, apiURL, err := ic.getClientAndURL(node, "/api/v1/env/bulk_save")
|
||||
client, apiURL, err := ic.getClientAndURL(node, "/api/v1/system/import")
|
||||
if err != nil {
|
||||
results = append(results, map[string]interface{}{"node_id": nodeID, "success": false, "msg": "反向隧道未连接"})
|
||||
continue
|
||||
}
|
||||
|
||||
payloadBytes, _ := json.Marshal(safeEnvs)
|
||||
|
||||
payloadBytes, _ := json.Marshal(exportData)
|
||||
|
||||
httpReq, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(payloadBytes))
|
||||
if err != nil {
|
||||
@@ -335,7 +312,11 @@ func (ic *InterconnectController) SyncEnv(c *gin.Context) {
|
||||
|
||||
resp, err := client.Do(httpReq)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
results = append(results, map[string]interface{}{"node_id": nodeID, "success": false, "msg": "同步请求失败或超时"})
|
||||
msg := "同步失败"
|
||||
if err != nil {
|
||||
msg = err.Error()
|
||||
}
|
||||
results = append(results, map[string]interface{}{"node_id": nodeID, "success": false, "msg": msg})
|
||||
} else {
|
||||
results = append(results, map[string]interface{}{"node_id": nodeID, "success": true, "msg": "同步成功"})
|
||||
}
|
||||
@@ -350,8 +331,8 @@ func (ic *InterconnectController) SyncEnv(c *gin.Context) {
|
||||
// SyncTask 将任务同步到指定的节点列表
|
||||
func (ic *InterconnectController) SyncTask(c *gin.Context) {
|
||||
var req struct {
|
||||
NodeIDs []string `json:"node_ids" binding:"required"`
|
||||
Tasks []vo.TaskVO `json:"tasks" binding:"required"`
|
||||
NodeIDs []string `json:"node_ids" binding:"required"`
|
||||
Tasks []struct{ ID string `json:"id"` } `json:"tasks" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -359,6 +340,14 @@ func (ic *InterconnectController) SyncTask(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var taskIDs []string
|
||||
for _, t := range req.Tasks {
|
||||
taskIDs = append(taskIDs, t.ID)
|
||||
}
|
||||
|
||||
dataService := services.NewDataService()
|
||||
exportData := dataService.ExportBusinessData(taskIDs, nil)
|
||||
|
||||
results := make([]map[string]interface{}, 0)
|
||||
|
||||
for _, nodeID := range req.NodeIDs {
|
||||
@@ -368,13 +357,13 @@ func (ic *InterconnectController) SyncTask(c *gin.Context) {
|
||||
continue
|
||||
}
|
||||
|
||||
client, apiURL, err := ic.getClientAndURL(node, "/api/v1/tasks/bulk_save")
|
||||
client, apiURL, err := ic.getClientAndURL(node, "/api/v1/system/import")
|
||||
if err != nil {
|
||||
results = append(results, map[string]interface{}{"node_id": nodeID, "success": false, "msg": "反向隧道未连接"})
|
||||
continue
|
||||
}
|
||||
|
||||
payloadBytes, _ := json.Marshal(req.Tasks)
|
||||
|
||||
payloadBytes, _ := json.Marshal(exportData)
|
||||
|
||||
httpReq, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(payloadBytes))
|
||||
if err != nil {
|
||||
@@ -386,7 +375,11 @@ func (ic *InterconnectController) SyncTask(c *gin.Context) {
|
||||
|
||||
resp, err := client.Do(httpReq)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
results = append(results, map[string]interface{}{"node_id": nodeID, "success": false, "msg": "同步请求失败或超时"})
|
||||
msg := "同步失败"
|
||||
if err != nil {
|
||||
msg = err.Error()
|
||||
}
|
||||
results = append(results, map[string]interface{}{"node_id": nodeID, "success": false, "msg": msg})
|
||||
} else {
|
||||
results = append(results, map[string]interface{}{"node_id": nodeID, "success": true, "msg": "同步成功"})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// ExportData 全量或部分业务数据的导出/导入结构
|
||||
type ExportData struct {
|
||||
Version string `json:"version"`
|
||||
ExportAt LocalTime `json:"export_at"`
|
||||
Tasks []Task `json:"tasks"`
|
||||
Envs []EnvironmentVariable `json:"envs"`
|
||||
Tags []DataStorage `json:"tags"`
|
||||
Bindings []NotifyBinding `json:"bindings"`
|
||||
}
|
||||
|
||||
// NewExportData 创建一个导出数据对象
|
||||
func NewExportData() *ExportData {
|
||||
return &ExportData{
|
||||
Version: "1.0",
|
||||
ExportAt: LocalTime(time.Now()),
|
||||
Tasks: make([]Task, 0),
|
||||
Envs: make([]EnvironmentVariable, 0),
|
||||
Tags: make([]DataStorage, 0),
|
||||
Bindings: make([]NotifyBinding, 0),
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,7 @@ func initAuthorizedAPIRoutes(api *gin.RouterGroup, c *Controllers) {
|
||||
registerWebUIRoutes(adminOnly, c)
|
||||
registerMonitorRoutes(adminOnly, c)
|
||||
registerInterconnectRoutes(adminOnly, c)
|
||||
registerSystemRoutes(adminOnly, c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,3 +330,11 @@ func registerInterconnectRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||
interconnect.Any("/proxy/:node_id/*path", c.Interconnect.ProxyRequest)
|
||||
}
|
||||
}
|
||||
|
||||
func registerSystemRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||
systemAPI := g.Group("/system")
|
||||
{
|
||||
systemAPI.POST("/export", c.Data.ExportBusinessData)
|
||||
systemAPI.POST("/import", c.Data.ImportBusinessData)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,11 +45,14 @@ func RegisterControllers() *Controllers {
|
||||
setupEventHandlers(appLogService, notifyService, loginLogService, systemWSManager)
|
||||
startAppLogCleanup(appLogService)
|
||||
|
||||
taskController := controllers.NewTaskController(taskService, executorService)
|
||||
envController := controllers.NewEnvController(envService)
|
||||
|
||||
// 初始化并返回控制器
|
||||
return &Controllers{
|
||||
Task: controllers.NewTaskController(taskService, executorService),
|
||||
Task: taskController,
|
||||
Auth: controllers.NewAuthController(userService, settingsService, loginLogService),
|
||||
Env: controllers.NewEnvController(envService),
|
||||
Env: envController,
|
||||
Script: controllers.NewScriptController(scriptService),
|
||||
Executor: controllers.NewExecutorController(executorService),
|
||||
File: controllers.NewFileController(constant.ScriptsWorkDir),
|
||||
@@ -67,6 +70,7 @@ func RegisterControllers() *Controllers {
|
||||
WebUI: controllers.NewWebUIController(services.NewWebUIService(settingsService)),
|
||||
Monitor: controllers.NewMonitorController(executorService),
|
||||
Interconnect: controllers.NewInterconnectController(interconnectService),
|
||||
Data: controllers.NewDataController(taskController, envController),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ type Controllers struct {
|
||||
WebUI *controllers.WebUIController
|
||||
Monitor *controllers.MonitorController
|
||||
Interconnect *controllers.InterconnectController
|
||||
Data *controllers.DataController
|
||||
}
|
||||
|
||||
func Setup(c *Controllers) *gin.Engine {
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/engigu/baihu-panel/internal/constant"
|
||||
"github.com/engigu/baihu-panel/internal/database"
|
||||
"github.com/engigu/baihu-panel/internal/models"
|
||||
"github.com/engigu/baihu-panel/internal/services/relation"
|
||||
"github.com/rs/xid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DataService struct{}
|
||||
|
||||
func NewDataService() *DataService {
|
||||
return &DataService{}
|
||||
}
|
||||
|
||||
// ExportBusinessData 智能解析依赖并导出业务数据
|
||||
func (s *DataService) ExportBusinessData(taskIDs []string, envIDs []string) *models.ExportData {
|
||||
export := models.NewExportData()
|
||||
|
||||
export.Tasks = s.collectTasksAndRelations(taskIDs)
|
||||
export.Envs = s.collectEnvironmentVariables(export.Tasks, envIDs)
|
||||
export.Bindings = s.collectNotifyBindings(export.Tasks)
|
||||
export.Tags = s.collectTagStorages(export.Tasks)
|
||||
|
||||
return export
|
||||
}
|
||||
|
||||
// collectTasksAndRelations 收集任务及其子任务,并加载关联关系 (Envs, Tags)
|
||||
func (s *DataService) collectTasksAndRelations(taskIDs []string) []models.Task {
|
||||
if len(taskIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var tasks []models.Task
|
||||
targetTaskIDs := make(map[string]bool)
|
||||
for _, id := range taskIDs {
|
||||
targetTaskIDs[id] = true
|
||||
}
|
||||
|
||||
var initialTasks []models.Task
|
||||
database.DB.Where("id IN ?", taskIDs).Find(&initialTasks)
|
||||
tasks = append(tasks, initialTasks...)
|
||||
|
||||
// 检查哪些是仓库任务,并递归查询其子任务
|
||||
var parentIDs []string
|
||||
for _, t := range initialTasks {
|
||||
if t.Type == "repo" {
|
||||
parentIDs = append(parentIDs, t.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(parentIDs) > 0 {
|
||||
var childTasks []models.Task
|
||||
database.DB.Where("repo_task_id IN ?", parentIDs).Find(&childTasks)
|
||||
for _, ct := range childTasks {
|
||||
if !targetTaskIDs[ct.ID] {
|
||||
tasks = append(tasks, ct)
|
||||
targetTaskIDs[ct.ID] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 填充任务的 Envs 与 Tags 关系数据,以保证依赖解析和后续导入成功
|
||||
if len(tasks) > 0 {
|
||||
var exportTaskIDs []string
|
||||
for _, t := range tasks {
|
||||
exportTaskIDs = append(exportTaskIDs, t.ID)
|
||||
}
|
||||
|
||||
envsMap := relation.DataRelation.LoadRelations(exportTaskIDs, constant.RelationTypeTaskEnv)
|
||||
tagsMap := relation.DataRelation.LoadTags(exportTaskIDs, constant.RelationTypeTaskTag)
|
||||
|
||||
for i, t := range tasks {
|
||||
if envs, ok := envsMap[t.ID]; ok {
|
||||
tasks[i].Envs = models.BigText(strings.Join(envs, ","))
|
||||
}
|
||||
if tags, ok := tagsMap[t.ID]; ok {
|
||||
tasks[i].Tags = strings.Join(tags, ",")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tasks
|
||||
}
|
||||
|
||||
// collectEnvironmentVariables 收集所需和任务所依赖的环境变量
|
||||
func (s *DataService) collectEnvironmentVariables(tasks []models.Task, envIDs []string) []models.EnvironmentVariable {
|
||||
targetEnvIDs := make(map[string]bool)
|
||||
for _, id := range envIDs {
|
||||
targetEnvIDs[id] = true
|
||||
}
|
||||
|
||||
// 从任务中解析依赖的环境变量
|
||||
for _, t := range tasks {
|
||||
if t.Envs != "" {
|
||||
envArray := strings.Split(string(t.Envs), ",")
|
||||
for _, eID := range envArray {
|
||||
eID = strings.TrimSpace(eID)
|
||||
if eID != "" {
|
||||
targetEnvIDs[eID] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(targetEnvIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var finalEnvIDs []string
|
||||
for id := range targetEnvIDs {
|
||||
finalEnvIDs = append(finalEnvIDs, id)
|
||||
}
|
||||
|
||||
var envs []models.EnvironmentVariable
|
||||
database.DB.Where("id IN ?", finalEnvIDs).Find(&envs)
|
||||
return envs
|
||||
}
|
||||
|
||||
// collectNotifyBindings 收集相关的通知规则 (NotifyBindings)
|
||||
func (s *DataService) collectNotifyBindings(tasks []models.Task) []models.NotifyBinding {
|
||||
if len(tasks) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var taskIDList []string
|
||||
for _, t := range tasks {
|
||||
taskIDList = append(taskIDList, t.ID)
|
||||
}
|
||||
|
||||
var bindings []models.NotifyBinding
|
||||
database.DB.Where("type = ? AND data_id IN ?", "task", taskIDList).Find(&bindings)
|
||||
return bindings
|
||||
}
|
||||
|
||||
// collectTagStorages 收集标签定义 (DataStorage)
|
||||
func (s *DataService) collectTagStorages(tasks []models.Task) []models.DataStorage {
|
||||
targetTagNames := make(map[string]bool)
|
||||
for _, t := range tasks {
|
||||
if t.Tags != "" {
|
||||
tagArray := strings.Split(t.Tags, ",")
|
||||
for _, tagName := range tagArray {
|
||||
tagName = strings.TrimSpace(tagName)
|
||||
if tagName != "" {
|
||||
targetTagNames[tagName] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(targetTagNames) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var finalTagNames []string
|
||||
for name := range targetTagNames {
|
||||
finalTagNames = append(finalTagNames, name)
|
||||
}
|
||||
|
||||
var tagStorages []models.DataStorage
|
||||
database.DB.Where("type = ? AND name IN ?", constant.RelationTypeTaskTag, finalTagNames).Find(&tagStorages)
|
||||
return tagStorages
|
||||
}
|
||||
|
||||
// ImportBusinessData 导入业务数据
|
||||
func (s *DataService) ImportBusinessData(data *models.ExportData) error {
|
||||
tx := database.DB.Begin()
|
||||
if tx.Error != nil {
|
||||
return tx.Error
|
||||
}
|
||||
|
||||
var adminUser models.User
|
||||
if err := tx.Where("role = ?", constant.AdminRole).First(&adminUser).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
importer := &businessImporter{
|
||||
tx: tx,
|
||||
adminID: adminUser.ID,
|
||||
}
|
||||
|
||||
// 1. 导入环境变量
|
||||
if err := importer.importEnvs(data.Envs); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 导入标签定义 (DataStorage)
|
||||
if err := importer.importTags(data.Tags); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 3. 导入任务及关联映射关系
|
||||
if err := importer.importTasks(data.Tasks); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 4. 导入通知规则
|
||||
if err := importer.importBindings(data.Bindings); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit().Error
|
||||
}
|
||||
|
||||
type businessImporter struct {
|
||||
tx *gorm.DB
|
||||
adminID string
|
||||
}
|
||||
|
||||
func (importer *businessImporter) importEnvs(envs []models.EnvironmentVariable) error {
|
||||
if len(envs) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, env := range envs {
|
||||
env.UserID = importer.adminID
|
||||
if err := importer.tx.Save(&env).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (importer *businessImporter) importTags(tags []models.DataStorage) error {
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, tagStorage := range tags {
|
||||
if err := importer.tx.Save(&tagStorage).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (importer *businessImporter) importTasks(tasks []models.Task) error {
|
||||
if len(tasks) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, task := range tasks {
|
||||
if err := importer.tx.Save(&task).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := importer.importTaskRelations(task); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (importer *businessImporter) importTaskRelations(task models.Task) error {
|
||||
if err := importer.importTaskTagRelations(task); err != nil {
|
||||
return err
|
||||
}
|
||||
return importer.importTaskEnvRelations(task)
|
||||
}
|
||||
|
||||
func (importer *businessImporter) importTaskTagRelations(task models.Task) error {
|
||||
if task.Tags == "" {
|
||||
return nil
|
||||
}
|
||||
if err := importer.tx.Where("data_id = ? AND type = ?", task.ID, constant.RelationTypeTaskTag).Delete(&models.DataRelation{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
tags := strings.Split(task.Tags, ",")
|
||||
for _, tag := range tags {
|
||||
tag = strings.TrimSpace(tag)
|
||||
if tag == "" {
|
||||
continue
|
||||
}
|
||||
var storage models.DataStorage
|
||||
res := importer.tx.Where("type = ? AND name = ?", constant.RelationTypeTaskTag, tag).Limit(1).Find(&storage)
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
storage = models.DataStorage{
|
||||
ID: xid.New().String(),
|
||||
Type: constant.RelationTypeTaskTag,
|
||||
Name: tag,
|
||||
CreatedAt: models.Now(),
|
||||
UpdatedAt: models.Now(),
|
||||
}
|
||||
if err := importer.tx.Create(&storage).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
rel := models.DataRelation{
|
||||
ID: xid.New().String(),
|
||||
DataID: task.ID,
|
||||
RelateID: storage.ID,
|
||||
Type: constant.RelationTypeTaskTag,
|
||||
CreatedAt: models.Now(),
|
||||
UpdatedAt: models.Now(),
|
||||
}
|
||||
if err := importer.tx.Create(&rel).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (importer *businessImporter) importTaskEnvRelations(task models.Task) error {
|
||||
if string(task.Envs) == "" {
|
||||
return nil
|
||||
}
|
||||
if err := importer.tx.Where("data_id = ? AND type = ?", task.ID, constant.RelationTypeTaskEnv).Delete(&models.DataRelation{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
ids := strings.Split(string(task.Envs), ",")
|
||||
for _, relateID := range ids {
|
||||
relateID = strings.TrimSpace(relateID)
|
||||
if relateID == "" {
|
||||
continue
|
||||
}
|
||||
rel := models.DataRelation{
|
||||
ID: xid.New().String(),
|
||||
DataID: task.ID,
|
||||
RelateID: relateID,
|
||||
Type: constant.RelationTypeTaskEnv,
|
||||
CreatedAt: models.Now(),
|
||||
UpdatedAt: models.Now(),
|
||||
}
|
||||
if err := importer.tx.Create(&rel).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (importer *businessImporter) importBindings(bindings []models.NotifyBinding) error {
|
||||
if len(bindings) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, binding := range bindings {
|
||||
if err := importer.tx.Save(&binding).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func ParsePagination(c *gin.Context) Pagination {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
if pageSize < 1 || pageSize > 10000 {
|
||||
pageSize = defaultPageSize
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user