|  | @@ -1,141 +1,141 @@
 | 
	
		
			
				|  |  |  package config
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import (
 | 
	
		
			
				|  |  | -	"github.com/0xJacky/Nginx-UI/api"
 | 
	
		
			
				|  |  | -	"github.com/0xJacky/Nginx-UI/internal/config"
 | 
	
		
			
				|  |  | -	"github.com/0xJacky/Nginx-UI/internal/helper"
 | 
	
		
			
				|  |  | -	"github.com/0xJacky/Nginx-UI/internal/nginx"
 | 
	
		
			
				|  |  | -	"github.com/0xJacky/Nginx-UI/model"
 | 
	
		
			
				|  |  | -	"github.com/0xJacky/Nginx-UI/query"
 | 
	
		
			
				|  |  | -	"github.com/gin-gonic/gin"
 | 
	
		
			
				|  |  | -	"github.com/sashabaranov/go-openai"
 | 
	
		
			
				|  |  | -	"net/http"
 | 
	
		
			
				|  |  | -	"os"
 | 
	
		
			
				|  |  | -	"time"
 | 
	
		
			
				|  |  | +    "github.com/0xJacky/Nginx-UI/api"
 | 
	
		
			
				|  |  | +    "github.com/0xJacky/Nginx-UI/internal/config"
 | 
	
		
			
				|  |  | +    "github.com/0xJacky/Nginx-UI/internal/helper"
 | 
	
		
			
				|  |  | +    "github.com/0xJacky/Nginx-UI/internal/nginx"
 | 
	
		
			
				|  |  | +    "github.com/0xJacky/Nginx-UI/model"
 | 
	
		
			
				|  |  | +    "github.com/0xJacky/Nginx-UI/query"
 | 
	
		
			
				|  |  | +    "github.com/gin-gonic/gin"
 | 
	
		
			
				|  |  | +    "github.com/sashabaranov/go-openai"
 | 
	
		
			
				|  |  | +    "net/http"
 | 
	
		
			
				|  |  | +    "os"
 | 
	
		
			
				|  |  | +    "time"
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  type EditConfigJson struct {
 | 
	
		
			
				|  |  | -	Content string `json:"content" binding:"required"`
 | 
	
		
			
				|  |  | +    Content string `json:"content" binding:"required"`
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func EditConfig(c *gin.Context) {
 | 
	
		
			
				|  |  | -	name := c.Param("name")
 | 
	
		
			
				|  |  | -	var json struct {
 | 
	
		
			
				|  |  | -		Name        string `json:"name" binding:"required"`
 | 
	
		
			
				|  |  | -		Filepath    string `json:"filepath" binding:"required"`
 | 
	
		
			
				|  |  | -		NewFilepath string `json:"new_filepath" binding:"required"`
 | 
	
		
			
				|  |  | -		Content     string `json:"content"`
 | 
	
		
			
				|  |  | -		Overwrite   bool   `json:"overwrite"`
 | 
	
		
			
				|  |  | -		SyncNodeIds []int  `json:"sync_node_ids"`
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	if !api.BindAndValid(c, &json) {
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	path := json.Filepath
 | 
	
		
			
				|  |  | -	if !helper.IsUnderDirectory(path, nginx.GetConfPath()) {
 | 
	
		
			
				|  |  | -		c.JSON(http.StatusForbidden, gin.H{
 | 
	
		
			
				|  |  | -			"message": "filepath is not under the nginx conf path",
 | 
	
		
			
				|  |  | -		})
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if !helper.IsUnderDirectory(json.NewFilepath, nginx.GetConfPath()) {
 | 
	
		
			
				|  |  | -		c.JSON(http.StatusForbidden, gin.H{
 | 
	
		
			
				|  |  | -			"message": "new filepath is not under the nginx conf path",
 | 
	
		
			
				|  |  | -		})
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if !helper.FileExists(path) {
 | 
	
		
			
				|  |  | -		c.JSON(http.StatusNotFound, gin.H{
 | 
	
		
			
				|  |  | -			"message": "file not found",
 | 
	
		
			
				|  |  | -		})
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	content := json.Content
 | 
	
		
			
				|  |  | -	origContent, err := os.ReadFile(path)
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if content != "" && content != string(origContent) {
 | 
	
		
			
				|  |  | -		err = os.WriteFile(path, []byte(content), 0644)
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | -			return
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	q := query.Config
 | 
	
		
			
				|  |  | -	cfg, err := q.Where(q.Filepath.Eq(json.Filepath)).FirstOrCreate()
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	_, err = q.Where(q.Filepath.Eq(json.Filepath)).Updates(&model.Config{
 | 
	
		
			
				|  |  | -		Name:          json.Name,
 | 
	
		
			
				|  |  | -		Filepath:      json.NewFilepath,
 | 
	
		
			
				|  |  | -		SyncNodeIds:   json.SyncNodeIds,
 | 
	
		
			
				|  |  | -		SyncOverwrite: json.Overwrite,
 | 
	
		
			
				|  |  | -	})
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	g := query.ChatGPTLog
 | 
	
		
			
				|  |  | -	// handle rename
 | 
	
		
			
				|  |  | -	if path != json.NewFilepath {
 | 
	
		
			
				|  |  | -		if helper.FileExists(json.NewFilepath) {
 | 
	
		
			
				|  |  | -			c.JSON(http.StatusNotAcceptable, gin.H{
 | 
	
		
			
				|  |  | -				"message": "File exists",
 | 
	
		
			
				|  |  | -			})
 | 
	
		
			
				|  |  | -			return
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		err := os.Rename(json.Filepath, json.NewFilepath)
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | -			return
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		// update ChatGPT record
 | 
	
		
			
				|  |  | -		_, _ = g.Where(g.Name.Eq(json.NewFilepath)).Delete()
 | 
	
		
			
				|  |  | -		_, _ = g.Where(g.Name.Eq(path)).Update(g.Name, json.NewFilepath)
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	err = config.SyncToRemoteServer(cfg, json.NewFilepath)
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	output := nginx.Reload()
 | 
	
		
			
				|  |  | -	if nginx.GetLogLevel(output) >= nginx.Warn {
 | 
	
		
			
				|  |  | -		c.JSON(http.StatusInternalServerError, gin.H{
 | 
	
		
			
				|  |  | -			"message": output,
 | 
	
		
			
				|  |  | -		})
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	chatgpt, err := g.Where(g.Name.Eq(json.NewFilepath)).FirstOrCreate()
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | -		return
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if chatgpt.Content == nil {
 | 
	
		
			
				|  |  | -		chatgpt.Content = make([]openai.ChatCompletionMessage, 0)
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	c.JSON(http.StatusOK, config.Config{
 | 
	
		
			
				|  |  | -		Name:            name,
 | 
	
		
			
				|  |  | -		Content:         content,
 | 
	
		
			
				|  |  | -		ChatGPTMessages: chatgpt.Content,
 | 
	
		
			
				|  |  | -		FilePath:        json.NewFilepath,
 | 
	
		
			
				|  |  | -		ModifiedAt:      time.Now(),
 | 
	
		
			
				|  |  | -	})
 | 
	
		
			
				|  |  | +    name := c.Param("name")
 | 
	
		
			
				|  |  | +    var json struct {
 | 
	
		
			
				|  |  | +        Name          string `json:"name" binding:"required"`
 | 
	
		
			
				|  |  | +        Filepath      string `json:"filepath" binding:"required"`
 | 
	
		
			
				|  |  | +        NewFilepath   string `json:"new_filepath" binding:"required"`
 | 
	
		
			
				|  |  | +        Content       string `json:"content"`
 | 
	
		
			
				|  |  | +        SyncOverwrite bool   `json:"sync_overwrite"`
 | 
	
		
			
				|  |  | +        SyncNodeIds   []int  `json:"sync_node_ids"`
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if !api.BindAndValid(c, &json) {
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    path := json.Filepath
 | 
	
		
			
				|  |  | +    if !helper.IsUnderDirectory(path, nginx.GetConfPath()) {
 | 
	
		
			
				|  |  | +        c.JSON(http.StatusForbidden, gin.H{
 | 
	
		
			
				|  |  | +            "message": "filepath is not under the nginx conf path",
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if !helper.IsUnderDirectory(json.NewFilepath, nginx.GetConfPath()) {
 | 
	
		
			
				|  |  | +        c.JSON(http.StatusForbidden, gin.H{
 | 
	
		
			
				|  |  | +            "message": "new filepath is not under the nginx conf path",
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if !helper.FileExists(path) {
 | 
	
		
			
				|  |  | +        c.JSON(http.StatusNotFound, gin.H{
 | 
	
		
			
				|  |  | +            "message": "file not found",
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    content := json.Content
 | 
	
		
			
				|  |  | +    origContent, err := os.ReadFile(path)
 | 
	
		
			
				|  |  | +    if err != nil {
 | 
	
		
			
				|  |  | +        api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if content != "" && content != string(origContent) {
 | 
	
		
			
				|  |  | +        err = os.WriteFile(path, []byte(content), 0644)
 | 
	
		
			
				|  |  | +        if err != nil {
 | 
	
		
			
				|  |  | +            api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | +            return
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    q := query.Config
 | 
	
		
			
				|  |  | +    cfg, err := q.Where(q.Filepath.Eq(json.Filepath)).FirstOrCreate()
 | 
	
		
			
				|  |  | +    if err != nil {
 | 
	
		
			
				|  |  | +        api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    _, err = q.Where(q.Filepath.Eq(json.Filepath)).Updates(&model.Config{
 | 
	
		
			
				|  |  | +        Name:          json.Name,
 | 
	
		
			
				|  |  | +        Filepath:      json.NewFilepath,
 | 
	
		
			
				|  |  | +        SyncNodeIds:   json.SyncNodeIds,
 | 
	
		
			
				|  |  | +        SyncOverwrite: json.SyncOverwrite,
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if err != nil {
 | 
	
		
			
				|  |  | +        api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    g := query.ChatGPTLog
 | 
	
		
			
				|  |  | +    // handle rename
 | 
	
		
			
				|  |  | +    if path != json.NewFilepath {
 | 
	
		
			
				|  |  | +        if helper.FileExists(json.NewFilepath) {
 | 
	
		
			
				|  |  | +            c.JSON(http.StatusNotAcceptable, gin.H{
 | 
	
		
			
				|  |  | +                "message": "File exists",
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +            return
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        err := os.Rename(json.Filepath, json.NewFilepath)
 | 
	
		
			
				|  |  | +        if err != nil {
 | 
	
		
			
				|  |  | +            api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | +            return
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // update ChatGPT record
 | 
	
		
			
				|  |  | +        _, _ = g.Where(g.Name.Eq(json.NewFilepath)).Delete()
 | 
	
		
			
				|  |  | +        _, _ = g.Where(g.Name.Eq(path)).Update(g.Name, json.NewFilepath)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    err = config.SyncToRemoteServer(cfg, json.NewFilepath)
 | 
	
		
			
				|  |  | +    if err != nil {
 | 
	
		
			
				|  |  | +        api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    output := nginx.Reload()
 | 
	
		
			
				|  |  | +    if nginx.GetLogLevel(output) >= nginx.Warn {
 | 
	
		
			
				|  |  | +        c.JSON(http.StatusInternalServerError, gin.H{
 | 
	
		
			
				|  |  | +            "message": output,
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    chatgpt, err := g.Where(g.Name.Eq(json.NewFilepath)).FirstOrCreate()
 | 
	
		
			
				|  |  | +    if err != nil {
 | 
	
		
			
				|  |  | +        api.ErrHandler(c, err)
 | 
	
		
			
				|  |  | +        return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if chatgpt.Content == nil {
 | 
	
		
			
				|  |  | +        chatgpt.Content = make([]openai.ChatCompletionMessage, 0)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    c.JSON(http.StatusOK, config.Config{
 | 
	
		
			
				|  |  | +        Name:            name,
 | 
	
		
			
				|  |  | +        Content:         content,
 | 
	
		
			
				|  |  | +        ChatGPTMessages: chatgpt.Content,
 | 
	
		
			
				|  |  | +        FilePath:        json.NewFilepath,
 | 
	
		
			
				|  |  | +        ModifiedAt:      time.Now(),
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  |  }
 |