diff --git a/api/sites/duplicate.go b/api/sites/duplicate.go index 577a288b..20c580d7 100644 --- a/api/sites/duplicate.go +++ b/api/sites/duplicate.go @@ -2,15 +2,14 @@ package sites import ( "github.com/0xJacky/Nginx-UI/api" - "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/nginx" + "github.com/0xJacky/Nginx-UI/internal/site" "github.com/gin-gonic/gin" "net/http" ) func DuplicateSite(c *gin.Context) { // Source name - name := c.Param("name") + src := c.Param("name") // Destination name var json struct { @@ -21,24 +20,13 @@ func DuplicateSite(c *gin.Context) { return } - src := nginx.GetConfPath("sites-available", name) - dst := nginx.GetConfPath("sites-available", json.Name) - - if helper.FileExists(dst) { - c.JSON(http.StatusNotAcceptable, gin.H{ - "message": "File exists", - }) - return - } - - _, err := helper.CopyFile(src, dst) - + err := site.Duplicate(src, json.Name) if err != nil { api.ErrHandler(c, err) return } c.JSON(http.StatusOK, gin.H{ - "dst": dst, + "message": "ok", }) } diff --git a/api/sites/router.go b/api/sites/router.go index 093ca51a..95af9680 100644 --- a/api/sites/router.go +++ b/api/sites/router.go @@ -3,17 +3,25 @@ package sites import "github.com/gin-gonic/gin" func InitRouter(r *gin.RouterGroup) { - r.GET("domains", GetSiteList) - r.GET("domains/:name", GetSite) - r.POST("domains/:name", SaveSite) - r.PUT("domains", BatchUpdateSites) - r.POST("domains/:name/enable", EnableSite) - r.POST("domains/:name/disable", DisableSite) - r.POST("domains/:name/advance", DomainEditByAdvancedMode) - r.DELETE("domains/:name", DeleteSite) - r.POST("domains/:name/duplicate", DuplicateSite) + r.GET("sites", GetSiteList) + r.GET("sites/:name", GetSite) + r.PUT("sites", BatchUpdateSites) + r.POST("sites/:name/advance", DomainEditByAdvancedMode) r.POST("auto_cert/:name", AddDomainToAutoCert) r.DELETE("auto_cert/:name", RemoveDomainFromAutoCert) + + // rename site + r.POST("sites/:name/rename", RenameSite) + // enable site + r.POST("sites/:name/enable", EnableSite) + // disable site + r.POST("sites/:name/disable", DisableSite) + // save site + r.POST("sites/:name", SaveSite) + // delete site + r.DELETE("sites/:name", DeleteSite) + // duplicate site + r.POST("sites/:name/duplicate", DuplicateSite) } func InitCategoryRouter(r *gin.RouterGroup) { diff --git a/api/sites/site.go b/api/sites/site.go index 66d32e03..f0fe2599 100644 --- a/api/sites/site.go +++ b/api/sites/site.go @@ -3,8 +3,8 @@ package sites import ( "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/cert" - "github.com/0xJacky/Nginx-UI/internal/helper" "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" @@ -17,14 +17,8 @@ import ( ) func GetSite(c *gin.Context) { - rewriteName, ok := c.Get("rewriteConfigFileName") name := c.Param("name") - // for modify filename - if ok { - name = rewriteName.(string) - } - path := nginx.GetConfPath("sites-available", name) file, err := os.Stat(path) if os.IsNotExist(err) { @@ -51,7 +45,7 @@ func GetSite(c *gin.Context) { } s := query.Site - site, err := s.Where(s.Path.Eq(path)).FirstOrCreate() + siteModel, err := s.Where(s.Path.Eq(path)).FirstOrCreate() if err != nil { api.ErrHandler(c, err) return @@ -62,7 +56,7 @@ func GetSite(c *gin.Context) { logger.Warn(err) } - if site.Advanced { + if siteModel.Advanced { origContent, err := os.ReadFile(path) if err != nil { api.ErrHandler(c, err) @@ -71,7 +65,7 @@ func GetSite(c *gin.Context) { c.JSON(http.StatusOK, Site{ ModifiedAt: file.ModTime(), - Site: site, + Site: siteModel, Enabled: enabled, Name: name, Config: string(origContent), @@ -103,8 +97,8 @@ func GetSite(c *gin.Context) { } c.JSON(http.StatusOK, Site{ + Site: siteModel, ModifiedAt: file.ModTime(), - Site: site, Enabled: enabled, Name: name, Config: nginxConfig.FmtCode(), @@ -119,15 +113,7 @@ func GetSite(c *gin.Context) { func SaveSite(c *gin.Context) { name := c.Param("name") - if name == "" { - c.JSON(http.StatusNotAcceptable, gin.H{ - "message": "param name is empty", - }) - return - } - var json struct { - Name string `json:"name" binding:"required"` Content string `json:"content" binding:"required"` SiteCategoryID uint64 `json:"site_category_id"` SyncNodeIDs []uint64 `json:"sync_node_ids"` @@ -138,129 +124,39 @@ func SaveSite(c *gin.Context) { return } - path := nginx.GetConfPath("sites-available", name) - - if !json.Overwrite && helper.FileExists(path) { - c.JSON(http.StatusNotAcceptable, gin.H{ - "message": "File exists", - }) - return - } - - err := os.WriteFile(path, []byte(json.Content), 0644) + err := site.Save(name, json.Content, json.Overwrite, json.SiteCategoryID, json.SyncNodeIDs) if err != nil { api.ErrHandler(c, err) return } - enabledConfigFilePath := nginx.GetConfPath("sites-enabled", name) - s := query.Site - - _, err = s.Where(s.Path.Eq(path)). - Select(s.SiteCategoryID, s.SyncNodeIDs). - Updates(&model.Site{ - SiteCategoryID: json.SiteCategoryID, - SyncNodeIDs: json.SyncNodeIDs, - }) - if err != nil { - api.ErrHandler(c, err) - return - } - - // rename the config file if needed - if name != json.Name { - newPath := nginx.GetConfPath("sites-available", json.Name) - _, _ = s.Where(s.Path.Eq(path)).Update(s.Path, newPath) - - // check if dst file exists, do not rename - if helper.FileExists(newPath) { - c.JSON(http.StatusNotAcceptable, gin.H{ - "message": "File exists", - }) - return - } - // recreate a soft link - if helper.FileExists(enabledConfigFilePath) { - _ = os.Remove(enabledConfigFilePath) - enabledConfigFilePath = nginx.GetConfPath("sites-enabled", json.Name) - err = os.Symlink(newPath, enabledConfigFilePath) - - if err != nil { - api.ErrHandler(c, err) - return - } - } - - err = os.Rename(path, newPath) - if err != nil { - api.ErrHandler(c, err) - return - } - - name = json.Name - c.Set("rewriteConfigFileName", name) - } - - enabledConfigFilePath = nginx.GetConfPath("sites-enabled", name) - if helper.FileExists(enabledConfigFilePath) { - // Test nginx configuration - output := nginx.TestConf() - - if nginx.GetLogLevel(output) > nginx.Warn { - c.JSON(http.StatusInternalServerError, gin.H{ - "message": output, - }) - return - } - - output = nginx.Reload() - - if nginx.GetLogLevel(output) > nginx.Warn { - c.JSON(http.StatusInternalServerError, gin.H{ - "message": output, - }) - return - } - } GetSite(c) } -func EnableSite(c *gin.Context) { - configFilePath := nginx.GetConfPath("sites-available", c.Param("name")) - enabledConfigFilePath := nginx.GetConfPath("sites-enabled", c.Param("name")) - - _, err := os.Stat(configFilePath) +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 { api.ErrHandler(c, err) return } - if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) { - err = os.Symlink(configFilePath, enabledConfigFilePath) + c.JSON(http.StatusOK, gin.H{ + "message": "ok", + }) +} - if err != nil { - api.ErrHandler(c, err) - return - } - } - - // Test nginx config, if not pass, then disable the site. - output := nginx.TestConf() - if nginx.GetLogLevel(output) > nginx.Warn { - _ = os.Remove(enabledConfigFilePath) - c.JSON(http.StatusInternalServerError, gin.H{ - "message": output, - }) - return - } - - output = nginx.Reload() - - if nginx.GetLogLevel(output) > nginx.Warn { - c.JSON(http.StatusInternalServerError, gin.H{ - "message": output, - }) +func EnableSite(c *gin.Context) { + err := site.Enable(c.Param("name")) + if err != nil { + api.ErrHandler(c, err) return } @@ -270,71 +166,19 @@ func EnableSite(c *gin.Context) { } func DisableSite(c *gin.Context) { - enabledConfigFilePath := nginx.GetConfPath("sites-enabled", c.Param("name")) - _, err := os.Stat(enabledConfigFilePath) + err := site.Disable(c.Param("name")) if err != nil { api.ErrHandler(c, err) return } - err = os.Remove(enabledConfigFilePath) - if err != nil { - api.ErrHandler(c, err) - return - } - - // delete auto cert record - certModel := model.Cert{Filename: c.Param("name")} - err = certModel.Remove() - 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 - } - c.JSON(http.StatusOK, gin.H{ "message": "ok", }) } func DeleteSite(c *gin.Context) { - var err error - name := c.Param("name") - availablePath := nginx.GetConfPath("sites-available", name) - - s := query.Site - _, err = s.Where(s.Path.Eq(availablePath)).Unscoped().Delete(&model.Site{}) - if err != nil { - api.ErrHandler(c, err) - return - } - - enabledPath := nginx.GetConfPath("sites-enabled", name) - if _, err = os.Stat(availablePath); os.IsNotExist(err) { - c.JSON(http.StatusNotFound, gin.H{ - "message": "site not found", - }) - return - } - - if _, err = os.Stat(enabledPath); err == nil { - c.JSON(http.StatusNotAcceptable, gin.H{ - "message": "site is enabled", - }) - return - } - - certModel := model.Cert{Filename: name} - _ = certModel.Remove() - - err = os.Remove(availablePath) + err := site.Delete(c.Param("name")) if err != nil { api.ErrHandler(c, err) return diff --git a/app/src/api/domain.ts b/app/src/api/site.ts similarity index 87% rename from app/src/api/domain.ts rename to app/src/api/site.ts index de2027a5..c4ae6f8e 100644 --- a/app/src/api/domain.ts +++ b/app/src/api/site.ts @@ -29,7 +29,7 @@ export interface AutoCertRequest { key_type: PrivateKeyType } -class Domain extends Curd { +class SiteCurd extends Curd { // eslint-disable-next-line ts/no-explicit-any enable(name: string, config?: any) { return http.post(`${this.baseUrl}/${name}/enable`, undefined, config) @@ -39,6 +39,10 @@ class Domain extends Curd { return http.post(`${this.baseUrl}/${name}/disable`) } + rename(oldName: string, newName: string) { + return http.post(`${this.baseUrl}/${oldName}/rename`, { new_name: newName }) + } + get_template() { return http.get('template') } @@ -60,6 +64,6 @@ class Domain extends Curd { } } -const domain = new Domain('/domains') +const site = new SiteCurd('/sites') -export default domain +export default site diff --git a/app/src/components/StdDesign/StdDataEntry/StdDataEntry.vue b/app/src/components/StdDesign/StdDataEntry/StdDataEntry.vue index 6eca07cc..007c4d7e 100644 --- a/app/src/components/StdDesign/StdDataEntry/StdDataEntry.vue +++ b/app/src/components/StdDesign/StdDataEntry/StdDataEntry.vue @@ -1,5 +1,6 @@ diff --git a/app/src/components/StdDesign/StdDataEntry/StdFormItem.vue b/app/src/components/StdDesign/StdDataEntry/StdFormItem.vue index 88c66d80..5aa26e19 100644 --- a/app/src/components/StdDesign/StdDataEntry/StdFormItem.vue +++ b/app/src/components/StdDesign/StdDataEntry/StdFormItem.vue @@ -1,6 +1,7 @@