mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 18:35:51 +02:00
chore: update cosy
This commit is contained in:
parent
e12e83c90a
commit
9be508c976
10 changed files with 170 additions and 133 deletions
|
@ -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.
|
||||
|
|
136
api/cosy/cosy.go
136
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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ func WeakDecode(input, output interface{}) error {
|
|||
WeaklyTypedInput: true,
|
||||
DecodeHook: mapstructure.ComposeDecodeHookFunc(
|
||||
ToDecimalHookFunc(), ToTimeHookFunc(), ToNullableStringHookFunc(),
|
||||
ToTimePtrHookFunc(),
|
||||
),
|
||||
TagName: "json",
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue