| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 | package sitesimport (	"net/http"	"os"	"github.com/0xJacky/Nginx-UI/internal/cert"	"github.com/0xJacky/Nginx-UI/internal/nginx"	"github.com/0xJacky/Nginx-UI/internal/site"	"github.com/0xJacky/Nginx-UI/model"	"github.com/0xJacky/Nginx-UI/query"	"github.com/gin-gonic/gin"	"github.com/sashabaranov/go-openai"	"github.com/uozi-tech/cosy"	"github.com/uozi-tech/cosy/logger"	"gorm.io/gorm/clause")func GetSite(c *gin.Context) {	name := c.Param("name")	path := nginx.GetConfPath("sites-available", name)	file, err := os.Stat(path)	if os.IsNotExist(err) {		c.JSON(http.StatusNotFound, gin.H{			"message": "file not found",		})		return	}	g := query.ChatGPTLog	chatgpt, err := g.Where(g.Name.Eq(path)).FirstOrCreate()	if err != nil {		cosy.ErrHandler(c, err)		return	}	if chatgpt.Content == nil {		chatgpt.Content = make([]openai.ChatCompletionMessage, 0)	}	s := query.Site	siteModel, err := s.Where(s.Path.Eq(path)).FirstOrCreate()	if err != nil {		cosy.ErrHandler(c, err)		return	}	certModel, err := model.FirstCert(name)	if err != nil {		logger.Warn(err)	}	if siteModel.Advanced {		origContent, err := os.ReadFile(path)		if err != nil {			cosy.ErrHandler(c, err)			return		}		c.JSON(http.StatusOK, site.Site{			ModifiedAt:      file.ModTime(),			Site:            siteModel,			Name:            name,			Config:          string(origContent),			AutoCert:        certModel.AutoCert == model.AutoCertEnabled,			ChatGPTMessages: chatgpt.Content,			Filepath:        path,			Status:          site.GetSiteStatus(name),		})		return	}	nginxConfig, err := nginx.ParseNgxConfig(path)	if err != nil {		cosy.ErrHandler(c, err)		return	}	certInfoMap := make(map[int][]*cert.Info)	for serverIdx, server := range nginxConfig.Servers {		for _, directive := range server.Directives {			if directive.Directive == "ssl_certificate" {				pubKey, err := cert.GetCertInfo(directive.Params)				if err != nil {					logger.Error("Failed to get certificate information", err)					continue				}				certInfoMap[serverIdx] = append(certInfoMap[serverIdx], pubKey)			}		}	}	c.JSON(http.StatusOK, site.Site{		Site:            siteModel,		ModifiedAt:      file.ModTime(),		Name:            name,		Config:          nginxConfig.FmtCode(),		Tokenized:       nginxConfig,		AutoCert:        certModel.AutoCert == model.AutoCertEnabled,		CertInfo:        certInfoMap,		ChatGPTMessages: chatgpt.Content,		Filepath:        path,		Status:          site.GetSiteStatus(name),	})}func SaveSite(c *gin.Context) {	name := c.Param("name")	var json struct {		Content     string   `json:"content" binding:"required"`		EnvGroupID  uint64   `json:"env_group_id"`		SyncNodeIDs []uint64 `json:"sync_node_ids"`		Overwrite   bool     `json:"overwrite"`		PostAction  string   `json:"post_action"`	}	if !cosy.BindAndValid(c, &json) {		return	}	err := site.Save(name, json.Content, json.Overwrite, json.EnvGroupID, json.SyncNodeIDs, json.PostAction)	if err != nil {		cosy.ErrHandler(c, err)		return	}	GetSite(c)}func RenameSite(c *gin.Context) {	oldName := c.Param("name")	var json struct {		NewName string `json:"new_name"`	}	if !cosy.BindAndValid(c, &json) {		return	}	err := site.Rename(oldName, json.NewName)	if err != nil {		cosy.ErrHandler(c, err)		return	}	c.JSON(http.StatusOK, gin.H{		"message": "ok",	})}func EnableSite(c *gin.Context) {	name := c.Param("name")	// Check if the site is in maintenance mode, if yes, disable maintenance mode first	maintenanceConfigPath := nginx.GetConfPath("sites-enabled", name+site.MaintenanceSuffix)	if _, err := os.Stat(maintenanceConfigPath); err == nil {		// Site is in maintenance mode, disable it first		err := site.DisableMaintenance(name)		if err != nil {			cosy.ErrHandler(c, err)			return		}	}	// Then enable the site normally	err := site.Enable(name)	if err != nil {		cosy.ErrHandler(c, err)		return	}	c.JSON(http.StatusOK, gin.H{		"message": "ok",	})}func DisableSite(c *gin.Context) {	name := c.Param("name")	// Check if the site is in maintenance mode, if yes, disable maintenance mode first	maintenanceConfigPath := nginx.GetConfPath("sites-enabled", name+site.MaintenanceSuffix)	if _, err := os.Stat(maintenanceConfigPath); err == nil {		// Site is in maintenance mode, disable it first		err := site.DisableMaintenance(name)		if err != nil {			cosy.ErrHandler(c, err)			return		}	}	// Then disable the site normally	err := site.Disable(name)	if err != nil {		cosy.ErrHandler(c, err)		return	}	c.JSON(http.StatusOK, gin.H{		"message": "ok",	})}func DeleteSite(c *gin.Context) {	err := site.Delete(c.Param("name"))	if err != nil {		cosy.ErrHandler(c, err)		return	}	c.JSON(http.StatusOK, gin.H{		"message": "ok",	})}func BatchUpdateSites(c *gin.Context) {	cosy.Core[model.Site](c).SetValidRules(gin.H{		"env_group_id": "required",	}).SetItemKey("path").		BeforeExecuteHook(func(ctx *cosy.Ctx[model.Site]) {			effectedPath := make([]string, len(ctx.BatchEffectedIDs))			var sites []*model.Site			for i, name := range ctx.BatchEffectedIDs {				path := nginx.GetConfPath("sites-available", name)				effectedPath[i] = path				sites = append(sites, &model.Site{					Path: path,				})			}			s := query.Site			err := s.Clauses(clause.OnConflict{				DoNothing: true,			}).Create(sites...)			if err != nil {				ctx.AbortWithError(err)				return			}			ctx.BatchEffectedIDs = effectedPath		}).BatchModify()}func EnableMaintenanceSite(c *gin.Context) {	name := c.Param("name")	// If site is already enabled, disable the normal site first	enabledConfigPath := nginx.GetConfPath("sites-enabled", name)	if _, err := os.Stat(enabledConfigPath); err == nil {		// Site is already enabled, disable normal site first		err := site.Disable(name)		if err != nil {			cosy.ErrHandler(c, err)			return		}	}	// Then enable maintenance mode	err := site.EnableMaintenance(name)	if err != nil {		cosy.ErrHandler(c, err)		return	}	c.JSON(http.StatusOK, gin.H{		"message": "ok",	})}
 |