From 9be508c976e51edd11defd2fd2d463fc9289f4c3 Mon Sep 17 00:00:00 2001 From: 0xJacky Date: Wed, 7 Feb 2024 14:57:45 +0800 Subject: [PATCH] chore: update cosy --- .air.toml | 2 +- api/cosy/cosy.go | 136 +++++++++++++++--------------- api/cosy/create.go | 15 ++-- api/cosy/custom.go | 2 +- api/cosy/delete.go | 17 ++-- api/cosy/error.go | 2 +- api/cosy/filter.go | 2 +- api/cosy/list.go | 97 +++++++++++---------- api/cosy/map2struct/hook.go | 29 +++++++ api/cosy/map2struct/map2struct.go | 1 + 10 files changed, 170 insertions(+), 133 deletions(-) diff --git a/.air.toml b/.air.toml index 0759b9e4..f3056317 100644 --- a/.air.toml +++ b/.air.toml @@ -7,7 +7,7 @@ tmp_dir = "tmp" [build] # Just plain old shell command. You could use `make` as well. -cmd = "CGO_ENABLED=1 go build -tags=jsoniter -ldflags=\"-X 'github.com/0xJacky/Nginx-UI/server/settings.buildTime=$(date +%s)'\" -o ./tmp/main ." +cmd = "CGO_ENABLED=1 go build -tags=jsoniter -ldflags=\"-X 'github.com/0xJacky/Nginx-UI/server/settings.buildTime=$(date +%s)'\" -v -o ./tmp/main ." # Binary file yields from `cmd`. bin = "tmp/main" # Customize binary. diff --git a/api/cosy/cosy.go b/api/cosy/cosy.go index 282b6f59..4d81ce61 100644 --- a/api/cosy/cosy.go +++ b/api/cosy/cosy.go @@ -1,117 +1,117 @@ package cosy import ( - "github.com/0xJacky/Nginx-UI/internal/logger" - "github.com/gin-gonic/gin" - "github.com/go-playground/validator/v10" - "gorm.io/gorm" + "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/gin-gonic/gin" + "github.com/go-playground/validator/v10" + "gorm.io/gorm" ) var validate *validator.Validate func init() { - validate = validator.New() + validate = validator.New() } type Ctx[T any] struct { - ctx *gin.Context - rules gin.H - Payload map[string]interface{} - Model T - OriginModel T - table string - tableArgs []interface{} - abort bool - nextHandler *gin.HandlerFunc - skipAssociationsOnCreate bool - beforeDecodeHookFunc []func(ctx *Ctx[T]) - beforeExecuteHookFunc []func(ctx *Ctx[T]) - executedHookFunc []func(ctx *Ctx[T]) - gormScopes []func(tx *gorm.DB) *gorm.DB - preloads []string - scan func(tx *gorm.DB) any - transformer func(*T) any - permanentlyDelete bool - SelectedFields []string - itemKey string + ctx *gin.Context + rules gin.H + Payload map[string]interface{} + Model T + OriginModel T + table string + tableArgs []interface{} + abort bool + nextHandler *gin.HandlerFunc + skipAssociationsOnCreate bool + beforeDecodeHookFunc []func(ctx *Ctx[T]) + beforeExecuteHookFunc []func(ctx *Ctx[T]) + executedHookFunc []func(ctx *Ctx[T]) + gormScopes []func(tx *gorm.DB) *gorm.DB + preloads []string + scan func(tx *gorm.DB) any + transformer func(*T) any + permanentlyDelete bool + SelectedFields []string + itemKey string } func Core[T any](c *gin.Context) *Ctx[T] { - return &Ctx[T]{ - ctx: c, - 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`", - skipAssociationsOnCreate: true, - } + return &Ctx[T]{ + ctx: c, + 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`", + skipAssociationsOnCreate: true, + } } func (c *Ctx[T]) SetTable(table string, args ...interface{}) *Ctx[T] { - c.table = table - c.tableArgs = args - return c + c.table = table + c.tableArgs = args + return c } func (c *Ctx[T]) SetItemKey(key string) *Ctx[T] { - c.itemKey = key - return c + c.itemKey = key + return c } func (c *Ctx[T]) SetValidRules(rules gin.H) *Ctx[T] { - c.rules = rules + c.rules = rules - return c + return c } func (c *Ctx[T]) SetPreloads(args ...string) *Ctx[T] { - c.preloads = append(c.preloads, args...) - return c + c.preloads = append(c.preloads, args...) + return c } func (c *Ctx[T]) validate() (errs gin.H) { - c.Payload = make(gin.H) + c.Payload = make(gin.H) - _ = c.ctx.ShouldBindJSON(&c.Payload) + _ = c.ctx.ShouldBindJSON(&c.Payload) - errs = validate.ValidateMap(c.Payload, c.rules) + errs = validate.ValidateMap(c.Payload, c.rules) - if len(errs) > 0 { - logger.Debug(errs) - for k := range errs { - errs[k] = c.rules[k] - } - return - } - // Make sure that the key in c.Payload is also the key of rules - validated := make(map[string]interface{}) + if len(errs) > 0 { + logger.Debug(errs) + for k := range errs { + errs[k] = c.rules[k] + } + return + } + // Make sure that the key in c.Payload is also the key of rules + validated := make(map[string]interface{}) - for k, v := range c.Payload { - if _, ok := c.rules[k]; ok { - validated[k] = v - } - } + for k, v := range c.Payload { + if _, ok := c.rules[k]; ok { + validated[k] = v + } + } - c.Payload = validated + c.Payload = validated - return + return } func (c *Ctx[T]) SetScan(scan func(tx *gorm.DB) any) *Ctx[T] { - c.scan = scan - return c + c.scan = scan + return c } func (c *Ctx[T]) SetTransformer(t func(m *T) any) *Ctx[T] { - c.transformer = t - return c + c.transformer = t + return c } func (c *Ctx[T]) AbortWithError(err error) { - c.abort = true - errHandler(c.ctx, err) + c.abort = true + errHandler(c.ctx, err) } func (c *Ctx[T]) Abort() { - c.abort = true + c.abort = true } diff --git a/api/cosy/create.go b/api/cosy/create.go index 1369795d..3dfcc91b 100644 --- a/api/cosy/create.go +++ b/api/cosy/create.go @@ -1,9 +1,9 @@ package cosy import ( - "github.com/gin-gonic/gin" "github.com/0xJacky/Nginx-UI/api/cosy/map2struct" "github.com/0xJacky/Nginx-UI/model" + "github.com/gin-gonic/gin" "gorm.io/gorm/clause" "net/http" ) @@ -52,12 +52,6 @@ func (c *Ctx[T]) Create() { return } - tx := db.Preload(clause.Associations) - for _, v := range c.preloads { - tx = tx.Preload(v) - } - tx.Table(c.table, c.tableArgs...).First(&c.Model) - if len(c.executedHookFunc) > 0 { for _, v := range c.executedHookFunc { v(c) @@ -67,6 +61,13 @@ func (c *Ctx[T]) Create() { } } } + + tx := db.Preload(clause.Associations) + for _, v := range c.preloads { + tx = tx.Preload(v) + } + tx.Table(c.table, c.tableArgs...).First(&c.Model) + if c.nextHandler != nil { (*c.nextHandler)(c.ctx) } else { diff --git a/api/cosy/custom.go b/api/cosy/custom.go index af749117..66ce714e 100644 --- a/api/cosy/custom.go +++ b/api/cosy/custom.go @@ -1,8 +1,8 @@ package cosy import ( - "github.com/gin-gonic/gin" "github.com/0xJacky/Nginx-UI/api/cosy/map2struct" + "github.com/gin-gonic/gin" "net/http" ) diff --git a/api/cosy/delete.go b/api/cosy/delete.go index 3890a78d..82b0e7c6 100644 --- a/api/cosy/delete.go +++ b/api/cosy/delete.go @@ -2,6 +2,7 @@ package cosy import ( "github.com/0xJacky/Nginx-UI/model" + "github.com/spf13/cast" "gorm.io/gorm" "net/http" ) @@ -20,9 +21,13 @@ func (c *Ctx[T]) Destroy() { c.beforeExecuteHook() db := model.UseDB() - var dbModel T result := db + + if cast.ToBool(c.ctx.Query("permanent")) || c.permanentlyDelete { + result = result.Unscoped() + } + if len(c.gormScopes) > 0 { result = result.Scopes(c.gormScopes...) } @@ -30,9 +35,9 @@ func (c *Ctx[T]) Destroy() { var err error session := result.Session(&gorm.Session{}) if c.table != "" { - err = session.Table(c.table, c.tableArgs...).Take(&dbModel, id).Error + err = session.Table(c.table, c.tableArgs...).Take(c.OriginModel, id).Error } else { - err = session.First(&dbModel, id).Error + err = session.First(&c.OriginModel, id).Error } if err != nil { @@ -40,11 +45,7 @@ func (c *Ctx[T]) Destroy() { return } - if c.permanentlyDelete { - result = result.Unscoped() - } - - err = result.Delete(&dbModel).Error + err = result.Delete(&c.OriginModel).Error if err != nil { errHandler(c.ctx, err) return diff --git a/api/cosy/error.go b/api/cosy/error.go index f3172c18..caa5a5ba 100644 --- a/api/cosy/error.go +++ b/api/cosy/error.go @@ -2,8 +2,8 @@ package cosy import ( "errors" - "github.com/gin-gonic/gin" "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/gin-gonic/gin" "go.uber.org/zap" "gorm.io/gorm" "net/http" diff --git a/api/cosy/filter.go b/api/cosy/filter.go index 686baf01..25bd36fc 100644 --- a/api/cosy/filter.go +++ b/api/cosy/filter.go @@ -2,8 +2,8 @@ package cosy import ( "fmt" - "github.com/gin-gonic/gin" "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/gin-gonic/gin" "gorm.io/gorm" "gorm.io/gorm/clause" "strings" diff --git a/api/cosy/list.go b/api/cosy/list.go index de6d0161..bbfd5143 100644 --- a/api/cosy/list.go +++ b/api/cosy/list.go @@ -49,13 +49,18 @@ func (c *Ctx[T]) result() (*gorm.DB, bool) { result := model.UseDB() if cast.ToBool(c.ctx.Query("trash")) { - stmt := &gorm.Statement{DB: model.UseDB()} - err := stmt.Parse(&dbModel) - if err != nil { - logger.Error(err) - return nil, false + tableName := c.table + if c.table == "" { + stmt := &gorm.Statement{DB: model.UseDB()} + err := stmt.Parse(&dbModel) + if err != nil { + logger.Error(err) + return nil, false + } + tableName = stmt.Schema.Table } - result = result.Unscoped().Where(stmt.Schema.Table + ".deleted_at IS NOT NULL") + + result = result.Unscoped().Where(tableName + ".deleted_at IS NOT NULL") } result = result.Model(&dbModel) @@ -99,52 +104,52 @@ func (c *Ctx[T]) ListAllData() (data any, ok bool) { } func (c *Ctx[T]) PagingListData() (*model.DataList, bool) { - result, ok := c.result() - if !ok { - return nil, false - } + result, ok := c.result() + if !ok { + return nil, false + } - scopesResult := result.Scopes(c.OrderAndPaginate()) - data := &model.DataList{} - if c.scan == nil { - models := make([]*T, 0) - scopesResult.Find(&models) + scopesResult := result.Scopes(c.OrderAndPaginate()) + data := &model.DataList{} + if c.scan == nil { + models := make([]*T, 0) + scopesResult.Find(&models) - if c.transformer != nil { - transformed := make([]any, 0) - for k := range models { - transformed = append(transformed, c.transformer(models[k])) - } - data.Data = transformed - } else { - data.Data = models - } - } else { - data.Data = c.scan(scopesResult) - } + if c.transformer != nil { + transformed := make([]any, 0) + for k := range models { + transformed = append(transformed, c.transformer(models[k])) + } + data.Data = transformed + } else { + data.Data = models + } + } else { + data.Data = c.scan(scopesResult) + } - var totalRecords int64 - delete(result.Statement.Clauses, "ORDER BY") - delete(result.Statement.Clauses, "LIMIT") - result.Count(&totalRecords) + var totalRecords int64 + delete(result.Statement.Clauses, "ORDER BY") + delete(result.Statement.Clauses, "LIMIT") + result.Count(&totalRecords) - page := cast.ToInt(c.ctx.Query("page")) - if page == 0 { - page = 1 - } + page := cast.ToInt(c.ctx.Query("page")) + if page == 0 { + page = 1 + } - pageSize := settings.ServerSettings.PageSize - if reqPageSize := c.ctx.Query("page_size"); reqPageSize != "" { - pageSize = cast.ToInt(reqPageSize) - } + pageSize := settings.ServerSettings.PageSize + if reqPageSize := c.ctx.Query("page_size"); reqPageSize != "" { + pageSize = cast.ToInt(reqPageSize) + } - data.Pagination = model.Pagination{ - Total: totalRecords, - PerPage: pageSize, - CurrentPage: page, - TotalPages: model.TotalPage(totalRecords, pageSize), - } - return data, true + data.Pagination = model.Pagination{ + Total: totalRecords, + PerPage: pageSize, + CurrentPage: page, + TotalPages: model.TotalPage(totalRecords, pageSize), + } + return data, true } func (c *Ctx[T]) PagingList() { diff --git a/api/cosy/map2struct/hook.go b/api/cosy/map2struct/hook.go index af40e835..50161615 100644 --- a/api/cosy/map2struct/hook.go +++ b/api/cosy/map2struct/hook.go @@ -38,6 +38,35 @@ func ToTimeHookFunc() mapstructure.DecodeHookFunc { } } +func ToTimePtrHookFunc() mapstructure.DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if t != reflect.TypeOf(&time.Time{}) { + return data, nil + } + + switch f.Kind() { + case reflect.String: + if data == "" { + return nil, nil + } + v, err := cast.ToTimeInDefaultLocationE(data, timeLocation) + return &v, err + case reflect.Float64: + v := time.Unix(0, int64(data.(float64))*int64(time.Millisecond)) + return &v, nil + case reflect.Int64: + v := time.Unix(0, data.(int64)*int64(time.Millisecond)) + return &v, nil + default: + return data, nil + } + // Convert it by parsing + } +} + func ToDecimalHookFunc() mapstructure.DecodeHookFunc { return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { diff --git a/api/cosy/map2struct/map2struct.go b/api/cosy/map2struct/map2struct.go index 12e63411..49f4f4cd 100644 --- a/api/cosy/map2struct/map2struct.go +++ b/api/cosy/map2struct/map2struct.go @@ -11,6 +11,7 @@ func WeakDecode(input, output interface{}) error { WeaklyTypedInput: true, DecodeHook: mapstructure.ComposeDecodeHookFunc( ToDecimalHookFunc(), ToTimeHookFunc(), ToNullableStringHookFunc(), + ToTimePtrHookFunc(), ), TagName: "json", }