Browse Source

refactor(cosy): cosy directory structure

0xJacky 1 year ago
parent
commit
9d62b3ef03
10 changed files with 332 additions and 91 deletions
  1. 6 40
      api/cosy/cosy.go
  2. 5 0
      api/cosy/delete.go
  3. 207 0
      api/cosy/filter.go
  4. 39 0
      api/cosy/hook.go
  5. 28 45
      api/cosy/list.go
  6. 39 0
      api/cosy/sort.go
  7. 5 3
      api/cosy/update.go
  8. 1 1
      app/package.json
  9. 1 1
      app/pnpm-lock.yaml
  10. 1 1
      dev.Dockerfile

+ 6 - 40
api/cosy/cosy.go

@@ -29,6 +29,7 @@ type Ctx[T any] struct {
 	transformer           func(*T) any
 	permanentlyDelete     bool
 	SelectedFields        []string
+	itemKey               string
 }
 
 func Core[T any](c *gin.Context) *Ctx[T] {
@@ -37,27 +38,18 @@ func Core[T any](c *gin.Context) *Ctx[T] {
 		gormScopes:            make([]func(tx *gorm.DB) *gorm.DB, 0),
 		beforeExecuteHookFunc: make([]func(ctx *Ctx[T]), 0),
 		beforeDecodeHookFunc:  make([]func(ctx *Ctx[T]), 0),
+		itemKey:               "`id`",
 	}
 }
 
-func (c *Ctx[T]) SetValidRules(rules gin.H) *Ctx[T] {
-	c.rules = rules
-
-	return c
-}
-
-func (c *Ctx[T]) BeforeDecodeHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
-	c.beforeDecodeHookFunc = append(c.beforeDecodeHookFunc, hook...)
+func (c *Ctx[T]) SetItemKey(key string) *Ctx[T] {
+	c.itemKey = key
 	return c
 }
 
-func (c *Ctx[T]) BeforeExecuteHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
-	c.beforeExecuteHookFunc = append(c.beforeExecuteHookFunc, hook...)
-	return c
-}
+func (c *Ctx[T]) SetValidRules(rules gin.H) *Ctx[T] {
+	c.rules = rules
 
-func (c *Ctx[T]) ExecutedHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
-	c.executedHookFunc = append(c.executedHookFunc, hook...)
 	return c
 }
 
@@ -66,22 +58,6 @@ func (c *Ctx[T]) SetPreloads(args ...string) *Ctx[T] {
 	return c
 }
 
-func (c *Ctx[T]) beforeExecuteHook() {
-	if len(c.beforeExecuteHookFunc) > 0 {
-		for _, v := range c.beforeExecuteHookFunc {
-			v(c)
-		}
-	}
-}
-
-func (c *Ctx[T]) beforeDecodeHook() {
-	if len(c.beforeDecodeHookFunc) > 0 {
-		for _, v := range c.beforeDecodeHookFunc {
-			v(c)
-		}
-	}
-}
-
 func (c *Ctx[T]) validate() (errs gin.H) {
 	c.Payload = make(gin.H)
 
@@ -128,13 +104,3 @@ func (c *Ctx[T]) AbortWithError(err error) {
 func (c *Ctx[T]) Abort() {
 	c.abort = true
 }
-
-func (c *Ctx[T]) PermanentlyDelete() *Ctx[T] {
-	c.permanentlyDelete = true
-	return c
-}
-
-func (c *Ctx[T]) GormScope(hook func(tx *gorm.DB) *gorm.DB) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, hook)
-	return c
-}

+ 5 - 0
api/cosy/delete.go

@@ -6,6 +6,11 @@ import (
 	"net/http"
 )
 
+func (c *Ctx[T]) PermanentlyDelete() *Ctx[T] {
+	c.permanentlyDelete = true
+	return c
+}
+
 func (c *Ctx[T]) Destroy() {
 	if c.abort {
 		return

+ 207 - 0
api/cosy/filter.go

@@ -0,0 +1,207 @@
+package cosy
+
+import (
+	"fmt"
+	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/gin-gonic/gin"
+	"gorm.io/gorm"
+	"strings"
+)
+
+func (c *Ctx[T]) SetFussy(keys ...string) *Ctx[T] {
+	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
+		return QueryToFussySearch(c.ctx, tx, keys...)
+	})
+	return c
+}
+
+func (c *Ctx[T]) SetFussyKeys(value string, keys ...string) *Ctx[T] {
+	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
+		return QueryToFussyKeysSearch(c.ctx, tx, value, keys...)
+	})
+	return c
+}
+
+func (c *Ctx[T]) SetEqual(keys ...string) *Ctx[T] {
+	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
+		return QueryToEqualSearch(c.ctx, tx, keys...)
+	})
+	return c
+}
+
+func (c *Ctx[T]) SetIn(keys ...string) *Ctx[T] {
+	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
+		return QueryToInSearch(c.ctx, tx, keys...)
+	})
+	return c
+}
+
+func (c *Ctx[T]) SetOrFussy(keys ...string) *Ctx[T] {
+	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
+		return QueryToOrFussySearch(c.ctx, tx, keys...)
+	})
+	return c
+}
+
+func (c *Ctx[T]) SetOrEqual(keys ...string) *Ctx[T] {
+	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
+		return QueryToOrEqualSearch(c.ctx, tx, keys...)
+	})
+	return c
+}
+
+func (c *Ctx[T]) SetOrIn(keys ...string) *Ctx[T] {
+	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
+		return QueryToOrInSearch(c.ctx, tx, keys...)
+	})
+	return c
+}
+
+func QueryToInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
+	for _, v := range keys {
+		queryArray := c.QueryArray(v + "[]")
+		if len(queryArray) == 0 {
+			queryArray = c.QueryArray(v)
+		}
+		if len(queryArray) > 0 {
+			var sb strings.Builder
+
+			_, err := fmt.Fprintf(&sb, "`%s` IN ?", v)
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+
+			db = db.Where(sb.String(), queryArray)
+		}
+	}
+	return db
+}
+
+func QueryToEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
+	for _, v := range keys {
+		if c.Query(v) != "" {
+			var sb strings.Builder
+
+			_, err := fmt.Fprintf(&sb, "`%s` = ?", v)
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+
+			db = db.Where(sb.String(), c.Query(v))
+		}
+	}
+	return db
+}
+
+func QueryToFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
+	for _, v := range keys {
+		if c.Query(v) != "" {
+			var sb strings.Builder
+
+			_, err := fmt.Fprintf(&sb, "`%s` LIKE ?", v)
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+
+			var sbValue strings.Builder
+
+			_, err = fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v))
+
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+
+			db = db.Where(sb.String(), sbValue.String())
+		}
+	}
+	return db
+}
+
+func QueryToFussyKeysSearch(c *gin.Context, db *gorm.DB, value string, keys ...string) *gorm.DB {
+	if c.Query(value) == "" {
+		return db
+	}
+
+	var condition *gorm.DB
+	for i, v := range keys {
+		sb := v + " LIKE ?"
+		sv := "%" + c.Query(value) + "%"
+
+		switch i {
+		case 0:
+			condition = db.Where(db.Where(sb, sv))
+		default:
+			condition = condition.Or(sb, sv)
+		}
+	}
+
+	return db.Where(condition)
+}
+
+func QueryToOrInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
+	for _, v := range keys {
+		queryArray := c.QueryArray(v + "[]")
+		if len(queryArray) == 0 {
+			queryArray = c.QueryArray(v)
+		}
+		if len(queryArray) > 0 {
+			var sb strings.Builder
+
+			_, err := fmt.Fprintf(&sb, "`%s` IN ?", v)
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+
+			db = db.Or(sb.String(), queryArray)
+		}
+	}
+	return db
+}
+
+func QueryToOrEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
+	for _, v := range keys {
+		if c.Query(v) != "" {
+			var sb strings.Builder
+
+			_, err := fmt.Fprintf(&sb, "`%s` = ?", v)
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+
+			db = db.Or(sb.String(), c.Query(v))
+		}
+	}
+	return db
+}
+
+func QueryToOrFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
+	for _, v := range keys {
+		if c.Query(v) != "" {
+			var sb strings.Builder
+
+			_, err := fmt.Fprintf(&sb, "`%s` LIKE ?", v)
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+
+			var sbValue strings.Builder
+
+			_, err = fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v))
+
+			if err != nil {
+				logger.Error(err)
+				continue
+			}
+
+			db = db.Or(sb.String(), sbValue.String())
+		}
+	}
+	return db
+}

+ 39 - 0
api/cosy/hook.go

@@ -0,0 +1,39 @@
+package cosy
+
+import "gorm.io/gorm"
+
+func (c *Ctx[T]) GormScope(hook func(tx *gorm.DB) *gorm.DB) *Ctx[T] {
+	c.gormScopes = append(c.gormScopes, hook)
+	return c
+}
+
+func (c *Ctx[T]) beforeExecuteHook() {
+	if len(c.beforeExecuteHookFunc) > 0 {
+		for _, v := range c.beforeExecuteHookFunc {
+			v(c)
+		}
+	}
+}
+
+func (c *Ctx[T]) beforeDecodeHook() {
+	if len(c.beforeDecodeHookFunc) > 0 {
+		for _, v := range c.beforeDecodeHookFunc {
+			v(c)
+		}
+	}
+}
+
+func (c *Ctx[T]) BeforeDecodeHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
+	c.beforeDecodeHookFunc = append(c.beforeDecodeHookFunc, hook...)
+	return c
+}
+
+func (c *Ctx[T]) BeforeExecuteHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
+	c.beforeExecuteHookFunc = append(c.beforeExecuteHookFunc, hook...)
+	return c
+}
+
+func (c *Ctx[T]) ExecutedHook(hook ...func(ctx *Ctx[T])) *Ctx[T] {
+	c.executedHookFunc = append(c.executedHookFunc, hook...)
+	return c
+}

+ 28 - 45
api/cosy/list.go

@@ -4,58 +4,39 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/gin-gonic/gin"
 	"github.com/spf13/cast"
 	"gorm.io/gorm"
 	"net/http"
 )
 
-func (c *Ctx[T]) SetFussy(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return model.QueryToFussySearch(c.ctx, tx, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetFussyKeys(value string, keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return model.QueryToFussyKeysSearch(c.ctx, tx, value, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetEqual(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return model.QueryToEqualSearch(c.ctx, tx, keys...)
-	})
-	return c
-}
-
-func (c *Ctx[T]) SetIn(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return model.QueryToInSearch(c.ctx, tx, keys...)
-	})
-	return c
+func GetPagingParams(c *gin.Context) (page, offset, pageSize int) {
+	page = cast.ToInt(c.Query("page"))
+	if page == 0 {
+		page = 1
+	}
+	pageSize = settings.ServerSettings.PageSize
+	reqPageSize := c.Query("page_size")
+	if reqPageSize != "" {
+		pageSize = cast.ToInt(reqPageSize)
+	}
+	offset = (page - 1) * pageSize
+	return
 }
 
-func (c *Ctx[T]) SetOrFussy(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return model.QueryToOrFussySearch(c.ctx, tx, keys...)
-	})
-	return c
-}
+func (c *Ctx[T]) combineStdSelectorRequest() {
+	var StdSelectorInitParams struct {
+		ID []int `json:"id"`
+	}
 
-func (c *Ctx[T]) SetOrEqual(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return model.QueryToOrEqualSearch(c.ctx, tx, keys...)
-	})
-	return c
-}
+	if err := c.ctx.ShouldBindJSON(&StdSelectorInitParams); err != nil {
+		logger.Error(err)
+		return
+	}
 
-func (c *Ctx[T]) SetOrIn(keys ...string) *Ctx[T] {
-	c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
-		return model.QueryToOrInSearch(c.ctx, tx, keys...)
+	c.GormScope(func(tx *gorm.DB) *gorm.DB {
+		return tx.Where(c.itemKey+" IN ?", StdSelectorInitParams.ID)
 	})
-	return c
 }
 
 func (c *Ctx[T]) result() (*gorm.DB, bool) {
@@ -72,7 +53,7 @@ func (c *Ctx[T]) result() (*gorm.DB, bool) {
 	var dbModel T
 	result := model.UseDB()
 
-	if c.ctx.Query("trash") == "true" {
+	if cast.ToBool(c.ctx.Query("trash")) {
 		stmt := &gorm.Statement{DB: model.UseDB()}
 		err := stmt.Parse(&dbModel)
 		if err != nil {
@@ -84,6 +65,8 @@ func (c *Ctx[T]) result() (*gorm.DB, bool) {
 
 	result = result.Model(&dbModel)
 
+	c.combineStdSelectorRequest()
+
 	if len(c.gormScopes) > 0 {
 		result = result.Scopes(c.gormScopes...)
 	}
@@ -97,7 +80,7 @@ func (c *Ctx[T]) ListAllData() ([]*T, bool) {
 		return nil, false
 	}
 
-	result = result.Scopes(model.SortOrder(c.ctx))
+	result = result.Scopes(c.SortOrder())
 	models := make([]*T, 0)
 	result.Find(&models)
 	return models, true
@@ -109,7 +92,7 @@ func (c *Ctx[T]) PagingListData() (*model.DataList, bool) {
 		return nil, false
 	}
 
-	result = result.Scopes(model.OrderAndPaginate(c.ctx))
+	result = result.Scopes(c.OrderAndPaginate())
 	data := &model.DataList{}
 	if c.scan == nil {
 		models := make([]*T, 0)

+ 39 - 0
api/cosy/sort.go

@@ -0,0 +1,39 @@
+package cosy
+
+import (
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"gorm.io/gorm"
+)
+
+func (c *Ctx[T]) SortOrder() func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		sort := c.ctx.DefaultQuery("order", "desc")
+		order := fmt.Sprintf("%s %s", DefaultQuery(c.ctx, "sort_by", c.itemKey), sort)
+		return db.Order(order)
+	}
+}
+
+func (c *Ctx[T]) OrderAndPaginate() func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		sort := c.ctx.DefaultQuery("order", "desc")
+
+		order := fmt.Sprintf("%s %s", DefaultQuery(c.ctx, "sort_by", c.itemKey), sort)
+		db = db.Order(order)
+
+		_, offset, pageSize := GetPagingParams(c.ctx)
+
+		return db.Offset(offset).Limit(pageSize)
+	}
+}
+
+func DefaultValue(c *gin.Context, key string, defaultValue any) any {
+	if value, ok := c.Get(key); ok {
+		return value
+	}
+	return defaultValue
+}
+
+func DefaultQuery(c *gin.Context, key string, defaultValue any) string {
+	return c.DefaultQuery(key, DefaultValue(c, key, defaultValue).(string))
+}

+ 5 - 3
api/cosy/update.go

@@ -28,6 +28,8 @@ func (c *Ctx[T]) Modify() {
 		return
 	}
 
+	var dbModel T
+
 	db := model.UseDB()
 
 	result := db
@@ -35,7 +37,7 @@ func (c *Ctx[T]) Modify() {
 		result = result.Scopes(c.gormScopes...)
 	}
 
-	err := result.Session(&gorm.Session{}).First(&c.Model, id).Error
+	err := result.Session(&gorm.Session{}).First(&dbModel, id).Error
 
 	if err != nil {
 		c.AbortWithError(err)
@@ -65,7 +67,7 @@ func (c *Ctx[T]) Modify() {
 		return
 	}
 
-	err = db.Model(&c.Model).Select(selectedFields).Updates(&c.Model).Error
+	err = db.Model(&dbModel).Select(selectedFields).Updates(&c.Model).Error
 
 	if err != nil {
 		c.AbortWithError(err)
@@ -85,6 +87,6 @@ func (c *Ctx[T]) Modify() {
 	if c.nextHandler != nil {
 		(*c.nextHandler)(c.ctx)
 	} else {
-		c.ctx.JSON(http.StatusOK, c.Model)
+		c.ctx.JSON(http.StatusOK, dbModel)
 	}
 }

+ 1 - 1
app/package.json

@@ -51,7 +51,7 @@
     "@vitejs/plugin-vue": "^4.5.0",
     "@vitejs/plugin-vue-jsx": "^3.1.0",
     "@vue/compiler-sfc": "^3.3.10",
-    "ace-builds": "^1.31.2",
+    "ace-builds": "^1.32.0",
     "autoprefixer": "^10.4.16",
     "eslint": "^8.54.0",
     "eslint-import-resolver-alias": "^1.1.2",

+ 1 - 1
app/pnpm-lock.yaml

@@ -122,7 +122,7 @@ devDependencies:
     specifier: ^0.4.0
     version: 0.4.0
   ace-builds:
-    specifier: ^1.31.2
+    specifier: ^1.32.0
     version: 1.32.0
   autoprefixer:
     specifier: ^10.4.16

+ 1 - 1
dev.Dockerfile

@@ -18,7 +18,7 @@ RUN set -x \
     && curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
            | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \
     && echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
-       http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
+       https://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
            | tee /etc/apt/sources.list.d/nginx.list
 
 RUN echo "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" | tee /etc/apt/preferences.d/99nginx \